Skip to content

Commit 432928c

Browse files
AstralBobAndreas Gruenbacher
authored andcommitted
gfs2: Add quota_change type
Function do_qc has two main uses: (1) to re-sync the local quota changes (qd) to the master quotas, and (2) normal quota changes. In the case of normal quota changes, the change can be positive or negative, as the quota usage goes up and down. Before this patch function do_qc was distinguishing one from another by whether the resulting value is or isn't zero: In the case of a re-sync (called do_sync) the quota value is moved from the temporary value to a master value, so the amount is added to one and subtracted from the other. The problem is that since the values can be positive or negative we can occasionally run into situations where we are not doing a re-sync but the quota change just happens to cancel out the previous value. In the case of a re-sync extra references and locks are taken, and so do_qc needs to release them. In the case of a normal quota change, no extra references and locks are taken, so it must not try to release them. The problem is: if the quota change is not a re-sync but the value just happens to cancel out the original quota change, the resulting zero value fools do_qc into thinking this is a re-sync and therefore it must release the extra references. This results in problems, mainly having to do with slot reference numbers going smaller than zero. This patch introduces new constants, QC_SYNC and QC_CHANGE so do_qc can really tell the difference. For QC_SYNC calls it must release the extra references acquired by gfs2_quota_unlock's call to qd_check_sync. For QC_CHANGE calls it does not have extra references to put. Note that this allows quota changes back to a value of zero, and so I removed an assert warning related to that. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent d68d0c6 commit 432928c

2 files changed

Lines changed: 15 additions & 11 deletions

File tree

fs/gfs2/quota.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
#define GFS2_QD_HASH_SIZE BIT(GFS2_QD_HASH_SHIFT)
7676
#define GFS2_QD_HASH_MASK (GFS2_QD_HASH_SIZE - 1)
7777

78+
#define QC_CHANGE 0
79+
#define QC_SYNC 1
80+
7881
/* Lock order: qd_lock -> bucket lock -> qd->lockref.lock -> lru lock */
7982
/* -> sd_bitmap_lock */
8083
static DEFINE_SPINLOCK(qd_lock);
@@ -470,7 +473,6 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
470473
spin_unlock(&qd_lock);
471474

472475
if (qd) {
473-
gfs2_assert_warn(sdp, qd->qd_change_sync);
474476
error = bh_get(qd);
475477
if (error) {
476478
clear_bit(QDF_LOCKED, &qd->qd_flags);
@@ -662,7 +664,7 @@ static int sort_qd(const void *a, const void *b)
662664
return 0;
663665
}
664666

665-
static void do_qc(struct gfs2_quota_data *qd, s64 change)
667+
static void do_qc(struct gfs2_quota_data *qd, s64 change, int qc_type)
666668
{
667669
struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd;
668670
struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
@@ -687,16 +689,18 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
687689
qd->qd_change = x;
688690
spin_unlock(&qd_lock);
689691

690-
if (!x) {
692+
if (qc_type == QC_CHANGE) {
693+
if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) {
694+
qd_hold(qd);
695+
slot_hold(qd);
696+
}
697+
} else {
691698
gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags));
692699
clear_bit(QDF_CHANGE, &qd->qd_flags);
693700
qc->qc_flags = 0;
694701
qc->qc_id = 0;
695702
slot_put(qd);
696703
qd_put(qd);
697-
} else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) {
698-
qd_hold(qd);
699-
slot_hold(qd);
700704
}
701705

702706
if (change < 0) /* Reset quiet flag if we freed some blocks */
@@ -953,7 +957,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
953957
if (error)
954958
goto out_end_trans;
955959

956-
do_qc(qd, -qd->qd_change_sync);
960+
do_qc(qd, -qd->qd_change_sync, QC_SYNC);
957961
set_bit(QDF_REFRESH, &qd->qd_flags);
958962
}
959963

@@ -1279,7 +1283,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
12791283

12801284
if (qid_eq(qd->qd_id, make_kqid_uid(uid)) ||
12811285
qid_eq(qd->qd_id, make_kqid_gid(gid))) {
1282-
do_qc(qd, change);
1286+
do_qc(qd, change, QC_CHANGE);
12831287
}
12841288
}
12851289
}

fs/gfs2/util.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
9898
*/
9999
int gfs2_freeze_lock_shared(struct gfs2_sbd *sdp)
100100
{
101-
int flags = LM_FLAG_NOEXP | GL_EXACT;
102101
int error;
103102

104-
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, flags,
103+
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED,
104+
LM_FLAG_NOEXP | GL_EXACT,
105105
&sdp->sd_freeze_gh);
106-
if (error && error != GLR_TRYFAILED)
106+
if (error)
107107
fs_err(sdp, "can't lock the freeze glock: %d\n", error);
108108
return error;
109109
}

0 commit comments

Comments
 (0)