Skip to content

Commit d5563f4

Browse files
author
Andreas Gruenbacher
committed
gfs2: Add some missing quota locking
The quota code is missing some locking between local quota changes and syncing those quota changes to the global quota file (gfs2_quota_sync); in particular, qd->qd_change needs to be kept in sync with the QDF_CHANGE change flag and the number of references held. Use the qd->qd_lockref.lock spinlock for that. With the qd->qd_lockref.lock spinlock held, we can no longer call lockref_get(), so turn qd_hold() into a variant that assumes that the lock is held. This function is really supposed to take an additional reference when one or more references are already held, so check for that instead of checking if the lockref is dead. Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 614abc1 commit d5563f4

File tree

1 file changed

+53
-29
lines changed

1 file changed

+53
-29
lines changed

fs/gfs2/quota.c

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -316,11 +316,11 @@ static int qd_get(struct gfs2_sbd *sdp, struct kqid qid,
316316
}
317317

318318

319-
static void qd_hold(struct gfs2_quota_data *qd)
319+
static void __qd_hold(struct gfs2_quota_data *qd)
320320
{
321321
struct gfs2_sbd *sdp = qd->qd_sbd;
322-
gfs2_assert(sdp, !__lockref_is_dead(&qd->qd_lockref));
323-
lockref_get(&qd->qd_lockref);
322+
gfs2_assert(sdp, qd->qd_lockref.count > 0);
323+
qd->qd_lockref.count++;
324324
}
325325

326326
static void qd_put(struct gfs2_quota_data *qd)
@@ -462,19 +462,27 @@ static void bh_put(struct gfs2_quota_data *qd)
462462
static bool qd_grab_sync(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd,
463463
u64 sync_gen)
464464
{
465+
bool ret = false;
466+
467+
spin_lock(&qd->qd_lockref.lock);
465468
if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
466469
!test_bit(QDF_CHANGE, &qd->qd_flags) ||
467470
qd->qd_sync_gen >= sync_gen)
468-
return false;
471+
goto out;
469472

470-
if (!lockref_get_not_dead(&qd->qd_lockref))
471-
return false;
473+
if (__lockref_is_dead(&qd->qd_lockref))
474+
goto out;
475+
qd->qd_lockref.count++;
472476

473477
list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
474478
set_bit(QDF_LOCKED, &qd->qd_flags);
475479
qd->qd_change_sync = qd->qd_change;
476480
slot_hold(qd);
477-
return true;
481+
ret = true;
482+
483+
out:
484+
spin_unlock(&qd->qd_lockref.lock);
485+
return ret;
478486
}
479487

480488
static void qd_ungrab_sync(struct gfs2_quota_data *qd)
@@ -493,8 +501,10 @@ static void qdsb_put(struct gfs2_quota_data *qd)
493501

494502
static void qd_unlock(struct gfs2_quota_data *qd)
495503
{
504+
spin_lock(&qd->qd_lockref.lock);
496505
gfs2_assert_warn(qd->qd_sbd, test_bit(QDF_LOCKED, &qd->qd_flags));
497506
clear_bit(QDF_LOCKED, &qd->qd_flags);
507+
spin_unlock(&qd->qd_lockref.lock);
498508
qdsb_put(qd);
499509
}
500510

@@ -663,6 +673,7 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
663673
struct gfs2_sbd *sdp = qd->qd_sbd;
664674
struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
665675
struct gfs2_quota_change *qc = qd->qd_bh_qc;
676+
bool needs_put = false;
666677
s64 x;
667678

668679
mutex_lock(&sdp->sd_quota_mutex);
@@ -674,26 +685,24 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
674685
* used, and we assume a value of 0 otherwise.
675686
*/
676687

688+
spin_lock(&qd->qd_lockref.lock);
689+
677690
x = 0;
678691
if (test_bit(QDF_CHANGE, &qd->qd_flags))
679692
x = be64_to_cpu(qc->qc_change);
680693
x += change;
681-
682-
spin_lock(&qd_lock);
683694
qd->qd_change += change;
684-
spin_unlock(&qd_lock);
685695

686696
if (!x && test_bit(QDF_CHANGE, &qd->qd_flags)) {
687697
/* The slot in the quota change file becomes unused. */
688698
clear_bit(QDF_CHANGE, &qd->qd_flags);
689699
qc->qc_flags = 0;
690700
qc->qc_id = 0;
691-
slot_put(qd);
692-
qd_put(qd);
701+
needs_put = true;
693702
} else if (x && !test_bit(QDF_CHANGE, &qd->qd_flags)) {
694703
/* The slot in the quota change file becomes used. */
695704
set_bit(QDF_CHANGE, &qd->qd_flags);
696-
qd_hold(qd);
705+
__qd_hold(qd);
697706
slot_hold(qd);
698707

699708
qc->qc_flags = 0;
@@ -703,6 +712,12 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
703712
}
704713
qc->qc_change = cpu_to_be64(x);
705714

