Skip to content

Commit

Permalink
Merge tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/gfs2/linux-gfs2

Pull GFS2 updates from Bob Peterson:
 "Here is a list of patches we've accumulated for GFS2 for the current
  upstream merge window.

  Most of the patches fix GFS2 quotas, which were not properly enforced.
  There's another that adds me as a GFS2 co-maintainer, and a couple
  patches that fix a kernel panic doing splice_write on GFS2 as well as
  a few correctness patches"

* tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: fix quota refresh race in do_glock()
  gfs2: incorrect check for debugfs returns
  gfs2: allow fallocate to max out quotas/fs efficiently
  gfs2: allow quota_check and inplace_reserve to return available blocks
  gfs2: perform quota checks against allocation parameters
  GFS2: Move gfs2_file_splice_write outside of #ifdef
  GFS2: Allocate reservation during splice_write
  GFS2: gfs2_set_acl(): Cache "no acl" as well
  Add myself (Bob Peterson) as a maintainer of GFS2
  • Loading branch information
torvalds committed Apr 14, 2015
2 parents 78d5dcd + 3013317 commit 80dcc31
Show file tree
Hide file tree
Showing 13 changed files with 186 additions and 97 deletions.
4 changes: 2 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4337,10 +4337,10 @@ F: scripts/get_maintainer.pl

GFS2 FILE SYSTEM
M: Steven Whitehouse <[email protected]>
M: Bob Peterson <[email protected]>
L: [email protected]
W: http://sources.redhat.com/cluster/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
S: Supported
F: Documentation/filesystems/gfs2*.txt
F: fs/gfs2/
Expand Down
6 changes: 1 addition & 5 deletions fs/gfs2/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
if (error)
goto out;

if (acl)
set_cached_acl(inode, type, acl);
else
forget_cached_acl(inode, type);
set_cached_acl(inode, type, acl);
out:
kfree(data);
return error;
Expand Down
6 changes: 3 additions & 3 deletions fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -671,12 +671,12 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,

