GFS2: merge window

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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJVLTjHAAoJENeLYdPf93o7QdsIAIvnyE4HFXct/OjsjNdhkf9o
 vY20tnSDfFwySlsGa1ZvI8H8VX5SFzbJgHLFNSuLQqB8L5tN5unlLT+tNyjIGKlp
 mW34RU7f7oFFmAxhb+gTUJYY7WhQK0GEvrwcILJxNXvNUhVxufArGwKWO9XWoMcU
 rLlwpWQvmMLzgXCLXEUDJXy442Hv78r5b7BSxFwGYjq4ak6MSPqQ38KwPFcq3e5d
 gH3IpWIefwPSStV7CpuZwSrPJ344a2GZRVQNboe/K2qhyDiAiOwxHCFz3X8e1u7G
 SX+SV6dO4C9MLeovUbLYfFQ1Y8tLtceQpzRDb0cu6UJvLJ3dDl2ZOa9OOMKmk4M=
 =l/IT
 -----END PGP SIGNATURE-----

Merge tag 'gfs2-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
Linus Torvalds 2015-04-14 16:09:18 -07:00
commit 80dcc31fbe
13 changed files with 187 additions and 98 deletions

View File

@ -4337,10 +4337,10 @@ F: scripts/get_maintainer.pl
GFS2 FILE SYSTEM
M: Steven Whitehouse <swhiteho@redhat.com>
M: Bob Peterson <rpeterso@redhat.com>
L: cluster-devel@redhat.com
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/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
@ -764,22 +764,30 @@ out:
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;
@ -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;
@ -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;
@ -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);
@ -930,6 +955,22 @@ out_uninit:
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
/**
@ -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,
};
@ -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,
};

View File

@ -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)
goto fail;
struct dentry *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_dir(sdp->sd_table_name, gfs2_root);
if (IS_ERR_OR_NULL(dent))
goto fail;
sdp->debugfs_dir = 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("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;
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;
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)
@ -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;
}

View File

@ -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 {

View File

@ -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;
@ -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;
@ -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;
@ -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;
@ -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;
@ -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;
}
@ -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:

View File

@ -923,6 +923,9 @@ restart:
if (error)
return error;
if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags))
force_refresh = FORCE;
qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
@ -974,11 +977,8 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
sizeof(struct gfs2_quota_data *), sort_qd, NULL);
for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
int force = NO_FORCE;
qd = ip->i_res->rs_qa_qd[x];
if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags))
force = FORCE;
error = do_glock(qd, force, &ip->i_res->rs_qa_qd_ghs[x]);
error = do_glock(qd, NO_FORCE, &ip->i_res->rs_qa_qd_ghs[x]);
if (error)
break;
}
@ -1094,14 +1094,33 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
return 0;
}
int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
/**
* gfs2_quota_check - check if allocating new blocks will exceed quota
* @ip: The inode for which this check is being performed
* @uid: The uid to check against
* @gid: The gid to check against
* @ap: The allocation parameters. ap->target contains the requested
* blocks. ap->min_target, if set, contains the minimum blks
* requested.
*
* Returns: 0 on success.
* min_req = ap->min_target ? ap->min_target : ap->target;
* quota must allow atleast min_req blks for success and
* ap->allowed is set to the number of blocks allowed
*
* -EDQUOT otherwise, quota violation. ap->allowed is set to number
* of blocks available.
*/
int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
struct gfs2_alloc_parms *ap)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_quota_data *qd;
s64 value;
s64 value, warn, limit;
unsigned int x;
int error = 0;
ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */
if (!test_bit(GIF_QD_LOCKED, &ip->i_flags))
return 0;
@ -1115,30 +1134,37 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
qid_eq(qd->qd_id, make_kqid_gid(gid))))
continue;
warn = (s64)be64_to_cpu(qd->qd_qb.qb_warn);
limit = (s64)be64_to_cpu(qd->qd_qb.qb_limit);
value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
spin_lock(&qd_lock);
value += qd->qd_change;
spin_unlock(&qd_lock);
if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
print_message(qd, "exceeded");
quota_send_warning(qd->qd_id,
sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
error = -EDQUOT;
break;
} else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
(s64)be64_to_cpu(qd->qd_qb.qb_warn) < value &&
if (limit > 0 && (limit - value) < ap->allowed)
ap->allowed = limit - value;
/* If we can't meet the target */
if (limit && limit < (value + (s64)ap->target)) {
/* If no min_target specified or we don't meet
* min_target, return -EDQUOT */
if (!ap->min_target || ap->min_target > ap->allowed) {
print_message(qd, "exceeded");
quota_send_warning(qd->qd_id,
sdp->sd_vfs->s_dev,
QUOTA_NL_BHARDWARN);
error = -EDQUOT;
break;
}
} else if (warn && warn < value &&
time_after_eq(jiffies, qd->qd_last_warn +
gfs2_tune_get(sdp,
gt_quota_warn_period) * HZ)) {
gfs2_tune_get(sdp, gt_quota_warn_period)
* HZ)) {
quota_send_warning(qd->qd_id,
sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
error = print_message(qd, "warning");
qd->qd_last_warn = jiffies;
}
}
return error;
}

