]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gfs2: Fix unlinked inode cleanup
authorAndreas Gruenbacher <agruenba@redhat.com>
Mon, 26 Aug 2024 18:06:21 +0000 (20:06 +0200)
committerAndreas Gruenbacher <agruenba@redhat.com>
Wed, 25 Sep 2024 15:11:49 +0000 (17:11 +0200)
Before commit f0e56edc2ec7 ("gfs2: Split the two kinds of glock "delete"
work"), function delete_work_func() was used to trigger the eviction of
in-memory inodes from remote as well as deleting unlinked inodes at a
later point.  These two kinds of work were then split into two kinds of
work, and the two places in the code were deferred deletion of inodes is
required accidentally ended up queuing the wrong kind of work.  This
caused unlinked inodes to be left behind, which could in the worst case
fill up filesystems and require a filesystem check to recover.

Fix that by queuing the right kind of work in try_rgrp_unlink() and
gfs2_drop_inode().

Fixes: f0e56edc2ec7 ("gfs2: Split the two kinds of glock "delete" work")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/rgrp.c
fs/gfs2/super.c

index 7119037a866c51cfef244eddb32d8476064ab5e8..9273ec5345eda7c2ff5d0962c9ca9c8e8fd18a66 100644 (file)
@@ -1012,7 +1012,7 @@ bool gfs2_queue_try_to_evict(struct gfs2_glock *gl)
                                  &gl->gl_delete, 0);
 }
 
-static bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later)
+bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later)
 {
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
        unsigned long delay;
index adf0091cc98f9571533ffde410bf1a2d83763b30..63e101d448e961b0c3944b29054cdf4123bb1c40 100644 (file)
@@ -245,6 +245,7 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
 void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state);
 void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
 bool gfs2_queue_try_to_evict(struct gfs2_glock *gl);
+bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later);
 void gfs2_cancel_delete_work(struct gfs2_glock *gl);
 void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
 void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
index 29c772816765266b420b24e9903424c96e3ed0ce..53930312971530014e383a886fd5ffa8a6580b5d 100644 (file)
@@ -1879,7 +1879,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
                 */
                ip = gl->gl_object;
 
-               if (ip || !gfs2_queue_try_to_evict(gl))
+               if (ip || !gfs2_queue_verify_delete(gl, false))
                        gfs2_glock_put(gl);
                else
                        found++;
index 6678060ed4d2bba850beb8b876bd1c7d728717a2..e22c1edc32b39e767b9ebc3bbc1755969b7c3d02 100644 (file)
@@ -1045,7 +1045,7 @@ static int gfs2_drop_inode(struct inode *inode)
                struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
 
                gfs2_glock_hold(gl);
-               if (!gfs2_queue_try_to_evict(gl))
+               if (!gfs2_queue_verify_delete(gl, true))
                        gfs2_glock_put_async(gl);
                return 0;
        }