if (alloc_required) {
struct gfs2_alloc_parms ap = { .aflags = 0, };
error = gfs2_quota_lock_check(ip);
requested = data_blocks + ind_blocks;
ap.target = requested;
error = gfs2_quota_lock_check(ip, &ap);
if (error)
goto out_unlock;

requested = data_blocks + ind_blocks;
ap.target = requested;
error = gfs2_inplace_reserve(ip, &ap);
if (error)
goto out_qunlock;
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@ static int do_grow(struct inode *inode, u64 size)

if (gfs2_is_stuffed(ip) &&
(size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) {
error = gfs2_quota_lock_check(ip);
error = gfs2_quota_lock_check(ip, &ap);
if (error)
return error;

Expand Down
101 changes: 71 additions & 30 deletions fs/gfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,11 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
if (ret)
goto out_unlock;

ret = gfs2_quota_lock_check(ip);
if (ret)
goto out_unlock;
gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
ap.target = data_blocks + ind_blocks;
ret = gfs2_quota_lock_check(ip, &ap);
if (ret)
goto out_unlock;
ret = gfs2_inplace_reserve(ip, &ap);
if (ret)
goto out_quota_unlock;
Expand Down Expand Up @@ -764,22 +764,30 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
brelse(dibh);
return error;
}

static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
unsigned int *data_blocks, unsigned int *ind_blocks)
/**
* calc_max_reserv() - Reverse of write_calc_reserv. Given a number of
* blocks, determine how many bytes can be written.
* @ip: The inode in question.
* @len: Max cap of bytes. What we return in *len must be <= this.
* @data_blocks: Compute and return the number of data blocks needed
* @ind_blocks: Compute and return the number of indirect blocks needed
* @max_blocks: The total blocks available to work with.
*
* Returns: void, but @len, @data_blocks and @ind_blocks are filled in.
*/
static void calc_max_reserv(struct gfs2_inode *ip, loff_t *len,
unsigned int *data_blocks, unsigned int *ind_blocks,
unsigned int max_blocks)
{
loff_t max = *len;
const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
unsigned int max_blocks = ip->i_rgd->rd_free_clone;
unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);

for (tmp = max_data; tmp > sdp->sd_diptrs;) {
tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
max_data -= tmp;
}
/* This calculation isn't the exact reverse of gfs2_write_calc_reserve,
so it might end up with fewer data blocks */
if (max_data <= *data_blocks)
return;

*data_blocks = max_data;
*ind_blocks = max_blocks - max_data;
*len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift;
Expand All @@ -796,7 +804,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_alloc_parms ap = { .aflags = 0, };
unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
loff_t bytes, max_bytes;
loff_t bytes, max_bytes, max_blks = UINT_MAX;
int error;
const loff_t pos = offset;
const loff_t count = len;
Expand All @@ -818,6 +826,9 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t

gfs2_size_hint(file, offset, len);

gfs2_write_calc_reserv(ip, PAGE_SIZE, &data_blocks, &ind_blocks);
ap.min_target = data_blocks + ind_blocks;

while (len > 0) {
if (len < bytes)
bytes = len;
Expand All @@ -826,27 +837,41 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
offset += bytes;
continue;
}
error = gfs2_quota_lock_check(ip);

/* We need to determine how many bytes we can actually
* fallocate without exceeding quota or going over the
* end of the fs. We start off optimistically by assuming
* we can write max_bytes */
max_bytes = (len > max_chunk_size) ? max_chunk_size : len;

/* Since max_bytes is most likely a theoretical max, we
* calculate a more realistic 'bytes' to serve as a good
* starting point for the number of bytes we may be able
* to write */
gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
ap.target = data_blocks + ind_blocks;

error = gfs2_quota_lock_check(ip, &ap);
if (error)
return error;
retry:
gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
/* ap.allowed tells us how many blocks quota will allow
* us to write. Check if this reduces max_blks */
if (ap.allowed && ap.allowed < max_blks)
max_blks = ap.allowed;

ap.target = data_blocks + ind_blocks;
error = gfs2_inplace_reserve(ip, &ap);
if (error) {
if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
bytes >>= 1;
bytes &= bsize_mask;
if (bytes == 0)
bytes = sdp->sd_sb.sb_bsize;
goto retry;
}
if (error)
goto out_qunlock;
}
max_bytes = bytes;
calc_max_reserv(ip, (len > max_chunk_size)? max_chunk_size: len,
&max_bytes, &data_blocks, &ind_blocks);

/* check if the selected rgrp limits our max_blks further */
if (ap.allowed && ap.allowed < max_blks)
max_blks = ap.allowed;

/* Almost done. Calculate bytes that can be written using
* max_blks. We also recompute max_bytes, data_blocks and
* ind_blocks */
calc_max_reserv(ip, &max_bytes, &data_blocks,
&ind_blocks, max_blks);

rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
RES_RG_HDR + gfs2_rg_blocks(ip, data_blocks + ind_blocks);
Expand Down Expand Up @@ -930,6 +955,22 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le
return ret;
}

static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
struct file *out, loff_t *ppos,
size_t len, unsigned int flags)
{
int error;
struct gfs2_inode *ip = GFS2_I(out->f_mapping->host);

error = gfs2_rs_alloc(ip);
if (error)
return (ssize_t)error;

gfs2_size_hint(out, *ppos, len);

return iter_file_splice_write(pipe, out, ppos, len, flags);
}

#ifdef CONFIG_GFS2_FS_LOCKING_DLM