View File

@ -24,7 +24,8 @@ extern void gfs2_quota_unhold(struct gfs2_inode *ip);
extern int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);
extern void gfs2_quota_unlock(struct gfs2_inode *ip);
extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);
extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
struct gfs2_alloc_parms *ap);
extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
kuid_t uid, kgid_t gid);
@ -37,7 +38,8 @@ extern int gfs2_quotad(void *data);
extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp);
static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
static inline int gfs2_quota_lock_check(struct gfs2_inode *ip,
struct gfs2_alloc_parms *ap)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
int ret;
@ -48,7 +50,7 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
return ret;
if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
return 0;
ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid, ap);
if (ret)
gfs2_quota_unlock(ip);
return ret;

View File

@ -1946,10 +1946,18 @@ static inline int fast_to_acquire(struct gfs2_rgrpd *rgd)
* @ip: the inode to reserve space for
* @ap: the allocation parameters
*
* Returns: errno
* We try our best to find an rgrp that has at least ap->target blocks
* available. After a couple of passes (loops == 2), the prospects of finding
* such an rgrp diminish. At this stage, we return the first rgrp that has
* atleast ap->min_target blocks available. Either way, we set ap->allowed to
* the number of blocks available in the chosen rgrp.
*
* Returns: 0 on success,
* -ENOMEM if a suitable rgrp can't be found
* errno otherwise
*/
int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap)
int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *begin = NULL;
@ -2012,7 +2020,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a
/* Skip unuseable resource groups */
if ((rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC |
GFS2_RDF_ERROR)) ||
(ap->target > rs->rs_rbm.rgd->rd_extfail_pt))
(loops == 0 && ap->target > rs->rs_rbm.rgd->rd_extfail_pt))
goto skip_rgrp;
if (sdp->sd_args.ar_rgrplvb)
@ -2027,11 +2035,13 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a
goto check_rgrp;
/* If rgrp has enough free space, use it */
if (rs->rs_rbm.rgd->rd_free_clone >= ap->target) {
if (rs->rs_rbm.rgd->rd_free_clone >= ap->target ||
(loops == 2 && ap->min_target &&
rs->rs_rbm.rgd->rd_free_clone >= ap->min_target)) {
ip->i_rgd = rs->rs_rbm.rgd;
ap->allowed = ip->i_rgd->rd_free_clone;
return 0;
}
check_rgrp:
/* Check for unlinked inodes which can be reclaimed */
if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK)

View File

@ -41,7 +41,8 @@ extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
#define GFS2_AF_ORLOV 1
extern int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap);
extern int gfs2_inplace_reserve(struct gfs2_inode *ip,
struct gfs2_alloc_parms *ap);
extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,

View File

@ -732,7 +732,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
if (error)
return error;
error = gfs2_quota_lock_check(ip);
error = gfs2_quota_lock_check(ip, &ap);
if (error)
return error;