Skip to content

Commit d9a75a6

Browse files
author
Andreas Gruenbacher
committed
gfs2: Be more careful with the quota sync generation
The quota sync generation is only ever updated under sd_quota_sync_mutex by gfs2_quota_sync(), but its current value is fetched ouside of that mutex, so use WRITE_ONCE() and READ_ONCE() when accessing it without holding that mutex. Pass the current sync generation to do_sync() from its callers to ensure that we're not recording the wrong generation when the syncing is done. Also, make sure that qd->qd_sync_gen only ever moves forward. In gfs2_quota_sync(), only write the new sync generation when we know that there are changes. This eliminates the need for function sd_changed(), which we will remove in the next commit. Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 8d89e06 commit d9a75a6

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

fs/gfs2/quota.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,8 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc,
891891
return err;
892892
}
893893

894-
static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
894+
static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda,
895+
u64 sync_gen)
895896
{
896897
struct gfs2_sbd *sdp = (*qda)->qd_sbd;
897898
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -982,8 +983,13 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
982983
gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl,
983984
GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_DO_SYNC);
984985
if (!error) {
985-
for (x = 0; x < num_qd; x++)
986-
qda[x]->qd_sync_gen = sdp->sd_quota_sync_gen;
986+
for (x = 0; x < num_qd; x++) {
987+
qd = qda[x];
988+
spin_lock(&qd->qd_lockref.lock);
989+
if (qd->qd_sync_gen < sync_gen)
990+
qd->qd_sync_gen = sync_gen;
991+
spin_unlock(&qd->qd_lockref.lock);
992+
}
987993
}
988994
return error;
989995
}
@@ -1177,7 +1183,9 @@ void gfs2_quota_unlock(struct gfs2_inode *ip)
11771183
}
11781184

11791185
if (count) {
1180-
do_sync(count, qda);
1186+
u64 sync_gen = READ_ONCE(sdp->sd_quota_sync_gen);
1187+
1188+
do_sync(count, qda, sync_gen);
11811189
for (x = 0; x < count; x++)
11821190
qd_unlock(qda[x]);
11831191
}
@@ -1323,6 +1331,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
13231331
struct gfs2_sbd *sdp = sb->s_fs_info;
13241332
struct gfs2_quota_data **qda;
13251333
unsigned int max_qd = PAGE_SIZE / sizeof(struct gfs2_holder);
1334+
u64 sync_gen;
13261335
int error = 0;
13271336

13281337
if (sb_rdonly(sdp->sd_vfs))
@@ -1335,7 +1344,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
13351344
return -ENOMEM;
13361345

13371346
mutex_lock(&sdp->sd_quota_sync_mutex);
1338-
sdp->sd_quota_sync_gen++;
1347+
sync_gen = sdp->sd_quota_sync_gen + 1;
13391348

13401349
do {
13411350
struct gfs2_quota_data *iter;
@@ -1344,7 +1353,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
13441353

13451354
spin_lock(&qd_lock);
13461355
list_for_each_entry(iter, &sdp->sd_quota_list, qd_list) {
1347-
if (qd_grab_sync(sdp, iter, sdp->sd_quota_sync_gen)) {
1356+
if (qd_grab_sync(sdp, iter, sync_gen)) {
13481357
qda[num_qd++] = iter;
13491358
if (num_qd == max_qd)
13501359
break;
@@ -1365,8 +1374,10 @@ int gfs2_quota_sync(struct super_block *sb, int type)
13651374
break;
13661375
}
13671376

1368-
if (!error)
1369-
error = do_sync(num_qd, qda);
1377+
if (!error) {
1378+
WRITE_ONCE(sdp->sd_quota_sync_gen, sync_gen);
1379+
error = do_sync(num_qd, qda, sync_gen);
1380+
}
13701381

13711382
for (x = 0; x < num_qd; x++)
13721383
qd_unlock(qda[x]);

0 commit comments

Comments
 (0)