aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhi Das <adas@redhat.com>2015-03-18 13:03:41 -0400
committerBob Peterson <rpeterso@redhat.com>2015-03-18 13:46:54 -0400
commitb8fbf471edb3dbf441716fd2a52a7ca76c381381 (patch)
treea5a2132cc29397dd1f1d8892497dbf18b2fb125f
parentf1ea6f4ec0a48d7b6bbf4d380a0ac14d69fadb44 (diff)
gfs2: perform quota checks against allocation parameters
Use struct gfs2_alloc_parms as an argument to gfs2_quota_check() and gfs2_quota_lock_check() to check for quota violations while accounting for the new blocks requested by the current operation in ap->target. Previously, the number of new blocks requested during an operation were not accounted for during quota_check and would allow these operations to exceed quota. This was not very apparent since most operations allocated only 1 block at a time and quotas would get violated in the next operation. i.e. quota excess would only be by 1 block or so. With fallocate, (where we allocate a bunch of blocks at once) the quota excess is non-trivial and is addressed by this patch. Signed-off-by: Abhi Das <adas@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com> Acked-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/aops.c6
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/file.c15
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/inode.c18
-rw-r--r--fs/gfs2/quota.c6
-rw-r--r--fs/gfs2/quota.h8
-rw-r--r--fs/gfs2/xattr.c2
8 files changed, 32 insertions, 27 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 4ad4f94edebe..7bc5c82423ea 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,
671 671
672 if (alloc_required) { 672 if (alloc_required) {
673 struct gfs2_alloc_parms ap = { .aflags = 0, }; 673 struct gfs2_alloc_parms ap = { .aflags = 0, };
674 error = gfs2_quota_lock_check(ip); 674 requested = data_blocks + ind_blocks;
675 ap.target = requested;
676 error = gfs2_quota_lock_check(ip, &ap);
675 if (error) 677 if (error)
676 goto out_unlock; 678 goto out_unlock;
677 679
678 requested = data_blocks + ind_blocks;
679 ap.target = requested;
680 error = gfs2_inplace_reserve(ip, &ap); 680 error = gfs2_inplace_reserve(ip, &ap);
681 if (error) 681 if (error)
682 goto out_qunlock; 682 goto out_qunlock;
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index f0b945ab853e..61296ecbd0e2 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1224,7 +1224,7 @@ static int do_grow(struct inode *inode, u64 size)
1224 1224
1225 if (gfs2_is_stuffed(ip) && 1225 if (gfs2_is_stuffed(ip) &&
1226 (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) { 1226 (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) {
1227 error = gfs2_quota_lock_check(ip); 1227 error = gfs2_quota_lock_check(ip, &ap);
1228 if (error) 1228 if (error)
1229 return error; 1229 return error;
1230 1230
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 7353c0a01a1e..c569adbc1431 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)
429 if (ret) 429 if (ret)
430 goto out_unlock; 430 goto out_unlock;
431 431
432 ret = gfs2_quota_lock_check(ip);
433 if (ret)
434 goto out_unlock;
435 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks); 432 gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
436 ap.target = data_blocks + ind_blocks; 433 ap.target = data_blocks + ind_blocks;
434 ret = gfs2_quota_lock_check(ip, &ap);
435 if (ret)
436 goto out_unlock;
437 ret = gfs2_inplace_reserve(ip, &ap); 437 ret = gfs2_inplace_reserve(ip, &ap);
438 if (ret) 438 if (ret)
439 goto out_quota_unlock; 439 goto out_quota_unlock;
@@ -827,13 +827,13 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
827 offset += bytes; 827 offset += bytes;
828 continue; 828 continue;
829 } 829 }
830 error = gfs2_quota_lock_check(ip);
831 if (error)
832 return error;
833retry: 830retry:
834 gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks); 831 gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
835
836 ap.target = data_blocks + ind_blocks; 832 ap.target = data_blocks + ind_blocks;
833
834 error = gfs2_quota_lock_check(ip, &ap);
835 if (error)
836 return error;
837 error = gfs2_inplace_reserve(ip, &ap); 837 error = gfs2_inplace_reserve(ip, &ap);
838 if (error) { 838 if (error) {
839 if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { 839 if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
@@ -841,6 +841,7 @@ retry:
841 bytes &= bsize_mask; 841 bytes &= bsize_mask;
842 if (bytes == 0) 842 if (bytes == 0)
843 bytes = sdp->sd_sb.sb_bsize; 843 bytes = sdp->sd_sb.sb_bsize;
844 gfs2_quota_unlock(ip);
844 goto retry; 845 goto retry;
845 } 846 }
846 goto out_qunlock; 847 goto out_qunlock;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 7a2dbbc0d634..3a4ea50c9113 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -301,7 +301,7 @@ struct gfs2_blkreserv {
301 * to the allocation code. 301 * to the allocation code.
302 */ 302 */
303struct gfs2_alloc_parms { 303struct gfs2_alloc_parms {
304 u32 target; 304 u64 target;
305 u32 aflags; 305 u32 aflags;
306}; 306};
307 307
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 73c72253faac..08bc84d7e768 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)
382 struct gfs2_alloc_parms ap = { .target = *dblocks, .aflags = flags, }; 382 struct gfs2_alloc_parms ap = { .target = *dblocks, .aflags = flags, };
383 int error; 383 int error;
384 384
385 error = gfs2_quota_lock_check(ip); 385 error = gfs2_quota_lock_check(ip, &ap);
386 if (error) 386 if (error)
387 goto out; 387 goto out;
388 388
@@ -525,7 +525,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
525 int error; 525 int error;
526 526
527 if (da->nr_blocks) { 527 if (da->nr_blocks) {
528 error = gfs2_quota_lock_check(dip); 528 error = gfs2_quota_lock_check(dip, &ap);
529 if (error) 529 if (error)
530 goto fail_quota_locks; 530 goto fail_quota_locks;
531 531
@@ -953,7 +953,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
953 953
954 if (da.nr_blocks) { 954 if (da.nr_blocks) {
955 struct gfs2_alloc_parms ap = { .target = da.nr_blocks, }; 955 struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
956 error = gfs2_quota_lock_check(dip); 956 error = gfs2_quota_lock_check(dip, &ap);
957 if (error) 957 if (error)
958 goto out_gunlock; 958 goto out_gunlock;
959 959
@@ -1470,7 +1470,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
1470 1470
1471 if (da.nr_blocks) { 1471 if (da.nr_blocks) {
1472 struct gfs2_alloc_parms ap = { .target = da.nr_blocks, }; 1472 struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
1473 error = gfs2_quota_lock_check(ndip); 1473 error = gfs2_quota_lock_check(ndip, &ap);
1474 if (error) 1474 if (error)
1475 goto out_gunlock; 1475 goto out_gunlock;
1476 1476
@@ -1669,6 +1669,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
1669 kuid_t ouid, nuid; 1669 kuid_t ouid, nuid;
1670 kgid_t ogid, ngid; 1670 kgid_t ogid, ngid;
1671 int error; 1671 int error;
1672 struct gfs2_alloc_parms ap;
1672 1673
1673 ouid = inode->i_uid; 1674 ouid = inode->i_uid;
1674 ogid = inode->i_gid; 1675 ogid = inode->i_gid;
@@ -1696,9 +1697,11 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
1696 if (error) 1697 if (error)
1697 goto out; 1698 goto out;
1698 1699
1700 ap.target = gfs2_get_inode_blocks(&ip->i_inode);
1701
1699 if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || 1702 if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
1700 !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) { 1703 !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
1701 error = gfs2_quota_check(ip, nuid, ngid); 1704 error = gfs2_quota_check(ip, nuid, ngid, &ap);
1702 if (error) 1705 if (error)
1703 goto out_gunlock_q; 1706 goto out_gunlock_q;
1704 } 1707 }
@@ -1713,9 +1716,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
1713 1716
1714 if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) || 1717 if (!uid_eq(ouid, NO_UID_QUOTA_CHANGE) ||
1715 !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) { 1718 !gid_eq(ogid, NO_GID_QUOTA_CHANGE)) {
1716 u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); 1719 gfs2_quota_change(ip, -ap.target, ouid, ogid);
1717 gfs2_quota_change(ip, -blocks, ouid, ogid); 1720 gfs2_quota_change(ip, ap.target, nuid, ngid);
1718 gfs2_quota_change(ip, blocks, nuid, ngid);
1719 } 1721 }
1720 1722
1721out_end_trans: 1723out_end_trans:
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 3aa17d4d1cfc..964a769a7a86 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1094,7 +1094,8 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
1094 return 0; 1094 return 0;
1095} 1095}
1096 1096
1097int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) 1097int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
1098 struct gfs2_alloc_parms *ap)
1098{ 1099{
1099 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 1100 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
1100 struct gfs2_quota_data *qd; 1101 struct gfs2_quota_data *qd;
@@ -1117,14 +1118,13 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid)
1117 1118
1118 value = (s64)be64_to_cpu(qd->qd_qb.qb_value); 1119 value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
1119 spin_lock(&qd_lock); 1120 spin_lock(&qd_lock);
1120 value += qd->qd_change; 1121 value += qd->qd_change + ap->target;
1121 spin_unlock(&qd_lock); 1122 spin_unlock(&qd_lock);
1122 1123
1123 if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { 1124 if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
1124 print_message(qd, "exceeded"); 1125 print_message(qd, "exceeded");
1125 quota_send_warning(qd->qd_id, 1126 quota_send_warning(qd->qd_id,
1126 sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN); 1127 sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
1127
1128 error = -EDQUOT; 1128 error = -EDQUOT;
1129 break; 1129 break;
1130 } else if (be64_to_cpu(qd->qd_qb.qb_warn) && 1130 } else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
index 55d506eb3c4a..ad04b3acae2b 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -24,7 +24,8 @@ extern void gfs2_quota_unhold(struct gfs2_inode *ip);
24extern int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); 24extern int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid);
25extern void gfs2_quota_unlock(struct gfs2_inode *ip); 25extern void gfs2_quota_unlock(struct gfs2_inode *ip);
26 26
27extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid); 27extern int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
28 struct gfs2_alloc_parms *ap);
28extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, 29extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
29 kuid_t uid, kgid_t gid); 30 kuid_t uid, kgid_t gid);
30 31
@@ -37,7 +38,8 @@ extern int gfs2_quotad(void *data);
37 38
38extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp); 39extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp);
39 40
40static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) 41static inline int gfs2_quota_lock_check(struct gfs2_inode *ip,
42 struct gfs2_alloc_parms *ap)
41{ 43{
42 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 44 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
43 int ret; 45 int ret;
@@ -48,7 +50,7 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
48 return ret; 50 return ret;
49 if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) 51 if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
50 return 0; 52 return 0;
51 ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); 53 ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid, ap);
52 if (ret) 54 if (ret)
53 gfs2_quota_unlock(ip); 55 gfs2_quota_unlock(ip);
54 return ret; 56 return ret;
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 0b81f783f787..fd260ce8869a 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -732,7 +732,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
732 if (error) 732 if (error)
733 return error; 733 return error;
734 734
735 error = gfs2_quota_lock_check(ip); 735 error = gfs2_quota_lock_check(ip, &ap);
736 if (error) 736 if (error)
737 return error; 737 return error;
738 738