Commit d9a75a60 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent 8d89e068
...@@ -891,7 +891,8 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc, ...@@ -891,7 +891,8 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc,
return err; return err;
} }
static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda,
u64 sync_gen)
{ {
struct gfs2_sbd *sdp = (*qda)->qd_sbd; struct gfs2_sbd *sdp = (*qda)->qd_sbd;
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); 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) ...@@ -982,8 +983,13 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl, gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl,
GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_DO_SYNC); GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_DO_SYNC);
if (!error) { if (!error) {
for (x = 0; x < num_qd; x++) for (x = 0; x < num_qd; x++) {
qda[x]->qd_sync_gen = sdp->sd_quota_sync_gen; qd = qda[x];
spin_lock(&qd->qd_lockref.lock);
if (qd->qd_sync_gen < sync_gen)
qd->qd_sync_gen = sync_gen;
spin_unlock(&qd->qd_lockref.lock);
}
} }
return error; return error;
} }
...@@ -1177,7 +1183,9 @@ void gfs2_quota_unlock(struct gfs2_inode *ip) ...@@ -1177,7 +1183,9 @@ void gfs2_quota_unlock(struct gfs2_inode *ip)
} }
if (count) { if (count) {
do_sync(count, qda); u64 sync_gen = READ_ONCE(sdp->sd_quota_sync_gen);
do_sync(count, qda, sync_gen);
for (x = 0; x < count; x++) for (x = 0; x < count; x++)
qd_unlock(qda[x]); qd_unlock(qda[x]);
} }
...@@ -1323,6 +1331,7 @@ int gfs2_quota_sync(struct super_block *sb, int type) ...@@ -1323,6 +1331,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_quota_data **qda; struct gfs2_quota_data **qda;
unsigned int max_qd = PAGE_SIZE / sizeof(struct gfs2_holder); unsigned int max_qd = PAGE_SIZE / sizeof(struct gfs2_holder);
u64 sync_gen;
int error = 0; int error = 0;
if (sb_rdonly(sdp->sd_vfs)) if (sb_rdonly(sdp->sd_vfs))
...@@ -1335,7 +1344,7 @@ int gfs2_quota_sync(struct super_block *sb, int type) ...@@ -1335,7 +1344,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
return -ENOMEM; return -ENOMEM;
mutex_lock(&sdp->sd_quota_sync_mutex); mutex_lock(&sdp->sd_quota_sync_mutex);
sdp->sd_quota_sync_gen++; sync_gen = sdp->sd_quota_sync_gen + 1;
do { do {
struct gfs2_quota_data *iter; struct gfs2_quota_data *iter;
...@@ -1344,7 +1353,7 @@ int gfs2_quota_sync(struct super_block *sb, int type) ...@@ -1344,7 +1353,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
spin_lock(&qd_lock); spin_lock(&qd_lock);
list_for_each_entry(iter, &sdp->sd_quota_list, qd_list) { list_for_each_entry(iter, &sdp->sd_quota_list, qd_list) {
if (qd_grab_sync(sdp, iter, sdp->sd_quota_sync_gen)) { if (qd_grab_sync(sdp, iter, sync_gen)) {
qda[num_qd++] = iter; qda[num_qd++] = iter;
if (num_qd == max_qd) if (num_qd == max_qd)
break; break;
...@@ -1365,8 +1374,10 @@ int gfs2_quota_sync(struct super_block *sb, int type) ...@@ -1365,8 +1374,10 @@ int gfs2_quota_sync(struct super_block *sb, int type)
break; break;
} }
if (!error) if (!error) {
error = do_sync(num_qd, qda); WRITE_ONCE(sdp->sd_quota_sync_gen, sync_gen);
error = do_sync(num_qd, qda, sync_gen);
}
for (x = 0; x < num_qd; x++) for (x = 0; x < num_qd; x++)
qd_unlock(qda[x]); qd_unlock(qda[x]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment