diff options
author | Abhi Das <adas@redhat.com> | 2015-03-18 13:04:37 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2015-03-18 13:47:10 -0400 |
commit | 25435e5ed611f310dda889940cbc4c45b3ecd9ec (patch) | |
tree | 9610acd909a2a48a01f092a58c163af4cac1aad2 | |
parent | b8fbf471edb3dbf441716fd2a52a7ca76c381381 (diff) |
gfs2: allow quota_check and inplace_reserve to return available blocks
struct gfs2_alloc_parms is passed to gfs2_quota_check() and
gfs2_inplace_reserve() with ap->target containing the number of
blocks being requested for allocation in the current operation.
We add a new field to struct gfs2_alloc_parms called 'allowed'.
gfs2_quota_check() and gfs2_inplace_reserve() return the max
blocks allowed by quota and the max blocks allowed by the chosen
rgrp respectively in 'allowed'.
A new field 'min_target', when non-zero, tells gfs2_quota_check()
and gfs2_inplace_reserve() to not return -EDQUOT/-ENOSPC when
there are atleast 'min_target' blocks allowable/available. The
assumption is that the caller is ok with just 'min_target' blocks
and will likely proceed with allocating them.
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/incore.h | 2 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 52 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 20 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 3 |
4 files changed, 58 insertions, 19 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 3a4ea50c9113..58b75abf6ab2 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -302,7 +302,9 @@ struct gfs2_blkreserv { | |||
302 | */ | 302 | */ |
303 | struct gfs2_alloc_parms { | 303 | struct gfs2_alloc_parms { |
304 | u64 target; | 304 | u64 target; |
305 | u32 min_target; | ||
305 | u32 aflags; | 306 | u32 aflags; |
307 | u64 allowed; | ||
306 | }; | 308 | }; |
307 | 309 | ||
308 | enum { | 310 | enum { |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 964a769a7a86..55614685a31c 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -1094,15 +1094,33 @@ static int print_message(struct gfs2_quota_data *qd, char *type) | |||
1094 | return 0; | 1094 | return 0; |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | /** | ||
1098 | * gfs2_quota_check - check if allocating new blocks will exceed quota | ||
1099 | * @ip: The inode for which this check is being performed | ||
1100 | * @uid: The uid to check against | ||
1101 | * @gid: The gid to check against | ||
1102 | * @ap: The allocation parameters. ap->target contains the requested | ||
1103 | * blocks. ap->min_target, if set, contains the minimum blks | ||
1104 | * requested. | ||
1105 | * | ||
1106 | * Returns: 0 on success. | ||
1107 | * min_req = ap->min_target ? ap->min_target : ap->target; | ||
1108 | * quota must allow atleast min_req blks for success and | ||
1109 | * ap->allowed is set to the number of blocks allowed | ||
1110 | * | ||
1111 | * -EDQUOT otherwise, quota violation. ap->allowed is set to number | ||
1112 | * of blocks available. | ||
1113 | */ | ||
1097 | int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, | 1114 | int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, |
1098 | struct gfs2_alloc_parms *ap) | 1115 | struct gfs2_alloc_parms *ap) |
1099 | { | 1116 | { |
1100 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1117 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1101 | struct gfs2_quota_data *qd; | 1118 | struct gfs2_quota_data *qd; |
1102 | s64 value; | 1119 | s64 value, warn, limit; |
1103 | unsigned int x; | 1120 | unsigned int x; |
1104 | int error = 0; | 1121 | int error = 0; |
1105 | 1122 | ||
1123 | ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */ | ||
1106 | if (!test_bit(GIF_QD_LOCKED, &ip->i_flags)) | 1124 | if (!test_bit(GIF_QD_LOCKED, &ip->i_flags)) |
1107 | return 0; | 1125 | return 0; |
1108 | 1126 | ||
@@ -1116,29 +1134,37 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid, | |||
1116 | qid_eq(qd->qd_id, make_kqid_gid(gid)))) | 1134 | qid_eq(qd->qd_id, make_kqid_gid(gid)))) |
1117 | continue; | 1135 | continue; |
1118 | 1136 | ||
1137 | warn = (s64)be64_to_cpu(qd->qd_qb.qb_warn); | ||
1138 | limit = (s64)be64_to_cpu(qd->qd_qb.qb_limit); | ||
1119 | value = (s64)be64_to_cpu(qd->qd_qb.qb_value); | 1139 | value = (s64)be64_to_cpu(qd->qd_qb.qb_value); |
1120 | spin_lock(&qd_lock); | 1140 | spin_lock(&qd_lock); |
1121 | value += qd->qd_change + ap->target; | 1141 | value += qd->qd_change; |
1122 | spin_unlock(&qd_lock); | 1142 | spin_unlock(&qd_lock); |
1123 | 1143 | ||
1124 | if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { | 1144 | if (limit > 0 && (limit - value) < ap->allowed) |
1125 | print_message(qd, "exceeded"); | 1145 | ap->allowed = limit - value; |
1126 | quota_send_warning(qd->qd_id, | 1146 | /* If we can't meet the target */ |
1127 | sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN); | 1147 | if (limit && limit < (value + (s64)ap->target)) { |
1128 | error = -EDQUOT; | 1148 | /* If no min_target specified or we don't meet |
1129 | break; | 1149 | * min_target, return -EDQUOT */ |
1130 | } else if (be64_to_cpu(qd->qd_qb.qb_warn) && | 1150 | if (!ap->min_target || ap->min_target > ap->allowed) { |
1131 | (s64)be64_to_cpu(qd->qd_qb.qb_warn) < value && | 1151 | print_message(qd, "exceeded"); |
1152 | quota_send_warning(qd->qd_id, | ||
1153 | sdp->sd_vfs->s_dev, | ||
1154 | QUOTA_NL_BHARDWARN); | ||
1155 | error = -EDQUOT; | ||
1156 | break; | ||
1157 | } | ||
1158 | } else if (warn && warn < value && | ||
1132 | time_after_eq(jiffies, qd->qd_last_warn + | 1159 | time_after_eq(jiffies, qd->qd_last_warn + |
1133 | gfs2_tune_get(sdp, | 1160 | gfs2_tune_get(sdp, gt_quota_warn_period) |
1134 | gt_quota_warn_period) * HZ)) { | 1161 | * HZ)) { |
1135 | quota_send_warning(qd->qd_id, | 1162 | quota_send_warning(qd->qd_id, |
1136 | sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN); | 1163 | sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN); |
1137 | error = print_message(qd, "warning"); | 1164 | error = print_message(qd, "warning"); |
1138 | qd->qd_last_warn = jiffies; | 1165 | qd->qd_last_warn = jiffies; |
1139 | } | 1166 | } |
1140 | } | 1167 | } |
1141 | |||
1142 | return error; | 1168 | return error; |
1143 | } | 1169 | } |
1144 | 1170 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 9150207f365c..6af2396a317c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -1946,10 +1946,18 @@ static inline int fast_to_acquire(struct gfs2_rgrpd *rgd) | |||
1946 | * @ip: the inode to reserve space for | 1946 | * @ip: the inode to reserve space for |
1947 | * @ap: the allocation parameters | 1947 | * @ap: the allocation parameters |
1948 | * | 1948 | * |
1949 | * Returns: errno | 1949 | * We try our best to find an rgrp that has at least ap->target blocks |
1950 | * available. After a couple of passes (loops == 2), the prospects of finding | ||
1951 | * such an rgrp diminish. At this stage, we return the first rgrp that has | ||
1952 | * atleast ap->min_target blocks available. Either way, we set ap->allowed to | ||
1953 | * the number of blocks available in the chosen rgrp. | ||
1954 | * | ||
1955 | * Returns: 0 on success, | ||
1956 | * -ENOMEM if a suitable rgrp can't be found | ||
1957 | * errno otherwise | ||
1950 | */ | 1958 | */ |
1951 | 1959 | ||
1952 | int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap) | 1960 | int gfs2_inplace_reserve(struct gfs2_inode *ip, struct gfs2_alloc_parms *ap) |
1953 | { | 1961 | { |
1954 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1962 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1955 | struct gfs2_rgrpd *begin = NULL; | 1963 | struct gfs2_rgrpd *begin = NULL; |
@@ -2012,7 +2020,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a | |||
2012 | /* Skip unuseable resource groups */ | 2020 | /* Skip unuseable resource groups */ |
2013 | if ((rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC | | 2021 | if ((rs->rs_rbm.rgd->rd_flags & (GFS2_RGF_NOALLOC | |
2014 | GFS2_RDF_ERROR)) || | 2022 | GFS2_RDF_ERROR)) || |
2015 | (ap->target > rs->rs_rbm.rgd->rd_extfail_pt)) | 2023 | (loops == 0 && ap->target > rs->rs_rbm.rgd->rd_extfail_pt)) |
2016 | goto skip_rgrp; | 2024 | goto skip_rgrp; |
2017 | 2025 | ||
2018 | if (sdp->sd_args.ar_rgrplvb) | 2026 | if (sdp->sd_args.ar_rgrplvb) |
@@ -2027,11 +2035,13 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a | |||
2027 | goto check_rgrp; | 2035 | goto check_rgrp; |
2028 | 2036 | ||
2029 | /* If rgrp has enough free space, use it */ | 2037 | /* If rgrp has enough free space, use it */ |
2030 | if (rs->rs_rbm.rgd->rd_free_clone >= ap->target) { | 2038 | if (rs->rs_rbm.rgd->rd_free_clone >= ap->target || |
2039 | (loops == 2 && ap->min_target && | ||
2040 | rs->rs_rbm.rgd->rd_free_clone >= ap->min_target)) { | ||
2031 | ip->i_rgd = rs->rs_rbm.rgd; | 2041 | ip->i_rgd = rs->rs_rbm.rgd; |
2042 | ap->allowed = ip->i_rgd->rd_free_clone; | ||
2032 | return 0; | 2043 | return 0; |
2033 | } | 2044 | } |
2034 | |||
2035 | check_rgrp: | 2045 | check_rgrp: |
2036 | /* Check for unlinked inodes which can be reclaimed */ | 2046 | /* Check for unlinked inodes which can be reclaimed */ |
2037 | if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK) | 2047 | if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK) |
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index b104f4af3afd..68972ecfbb01 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -41,7 +41,8 @@ extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh); | |||
41 | extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); | 41 | extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); |
42 | 42 | ||
43 | #define GFS2_AF_ORLOV 1 | 43 | #define GFS2_AF_ORLOV 1 |
44 | extern int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *ap); | 44 | extern int gfs2_inplace_reserve(struct gfs2_inode *ip, |
45 | struct gfs2_alloc_parms *ap); | ||
45 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 46 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
46 | 47 | ||
47 | extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, | 48 | extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n, |