715+
spin_unlock(&qd->qd_lockref.lock);
716+
717+
if (needs_put) {
718+
slot_put(qd);
719+
qd_put(qd);
720+
}
706721
if (change < 0) /* Reset quiet flag if we freed some blocks */
707722
clear_bit(QDF_QMSG_QUIET, &qd->qd_flags);
708723
mutex_unlock(&sdp->sd_quota_mutex);
@@ -844,6 +859,7 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc,
844859
be64_add_cpu(&q.qu_value, change);
845860
if (((s64)be64_to_cpu(q.qu_value)) < 0)
846861
q.qu_value = 0; /* Never go negative on quota usage */
862+
spin_lock(&qd->qd_lockref.lock);
847863
qd->qd_qb.qb_value = q.qu_value;
848864
if (fdq) {
849865
if (fdq->d_fieldmask & QC_SPC_SOFT) {
@@ -859,6 +875,7 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc,
859875
qd->qd_qb.qb_value = q.qu_value;
860876
}
861877
}
878+
spin_unlock(&qd->qd_lockref.lock);
862879

863880
err = gfs2_write_disk_quota(sdp, &q, loc);
864881
if (!err) {
@@ -990,7 +1007,9 @@ static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd)
9901007
qlvb->qb_limit = q.qu_limit;
9911008
qlvb->qb_warn = q.qu_warn;
9921009
qlvb->qb_value = q.qu_value;
1010+
spin_lock(&qd->qd_lockref.lock);
9931011
qd->qd_qb = *qlvb;
1012+
spin_unlock(&qd->qd_lockref.lock);
9941013

9951014
return 0;
9961015
}
@@ -1012,7 +1031,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
10121031
if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags))
10131032
force_refresh = FORCE;
10141033

1034+
spin_lock(&qd->qd_lockref.lock);
10151035
qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
1036+
spin_unlock(&qd->qd_lockref.lock);
10161037

10171038
if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
10181039
gfs2_glock_dq_uninit(q_gh);
@@ -1085,20 +1106,19 @@ static bool need_sync(struct gfs2_quota_data *qd)
10851106
struct gfs2_tune *gt = &sdp->sd_tune;
10861107
s64 value, change, limit;
10871108
unsigned int num, den;
1109+
int ret = false;
10881110

1111+
spin_lock(&qd->qd_lockref.lock);
10891112
if (!qd->qd_qb.qb_limit)
1090-
return false;
1113+
goto out;
10911114

1092-
spin_lock(&qd_lock);
10931115
change = qd->qd_change;
1094-
spin_unlock(&qd_lock);
1095-
10961116
if (change <= 0)
1097-
return false;
1117+
goto out;
10981118
value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
10991119
limit = (s64)be64_to_cpu(qd->qd_qb.qb_limit);
11001120
if (value >= limit)
1101-
return false;
1121+
goto out;
11021122

11031123
spin_lock(&gt->gt_spin);
11041124
num = gt->gt_quota_scale_num;
@@ -1108,8 +1128,12 @@ static bool need_sync(struct gfs2_quota_data *qd)
11081128
change *= gfs2_jindex_size(sdp) * num;
11091129
change = div_s64(change, den);
11101130
if (value + change < limit)
1111-
return false;
1112-
return true;
1131+
goto out;
1132+
1133+
ret = true;
1134+
out:
1135+
spin_unlock(&qd->qd_lockref.lock);
1136+
return ret;
11131137
}
11141138

11151139
void gfs2_quota_unlock(struct gfs2_inode *ip)
@@ -1211,12 +1235,12 @@ int gfs2_quota_check(struct gfs2_inode *ip, kuid_t uid, kgid_t gid,
12111235
qid_eq(qd->qd_id, make_kqid_gid(gid))))
12121236
continue;
12131237

1238+
spin_lock(&qd->qd_lockref.lock);
12141239
warn = (s64)be64_to_cpu(qd->qd_qb.qb_warn);
12151240
limit = (s64)be64_to_cpu(qd->qd_qb.qb_limit);
12161241
value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
1217-
spin_lock(&qd_lock);
12181242
value += qd->qd_change;
1219-
spin_unlock(&qd_lock);
1243+
spin_unlock(&qd->qd_lockref.lock);
12201244

12211245
if (limit > 0 && (limit - value) < ap->allowed)
12221246
ap->allowed = limit - value;
@@ -1282,12 +1306,12 @@ static bool qd_changed(struct gfs2_sbd *sdp)
12821306

12831307
spin_lock(&qd_lock);
12841308
list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
1285-
if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
1286-
!test_bit(QDF_CHANGE, &qd->qd_flags))
1287-
continue;
1288-
1289-
changed = true;
1290-
break;
1309+
spin_lock(&qd->qd_lockref.lock);
1310+
changed = !test_bit(QDF_LOCKED, &qd->qd_flags) &&
1311+
test_bit(QDF_CHANGE, &qd->qd_flags);
1312+
spin_unlock(&qd->qd_lockref.lock);
1313+
if (changed)
1314+
break;
12911315
}
12921316
spin_unlock(&qd_lock);
12931317
return changed;

0 commit comments

Comments
 (0)