/**
Expand Down Expand Up @@ -1076,7 +1117,7 @@ const struct file_operations gfs2_file_fops = {
.lock = gfs2_lock,
.flock = gfs2_flock,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.splice_write = gfs2_file_splice_write,
.setlease = simple_nosetlease,
.fallocate = gfs2_fallocate,
};
Expand Down Expand Up @@ -1106,7 +1147,7 @@ const struct file_operations gfs2_file_fops_nolock = {
.release = gfs2_release,
.fsync = gfs2_fsync,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.splice_write = gfs2_file_splice_write,
.setlease = generic_setlease,
.fallocate = gfs2_fallocate,
};
Expand Down
47 changes: 28 additions & 19 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2047,34 +2047,41 @@ static const struct file_operations gfs2_sbstats_fops = {

int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
{
sdp->debugfs_dir = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
if (!sdp->debugfs_dir)
return -ENOMEM;
sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_glocks_fops);
if (!sdp->debugfs_dentry_glocks)
struct dentry *dent;

dent = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
if (IS_ERR_OR_NULL(dent))
goto fail;
sdp->debugfs_dir = dent;

dent = debugfs_create_file("glocks",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_glocks_fops);
if (IS_ERR_OR_NULL(dent))
goto fail;
sdp->debugfs_dentry_glocks = dent;

sdp->debugfs_dentry_glstats = debugfs_create_file("glstats",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_glstats_fops);
if (!sdp->debugfs_dentry_glstats)
dent = debugfs_create_file("glstats",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_glstats_fops);
if (IS_ERR_OR_NULL(dent))
goto fail;
sdp->debugfs_dentry_glstats = dent;

sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_sbstats_fops);
if (!sdp->debugfs_dentry_sbstats)
dent = debugfs_create_file("sbstats",
S_IFREG | S_IRUGO,
sdp->debugfs_dir, sdp,
&gfs2_sbstats_fops);
if (IS_ERR_OR_NULL(dent))
goto fail;
sdp->debugfs_dentry_sbstats = dent;

return 0;
fail:
gfs2_delete_debugfs_file(sdp);
return -ENOMEM;
return dent ? PTR_ERR(dent) : -ENOMEM;
}

void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
Expand All @@ -2100,6 +2107,8 @@ void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
int gfs2_register_debugfs(void)
{
gfs2_root = debugfs_create_dir("gfs2", NULL);
if (IS_ERR(gfs2_root))
return PTR_ERR(gfs2_root);
return gfs2_root ? 0 : -ENOMEM;
}

Expand Down
4 changes: 3 additions & 1 deletion fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,10 @@ struct gfs2_blkreserv {
* to the allocation code.
*/
struct gfs2_alloc_parms {
u32 target;
u64 target;
u32 min_target;
u32 aflags;
u64 allowed;
};

enum {
Expand Down
18 changes: 10 additions & 8 deletions fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags, unsigned *dblocks)
struct gfs2_alloc_parms ap = { .target = *dblocks, .aflags = flags, };
int error;

error = gfs2_quota_lock_check(ip);
error = gfs2_quota_lock_check(ip, &ap);
if (error)
goto out;

Expand Down Expand Up @@ -525,7 +525,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
int error;

if (da->nr_blocks) {
error = gfs2_quota_lock_check(dip);
error = gfs2_quota_lock_check(dip, &ap);
if (error)
goto fail_quota_locks;

Expand Down Expand Up @@ -953,7 +953,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,

if (da.nr_blocks) {
struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
error = gfs2_quota_lock_check(dip);
error = gfs2_quota_lock_check(dip, &ap);
if (error)
goto out_gunlock;

Expand Down Expand Up @@ -1470,7 +1470,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,

if (da.nr_blocks) {
struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
error = gfs2_quota_lock_check(ndip);
error = gfs2_quota_lock_check(ndip, &ap);
if (error)
goto out_gunlock;

Expand Down Expand Up @@ -1669,6 +1669,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
kuid_t ouid, nuid;
kgid_t ogid, ngid;
int error;
struct gfs2_alloc_parms ap;

ouid = inode->i_uid;
ogid = inode->i_gid;
Expand Down Expand Up @@ -1696,9 +1697,11 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error)
goto out;

ap.target = gfs2_get_inode_blocks(&ip->i_inode);

if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
!gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
error = gfs2_quota_check(ip, nuid, ngid);
error = gfs2_quota_check(ip, nuid, ngid, &ap);
if (error)
goto out_gunlock_q;
}
Expand All @@ -1713,9 +1716,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)

if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
!gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
u64 blocks = gfs2_get_inode_blocks(&ip->i_inode);
gfs2_quota_change(ip, -blocks, ouid, ogid);
gfs2_quota_change(ip, blocks, nuid, ngid);
gfs2_quota_change(ip, -ap.target, ouid, ogid);
gfs2_quota_change(ip, ap.target, nuid, ngid);
}

out_end_trans:
Expand Down
Loading

0 comments on commit 80dcc31

Please sign in to comment.