gfs2: Keep track of deleted inode generations in LVBs
authorAndreas Gruenbacher <agruenba@redhat.com>
Mon, 13 Jan 2020 20:21:49 +0000 (21:21 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Fri, 5 Jun 2020 18:19:20 +0000 (20:19 +0200)
When deleting an inode, keep track of the generation of the deleted inode in
the inode glock Lock Value Block (LVB).  When trying to delete an inode
remotely, check the last-known inode generation against the deleted inode
generation to skip duplicate remote deletes.  This avoids taking the resource
group glock in order to verify the block type.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/super.c
include/uapi/linux/gfs2_ondisk.h

index 86e9e621f346a3af8b6f418525d2398fc99a0410..12681616eb76b769cf8ff89ed3630864106bd4c5 100644 (file)
@@ -755,6 +755,25 @@ out_unlock:
        return;
 }
 
+void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation)
+{
+       struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
+
+       if (ri->ri_magic == 0)
+               ri->ri_magic = cpu_to_be32(GFS2_MAGIC);
+       if (ri->ri_magic == cpu_to_be32(GFS2_MAGIC))
+               ri->ri_generation_deleted = cpu_to_be64(generation);
+}
+
+bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
+{
+       struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
+
+       if (ri->ri_magic != cpu_to_be32(GFS2_MAGIC))
+               return false;
+       return generation <= be64_to_cpu(ri->ri_generation_deleted);
+}
+
 static void delete_work_func(struct work_struct *work)
 {
        struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
index b8adaf80e4c5ee2eaf4550fd5f5f97f38a5818ce..5c1b60fdedcfa3420db76940eedad739c9c61d58 100644 (file)
@@ -306,4 +306,7 @@ static inline void glock_clear_object(struct gfs2_glock *gl, void *object)
        spin_unlock(&gl->gl_lockref.lock);
 }
 
+extern void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation);
+extern bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation);
+
 #endif /* __GLOCK_DOT_H__ */
index 9e9c7a4b8c6632d8aac3886d4bd96682dcec918c..63ae9e45ce3484bd5e3f2ba626777dd9981f2dc4 100644 (file)
@@ -692,7 +692,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
        .go_lock = inode_go_lock,
        .go_dump = inode_go_dump,
        .go_type = LM_TYPE_INODE,
-       .go_flags = GLOF_ASPACE | GLOF_LRU,
+       .go_flags = GLOF_ASPACE | GLOF_LRU | GLOF_LVB,
        .go_free = inode_go_free,
 };
 
index 956fced0a8ec2c47ed5eed4fe334f38cb674a47d..e69efed9fb51b0cd0e4ba0cd5381a2e7de8c3112 100644 (file)
@@ -1315,6 +1315,8 @@ static void gfs2_evict_inode(struct inode *inode)
                goto out;
        }
 
+       if (gfs2_inode_already_deleted(ip->i_gl, ip->i_no_formal_ino))
+               goto out_truncate;
        error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
        if (error)
                goto out_truncate;
@@ -1368,6 +1370,7 @@ alloc_failed:
           that subsequent inode creates don't see an old gl_object. */
        glock_clear_object(ip->i_gl, ip);
        error = gfs2_dinode_dealloc(ip);
+       gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino);
        goto out_unlock;
 
 out_truncate:
index 2dc10a034de1adf6e489c15d31b190c0026bd56a..07e508e6691b685a1832481b779079e184688b2a 100644 (file)
@@ -171,6 +171,12 @@ struct gfs2_rindex {
 #define GFS2_RGF_NOALLOC       0x00000008
 #define GFS2_RGF_TRIMMED       0x00000010
 
+struct gfs2_inode_lvb {
+       __be32 ri_magic;
+       __be32 __pad;
+       __be64 ri_generation_deleted;
+};
+
 struct gfs2_rgrp_lvb {
        __be32 rl_magic;
        __be32 rl_flags;