Re: [Cluster-devel] [GFS2 PATCH 1/4] gfs2: check quota for blocks we're about to allocate
Hi Abhi, On 12/02/15 16:54, Abhi Das wrote: This patch allows gfs2_quota_check() to take an extra argument called 'exp_change'. Prior to any allocation, gfs2_quota_check() or gfs2_quota_lock_check() is called with exp_change containing the number of blocks we expect to allocate in this operation. gfs2_quota_check() will add this number to the current usage and check the sum against the quota warns and limits and fail the operation if necessary. snip -int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) +int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, s64 exp_change) { struct gfs2_sbd *sdp = GFS2_SB(ip-i_inode); struct gfs2_quota_data *qd; @@ -1116,7 +1116,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) value = (s64)be64_to_cpu(qd-qd_qb.qb_value); spin_lock(qd_lock); - value += qd-qd_change; + value += qd-qd_change + exp_change; So I guess I don't understand why we need both qd_change and exp_change now. What sets qd_change, and why can't it be accurate (i.e. equal to exp_change) when we need it to be? Andy
Re: [Cluster-devel] [fsck.gfs2 PATCH] fsck.gfs2: Change block_map to match bitmap
- Original Message - - Original Message - Hi Bob, On 22/01/15 20:41, Bob Peterson wrote: Hi, This patch changes the old block_map structure for fsck.gfs2 to the simpler bitmap structure so that we have a 1:1 correspondence. This was done to reduce memory requirements of fsck.gfs2. I'm curious as to whether we're losing any useful information here. I see an extra bread() for BLKST_USED blocks in check_data, is that the main performance compromise, and how severe is it? Cheers, Andy Hi, That's exactly where things get a bit sticky. It used to keep track of the various GFS2_METATYPE_* block types. For the most part, dinodes were straightforward because we only needed to distinguish between directories and non-directories. Free space is pretty straightforward too, with only a few corner cases where things were marked a bad type. Unlinked also wasn't a big problem. The problem comes with blocks marked Data. In GFS1, data blocks were data blocks. In GFS2, a data block could be data or metadata. In some cases we don't care because the height will tell us if it's real data. But things get sticky when we need to distinguish between different types of non-dinode metadata in fsck. For example, what if a dinode has indirect blocks that are not really indirect blocks, but say, an extended attribute block? The old fsck could distinguish between them pretty easily because of their unique types. Going by just the bitmap alone is ambiguous, so sometimes we need to know more details, especially in cases where we have a block that's referenced multiple times: it's much more likely that one of the references is for the wrong type, and in that case, we do the extra read. This shouldn't impact performance, except for duplicate references (which is rare) and needs to be done. There are probably cases where fsck is now making assumptions about the previously processed block type for indirect blocks, so in that respect, the information is lost. However, I've tried to minimize the risk, and rigorous testing has shown that it works in many very difficult situations. You can tell my testing has been good, since I've posted so many bug fix patches recently that I've uncovered. :) In that respect, this new fsck is better than the previous. Still, there may very well be cases where the lost information causes an unforeseen problem. I'm not sure we can do anything about that but test it thoroughly. Maybe I'll try to dummy up some potential problems (like the one I gave above with indirect versus extended attribute) to see how well it does. I suppose I could try to dummy up every permutation. That is likely to uncover even more problems, most of which already exist in today's fsck. Regards, Bob Peterson Red Hat File Systems Hi, As promised, I dummied up some file systems to intentionally have the wrong metadata block types. I tried these scenarios: 1. File that had an extended attribute block that was really an indirect block. 2. File that had an indirect block that was really an extended attribute block. 3. Directory that had an extended attribute block that was really a leaf block. 4. Directory that had a leaf block that was really an extended attribute block. 5. File that had an extended attribute block that was really an ED block. 6. File whose indirect pointer points to a leaf block 7. Directory whose leaf block pointers all point to an indirect block In all these scenarios, the fsck.gfs2 with my patch made the same decisions and produced relatively the same output as the stock fsck.gfs2. So I think it's safe to push this patch now, unless anyone has an objection or has specific tests they'd like me to try. Regards, Bob Peterson Red Hat File Systems
Re: [Cluster-devel] [GFS2 PATCH 1/4] gfs2: check quota for blocks we're about to allocate
- Original Message - From: Andrew Price anpr...@redhat.com To: Abhi Das a...@redhat.com, cluster-devel@redhat.com Sent: Thursday, February 12, 2015 12:12:50 PM Subject: Re: [Cluster-devel] [GFS2 PATCH 1/4] gfs2: check quota for blocks we're about to allocate Hi Abhi, On 12/02/15 16:54, Abhi Das wrote: This patch allows gfs2_quota_check() to take an extra argument called 'exp_change'. Prior to any allocation, gfs2_quota_check() or gfs2_quota_lock_check() is called with exp_change containing the number of blocks we expect to allocate in this operation. gfs2_quota_check() will add this number to the current usage and check the sum against the quota warns and limits and fail the operation if necessary. snip -int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) +int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, s64 exp_change) { struct gfs2_sbd *sdp = GFS2_SB(ip-i_inode); struct gfs2_quota_data *qd; @@ -1116,7 +1116,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) value = (s64)be64_to_cpu(qd-qd_qb.qb_value); spin_lock(qd_lock); - value += qd-qd_change; + value += qd-qd_change + exp_change; So I guess I don't understand why we need both qd_change and exp_change now. What sets qd_change, and why can't it be accurate (i.e. equal to exp_change) when we need it to be? Andy qd_change gets set when gfs2_quota_change() is called... after the current operation has completed to account for the block allocs/deallocs that have been done during that operation. Once gfs2_quota_change() is called, that quota change is basically set in stone and do_qc() goes ahead and syncs it to the local quota_change file and eventually it'll get synced to the global quota file. So, when quota_check() is called, the qd_change value (if not synced yet) will contain the usage as of the previous operation. Does that make sense? Cheers! --Abhi
[Cluster-devel] [PATCH] GFS2: gfs2_set_acl(): Cache no acl as well
When removing a default acl or setting an access acl that is entirely represented in the file mode, we end up with acl == NULL in gfs2_set_acl(). In that case, bring gfs2 in line with other file systems and cache the NULL acl with set_cached_acl() instead of invalidating the cache with forget_cached_acl(). Signed-off-by: Andreas Gruenbacher agrue...@redhat.com --- fs/gfs2/acl.c | 6 +- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 7b31430..1be3b06 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -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; -- 2.1.0
[Cluster-devel] [GFS2 PATCH 3/4] gfs2: add new function gfs2_inpl_rsrv_ret_max_avl
This is a variant of the existing gfs2_inplace_reserve() function. If the requested number of blocks are not available to be reserved from any of the rgrps, gfs2_inplace_reserve() return -ENOSPC. gfs2_inpl_rsrv_ret_max_val() will also return the maximum blocks available in an extra parameter 'max_avail'. If acceptable to the caller logic, either of these inplace resreve functions may be called again requesting 'max_avail' blocks to avoid the -ENOSPC error. Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/rgrp.c | 13 +++-- fs/gfs2/rgrp.h | 10 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 9150207..0fa9ae3 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1942,14 +1942,17 @@ static inline int fast_to_acquire(struct gfs2_rgrpd *rgd) } /** - * gfs2_inplace_reserve - Reserve space in the filesystem + * gfs2_inpl_rsrv_ret_max_avl - Reserve space in the filesystem * @ip: the inode to reserve space for * @ap: the allocation parameters + * @max_avail: If non-NULL, return the max available extent if -ENOSPC * * Returns: errno */ -int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap) +int gfs2_inpl_rsrv_ret_max_avl(struct gfs2_inode *ip, + const struct gfs2_alloc_parms *ap, + u32 *max_avail) { struct gfs2_sbd *sdp = GFS2_SB(ip-i_inode); struct gfs2_rgrpd *begin = NULL; @@ -1958,6 +1961,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a u64 last_unlinked = NO_BLOCK; int loops = 0; u32 skip = 0; + u32 max_avlbl = 0; if (sdp-sd_args.ar_rgrplvb) flags |= GL_SKIP; @@ -2030,6 +2034,8 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a if (rs-rs_rbm.rgd-rd_free_clone = ap-target) { ip-i_rgd = rs-rs_rbm.rgd; return 0; + } else if (rs-rs_rbm.rgd-rd_free_clone max_avlbl) { + max_avlbl = rs-rs_rbm.rgd-rd_free_clone; } check_rgrp: @@ -2068,6 +2074,9 @@ next_rgrp: gfs2_log_flush(sdp, NULL, NORMAL_FLUSH); } + if (max_avail) + *max_avail = max_avlbl; + return -ENOSPC; } diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index b104f4a..2adffca 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -41,7 +41,15 @@ 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_inpl_rsrv_ret_max_avl(struct gfs2_inode *ip, + const struct gfs2_alloc_parms *ap, + u32 *max_avail); +static inline int gfs2_inplace_reserve(struct gfs2_inode *ip, + const struct gfs2_alloc_parms *ap) +{ + return gfs2_inpl_rsrv_ret_max_avl(ip, ap, NULL); +} + extern void gfs2_inplace_release(struct gfs2_inode *ip); extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, -- 1.8.1.4
[Cluster-devel] [GFS2 PATCH 0/4] fallocate quota fixes
These patches are related to bz1174295 where fallocate could exceed quota. I'm posting these for early feedback as these patches are only compile-tested so far. patch 1 - This is the patch that actually addresses the quota exceed issue. Quota checks were not being performed against the blocks about to be allocated. patch 2 - Adds new variants of quota check functions that return the number of allowed blocks if quotas are violated by the number of requested blocks patch 3 - Adds a new variant of gfs2_inplace_reserve that returns the max number of available blocks if the function returns -ENOSPC due to unavailability of the requested number of blocks. patch 4 - Allows fallocate to take advantage of patches 2 and 3 to efficiently max out quotas or fill up the fs instead of returning -EDQUOT/-ENOSPC and leaving some available blocks unallocated. Abhi Das (4): gfs2: check quota for blocks we're about to allocate gfs2: add new quota check functions gfs2: add new function gfs2_inpl_rsrv_ret_max_avl gfs2: allow fallocate to max out quotas/fs efficiently fs/gfs2/aops.c | 6 +++--- fs/gfs2/bmap.c | 2 +- fs/gfs2/file.c | 30 ++ fs/gfs2/inode.c | 14 -- fs/gfs2/quota.c | 26 +- fs/gfs2/quota.h | 20 +--- fs/gfs2/rgrp.c | 13 +++-- fs/gfs2/rgrp.h | 10 +- fs/gfs2/xattr.c | 2 +- 9 files changed, 89 insertions(+), 34 deletions(-) -- 1.8.1.4
[Cluster-devel] [GFS2 PATCH 4/4] gfs2: allow fallocate to max out quotas/fs efficiently
With the addition of gfs2_quota_lck_chk_ret_allow() and gfs2_inpl_rsrv_ret_max_avl(), we can quickly get an estimate of how many more blocks are available for allocation restricted by quota and fs size respectively. By trying to allocate what's available instead of guessing, we can max out quotas or the filesystem efficiently. Bear in mind that this applies only when the requested fallocate operation would otherwise error out with -EDQUOT or -ENOSPC without utilizing all the blocks that might still be available. Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/file.c | 24 +++- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index c9482ae..9d8e03a 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -805,6 +805,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t loff_t bsize_mask = ~((loff_t)sdp-sd_sb.sb_bsize - 1); loff_t next = (offset + len - 1) sdp-sd_sb.sb_bsize_shift; loff_t max_chunk_size = UINT_MAX bsize_mask; + u32 allow; next = (next + 1) sdp-sd_sb.sb_bsize_shift; @@ -828,20 +829,25 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t offset += bytes; continue; } - error = gfs2_quota_lock_check(ip, bytes sdp-sd_sb.sb_bsize_shift); - if (error) + quota_retry: + error = gfs2_quota_lck_chk_ret_allow(ip, +bytes sdp-sd_sb.sb_bsize_shift, +allow); + if (error) { + if (error == -EDQUOT allow) { + bytes = allow sdp-sd_sb.sb_bsize_shift; + goto quota_retry; + } return error; -retry: + } + retry: gfs2_write_calc_reserv(ip, bytes, data_blocks, ind_blocks); ap.target = data_blocks + ind_blocks; - error = gfs2_inplace_reserve(ip, ap); + error = gfs2_inpl_rsrv_ret_max_avl(ip, ap, allow); 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; + if (error == -ENOSPC allow) { + bytes = allow sdp-sd_sb.sb_bsize_shift; goto retry; } goto out_qunlock; -- 1.8.1.4
[Cluster-devel] [GFS2 PATCH 1/4] gfs2: check quota for blocks we're about to allocate
This patch allows gfs2_quota_check() to take an extra argument called 'exp_change'. Prior to any allocation, gfs2_quota_check() or gfs2_quota_lock_check() is called with exp_change containing the number of blocks we expect to allocate in this operation. gfs2_quota_check() will add this number to the current usage and check the sum against the quota warns and limits and fail the operation if necessary. Resolves: rhbz#1174295 Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/aops.c | 6 +++--- fs/gfs2/bmap.c | 2 +- fs/gfs2/file.c | 8 fs/gfs2/inode.c | 14 -- fs/gfs2/quota.c | 4 ++-- fs/gfs2/quota.h | 6 +++--- fs/gfs2/xattr.c | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 805b37f..aa7700a 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -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.target); if (error) goto out_unlock; - requested = data_blocks + ind_blocks; - ap.target = requested; error = gfs2_inplace_reserve(ip, ap); if (error) goto out_qunlock; diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index f0b945a..86cc7b2 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -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.target); if (error) return error; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 6e600ab..c9482ae 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -429,11 +429,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.target); + if (ret) + goto out_unlock; ret = gfs2_inplace_reserve(ip, ap); if (ret) goto out_quota_unlock; @@ -828,7 +828,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t offset += bytes; continue; } - error = gfs2_quota_lock_check(ip); + error = gfs2_quota_lock_check(ip, bytes sdp-sd_sb.sb_bsize_shift); if (error) return error; retry: diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 73c72253..67ffa07 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -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.target); 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.target); 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.target); 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.target); 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; + u64 blocks; ouid = inode-i_uid; ogid = inode-i_gid; @@ -1696,9 +1697,11 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
[Cluster-devel] [GFS2 PATCH 2/4] gfs2: add new quota check functions
gfs2_quota_chk_ret_allow and gfs2_quota_lck_chk_ret_allow are variants of gfs2_quota_check and gfs2_quota_lock_check respectively. If an operation will not succeed due to a quota violation, these functions will return the number of blocks that quota will actually allow without failing in an extra parameter 'allow' If acceptable to the caller logic, any of the quota_check functions may be called again with the 'allow'ed blocks to try and avoid a quota violation. Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/quota.c | 24 fs/gfs2/quota.h | 20 +--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index e2f86ec..98cdf97 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1092,8 +1092,20 @@ 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, s64 exp_change) +/** + * gfs2_quota_chk_ret_allow - Checks if adding the specified number of + * blocks will exceed usr/grp quotas + * @ip: The inode for which this check is being performed + * @uid: The uid to check against + * @gid: The gid to check against + * @exp_change: The expected change in blocks + * @allow: If non-NULL, we should return the number of blocks + * quota will allow if exp_change exceeds limits + * + * Returns: 0 on success, error code otherwise. + */ +int gfs2_quota_chk_ret_allow(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, +s64 exp_change, u32 *allow) { struct gfs2_sbd *sdp = GFS2_SB(ip-i_inode); struct gfs2_quota_data *qd; @@ -1119,12 +1131,16 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, s64 exp_chan value += qd-qd_change + exp_change; spin_unlock(qd_lock); - if (be64_to_cpu(qd-qd_qb.qb_limit) (s64)be64_to_cpu(qd-qd_qb.qb_limit) value) { + 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; + if (allow) { + *allow = (s64)be64_to_cpu(qd-qd_qb.qb_limit) - + (value - exp_change); + } break; } else if (be64_to_cpu(qd-qd_qb.qb_warn) (s64)be64_to_cpu(qd-qd_qb.qb_warn) value diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 1457c66..49d1fd9 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -24,7 +24,14 @@ 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, s64 exp_change); +extern int gfs2_quota_chk_ret_allow(struct gfs2_inode *ip, kuid_t uid, + kgid_t gid, s64 exp_change, u32 *allow); +static inline int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, + s64 exp_change) +{ + return gfs2_quota_chk_ret_allow(ip, uid, gid, exp_change, NULL); +} + extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, kuid_t uid, kgid_t gid); @@ -37,7 +44,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, s64 exp_change) +static inline int gfs2_quota_lck_chk_ret_allow(struct gfs2_inode *ip, + s64 exp_change, u32 *allow) { struct gfs2_sbd *sdp = GFS2_SB(ip-i_inode); int ret; @@ -48,12 +56,18 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, s64 exp_change) 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, exp_change); + ret = gfs2_quota_chk_ret_allow(ip, ip-i_inode.i_uid, ip-i_inode.i_gid, + exp_change, allow); if (ret) gfs2_quota_unlock(ip); return ret; } +static inline int gfs2_quota_lock_check(struct gfs2_inode *ip, s64 exp_change) +{ + return gfs2_quota_lck_chk_ret_allow(ip, exp_change, NULL); +} + extern const struct quotactl_ops gfs2_quotactl_ops; extern struct shrinker gfs2_qd_shrinker; extern struct list_lru gfs2_qd_lru; -- 1.8.1.4
Re: [Cluster-devel] [GFS2 PATCH 0/4] fallocate quota fixes
- Original Message - These patches are related to bz1174295 where fallocate could exceed quota. I'm posting these for early feedback as these patches are only compile-tested so far. patch 1 - This is the patch that actually addresses the quota exceed issue. Quota checks were not being performed against the blocks about to be allocated. patch 2 - Adds new variants of quota check functions that return the number of allowed blocks if quotas are violated by the number of requested blocks patch 3 - Adds a new variant of gfs2_inplace_reserve that returns the max number of available blocks if the function returns -ENOSPC due to unavailability of the requested number of blocks. patch 4 - Allows fallocate to take advantage of patches 2 and 3 to efficiently max out quotas or fill up the fs instead of returning -EDQUOT/-ENOSPC and leaving some available blocks unallocated. Abhi Das (4): gfs2: check quota for blocks we're about to allocate gfs2: add new quota check functions gfs2: add new function gfs2_inpl_rsrv_ret_max_avl gfs2: allow fallocate to max out quotas/fs efficiently fs/gfs2/aops.c | 6 +++--- fs/gfs2/bmap.c | 2 +- fs/gfs2/file.c | 30 ++ fs/gfs2/inode.c | 14 -- fs/gfs2/quota.c | 26 +- fs/gfs2/quota.h | 20 +--- fs/gfs2/rgrp.c | 13 +++-- fs/gfs2/rgrp.h | 10 +- fs/gfs2/xattr.c | 2 +- 9 files changed, 89 insertions(+), 34 deletions(-) -- 1.8.1.4 Hi, ACK. Looks okay to me. Regards, Bob Peterson Red Hat File Systems