]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gfs2: Be more careful with the quota sync generation
authorAndreas Gruenbacher <agruenba@redhat.com>
Fri, 7 Jun 2024 13:54:21 +0000 (15:54 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Thu, 20 Jun 2024 14:38:15 +0000 (16:38 +0200)
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 <agruenba@redhat.com>
fs/gfs2/quota.c

index 931a133a5f9697a2d32458b0053e9dfa5498d182..4f2caa06ca9327f382767bf6a55e5a920bd707ed 100644 (file)
@@ -891,7 +891,8 @@ static int gfs2_adjust_quota(struct gfs2_sbd *sdp, loff_t loc,
        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_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -982,8 +983,13 @@ out_dq:
        gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl,
                       GFS2_LOG_HEAD_FLUSH_NORMAL | GFS2_LFC_DO_SYNC);
        if (!error) {
-               for (x = 0; x < num_qd; x++)
-                       qda[x]->qd_sync_gen = sdp->sd_quota_sync_gen;
+               for (x = 0; x < num_qd; x++) {
+                       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;
 }
@@ -1177,7 +1183,9 @@ void gfs2_quota_unlock(struct gfs2_inode *ip)
        }
 
        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++)
                        qd_unlock(qda[x]);
        }
@@ -1323,6 +1331,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_quota_data **qda;
        unsigned int max_qd = PAGE_SIZE / sizeof(struct gfs2_holder);
+       u64 sync_gen;
        int error = 0;
 
        if (sb_rdonly(sdp->sd_vfs))
@@ -1335,7 +1344,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
                return -ENOMEM;
 
        mutex_lock(&sdp->sd_quota_sync_mutex);
-       sdp->sd_quota_sync_gen++;
+       sync_gen = sdp->sd_quota_sync_gen + 1;
 
        do {
                struct gfs2_quota_data *iter;
@@ -1344,7 +1353,7 @@ int gfs2_quota_sync(struct super_block *sb, int type)
 
                spin_lock(&qd_lock);
                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;
                                if (num_qd == max_qd)
                                        break;
@@ -1365,8 +1374,10 @@ int gfs2_quota_sync(struct super_block *sb, int type)
                        break;
                }
 
-               if (!error)
-                       error = do_sync(num_qd, qda);
+               if (!error) {
+                       WRITE_ONCE(sdp->sd_quota_sync_gen, sync_gen);
+                       error = do_sync(num_qd, qda, sync_gen);
+               }
 
                for (x = 0; x < num_qd; x++)
                        qd_unlock(qda[x]);