Merge tag 'gfs2-v6.0-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Oct 2022 03:08:52 +0000 (20:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Oct 2022 03:08:52 +0000 (20:08 -0700)
Pull gfs2 updates from Andreas Gruenbacher:

 - Make sure to initialize the filesystem work queues before registering
   the filesystem; this prevents them from being used uninitialized.

 - On filesystem withdraw: prevent a a double iput() and immediately
   reject pending locking requests that can no longer succeed.

 - Use TRY lock in gfs2_inode_lookup() to prevent a rare glock hang
   during evict.

 - During filesystem mount, explicitly make sure that the sb_bsize and
   sb_bsize_shift super block fields are consistent with each other.
   This prevents messy error messages during fuzz testing.

 - Switch from strlcpy to strscpy.

* tag 'gfs2-v6.0-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Register fs after creating workqueues
  gfs2: Check sb_bsize_shift after reading superblock
  gfs2: Switch from strlcpy to strscpy
  gfs2: Clear flags when withdraw prevents xmote
  gfs2: Dequeue waiters when withdrawn
  gfs2: Prevent double iput for journal on error
  gfs2: Use TRY lock in gfs2_inode_lookup for UNLINKED inodes

fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/inode.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/util.c

index 41b6c89e4bf7dfd39dbe26a15a3bc119e4d38e1b..dca2cbf0338c856160244408d281cff59d72ab66 100644 (file)
@@ -59,6 +59,8 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl);
 
 static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int target);
 static void __gfs2_glock_dq(struct gfs2_holder *gh);
+static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+                           unsigned long delay, bool remote);
 
 static struct dentry *gfs2_root;
 static struct workqueue_struct *glock_workqueue;
@@ -730,7 +732,8 @@ static bool is_system_glock(struct gfs2_glock *gl)
  *
  */
 
-static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int target)
+static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh,
+                                        unsigned int target)
 __releases(&gl->gl_lockref.lock)
 __acquires(&gl->gl_lockref.lock)
 {
@@ -741,7 +744,8 @@ __acquires(&gl->gl_lockref.lock)
 
        if (target != LM_ST_UNLOCKED && glock_blocked_by_withdraw(gl) &&
            gh && !(gh->gh_flags & LM_FLAG_NOEXP))
-               return;
+               goto skip_inval;
+
        lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP |
                      LM_FLAG_PRIORITY);
        GLOCK_BUG_ON(gl, gl->gl_state == target);
@@ -826,6 +830,20 @@ skip_inval:
            (target != LM_ST_UNLOCKED ||
             test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags))) {
                if (!is_system_glock(gl)) {
+                       handle_callback(gl, LM_ST_UNLOCKED, 0, false); /* sets demote */
+                       /*
+                        * Ordinarily, we would call dlm and its callback would call
+                        * finish_xmote, which would call state_change() to the new state.
+                        * Since we withdrew, we won't call dlm, so call state_change
+                        * manually, but to the UNLOCKED state we desire.
+                        */
+                       state_change(gl, LM_ST_UNLOCKED);
+                       /*
+                        * We skip telling dlm to do the locking, so we won't get a
+                        * reply that would otherwise clear GLF_LOCK. So we clear it here.
+                        */
+                       clear_bit(GLF_LOCK, &gl->gl_flags);
+                       clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
                        gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
                        goto out;
                } else {
@@ -1018,16 +1036,18 @@ static void delete_work_func(struct work_struct *work)
                        if (gfs2_queue_delete_work(gl, 5 * HZ))
                                return;
                }
-               goto out;
        }
 
        inode = gfs2_lookup_by_inum(sdp, no_addr, gl->gl_no_formal_ino,
                                    GFS2_BLKST_UNLINKED);
-       if (!IS_ERR_OR_NULL(inode)) {
+       if (IS_ERR(inode)) {
+               if (PTR_ERR(inode) == -EAGAIN &&
+                       (gfs2_queue_delete_work(gl, 5 * HZ)))
+                               return;
+       } else {
                d_prune_aliases(inode);
                iput(inode);
        }
-out:
        gfs2_glock_put(gl);
 }
 
@@ -2194,6 +2214,20 @@ static void dump_glock_func(struct gfs2_glock *gl)
        dump_glock(NULL, gl, true);
 }
 
+static void withdraw_dq(struct gfs2_glock *gl)
+{
+       spin_lock(&gl->gl_lockref.lock);
+       if (!__lockref_is_dead(&gl->gl_lockref) &&
+           glock_blocked_by_withdraw(gl))
+               do_error(gl, LM_OUT_ERROR); /* remove pending waiters */
+       spin_unlock(&gl->gl_lockref.lock);
+}
+
+void gfs2_gl_dq_holders(struct gfs2_sbd *sdp)
+{
+       glock_hash_walk(withdraw_dq, sdp);
+}
+
 /**
  * gfs2_gl_hash_clear - Empty out the glock hash table
  * @sdp: the filesystem
index 5aed8b500cf5ab88015b394d26a147afb1e17dc9..0199a3dcb11406f56611c9ca56c9ab46f15ff749 100644 (file)
@@ -274,6 +274,7 @@ extern void gfs2_cancel_delete_work(struct gfs2_glock *gl);
 extern bool gfs2_delete_work_queued(const struct gfs2_glock *gl);
 extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
 extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
+extern void gfs2_gl_dq_holders(struct gfs2_sbd *sdp);
 extern void gfs2_glock_thaw(struct gfs2_sbd *sdp);
 extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
 extern void gfs2_glock_free(struct gfs2_glock *gl);
index c8ec876f33ea35787d05d2d69c81ca91854ab685..56ded979988cac324a8a17e2ee06755bc327cee5 100644 (file)
@@ -130,6 +130,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
        if (inode->i_state & I_NEW) {
                struct gfs2_sbd *sdp = GFS2_SB(inode);
                struct gfs2_glock *io_gl;
+               int extra_flags = 0;
 
                error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE,
                                       &ip->i_gl);
@@ -141,9 +142,12 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
                if (unlikely(error))
                        goto fail;
 
-               if (blktype != GFS2_BLKST_UNLINKED)
+               if (blktype == GFS2_BLKST_UNLINKED)
+                       extra_flags |= LM_FLAG_TRY;
+               else
                        gfs2_cancel_delete_work(io_gl);
-               error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT,
+               error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED,
+                                          GL_EXACT | extra_flags,
                                           &ip->i_iopen_gh);
                gfs2_glock_put(io_gl);
                if (unlikely(error))
@@ -210,6 +214,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
        return inode;
 
 fail:
+       if (error == GLR_TRYFAILED)
+               error = -EAGAIN;
        if (gfs2_holder_initialized(&ip->i_iopen_gh))
                gfs2_glock_dq_uninit(&ip->i_iopen_gh);
        if (gfs2_holder_initialized(&i_gh))
index 14ae9de7627726d515f2419a82dc4e109cd49689..afcb32854f14224f1a07d977faa6c8202baeb38f 100644 (file)
@@ -151,14 +151,6 @@ static int __init init_gfs2_fs(void)
        if (error)
                goto fail_shrinker;
 
-       error = register_filesystem(&gfs2_fs_type);
-       if (error)
-               goto fail_fs1;
-
-       error = register_filesystem(&gfs2meta_fs_type);
-       if (error)
-               goto fail_fs2;
-
        error = -ENOMEM;
        gfs_recovery_wq = alloc_workqueue("gfs_recovery",
                                          WQ_MEM_RECLAIM | WQ_FREEZABLE, 0);
@@ -180,11 +172,23 @@ static int __init init_gfs2_fs(void)
                goto fail_mempool;
 
        gfs2_register_debugfs();
+       error = register_filesystem(&gfs2_fs_type);
+       if (error)
+               goto fail_fs1;
+
+       error = register_filesystem(&gfs2meta_fs_type);
+       if (error)
+               goto fail_fs2;
+
 
        pr_info("GFS2 installed\n");
 
        return 0;
 
+fail_fs2:
+       unregister_filesystem(&gfs2_fs_type);
+fail_fs1:
+       mempool_destroy(gfs2_page_pool);
 fail_mempool:
        destroy_workqueue(gfs2_freeze_wq);
 fail_wq3:
@@ -192,10 +196,6 @@ fail_wq3:
 fail_wq2:
        destroy_workqueue(gfs_recovery_wq);
 fail_wq1:
-       unregister_filesystem(&gfs2meta_fs_type);
-fail_fs2:
-       unregister_filesystem(&gfs2_fs_type);
-fail_fs1:
        unregister_shrinker(&gfs2_qd_shrinker);
 fail_shrinker:
        kmem_cache_destroy(gfs2_trans_cachep);
index 549879929c847c143905d03bfac6bbc1b9564f4b..c7e2e623836685d73587a7352a04681151b54405 100644 (file)
@@ -178,7 +178,10 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent)
                pr_warn("Invalid block size\n");
                return -EINVAL;
        }
-
+       if (sb->sb_bsize_shift != ffs(sb->sb_bsize) - 1) {
+               pr_warn("Invalid block size shift\n");
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -381,8 +384,10 @@ static int init_names(struct gfs2_sbd *sdp, int silent)
        if (!table[0])
                table = sdp->sd_vfs->s_id;
 
-       strlcpy(sdp->sd_proto_name, proto, GFS2_FSNAME_LEN);
-       strlcpy(sdp->sd_table_name, table, GFS2_FSNAME_LEN);
+       BUILD_BUG_ON(GFS2_LOCKNAME_LEN > GFS2_FSNAME_LEN);
+
+       strscpy(sdp->sd_proto_name, proto, GFS2_LOCKNAME_LEN);
+       strscpy(sdp->sd_table_name, table, GFS2_LOCKNAME_LEN);
 
        table = sdp->sd_table_name;
        while ((table = strchr(table, '/')))
@@ -1439,13 +1444,13 @@ static int gfs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 
        switch (o) {
        case Opt_lockproto:
-               strlcpy(args->ar_lockproto, param->string, GFS2_LOCKNAME_LEN);
+               strscpy(args->ar_lockproto, param->string, GFS2_LOCKNAME_LEN);
                break;
        case Opt_locktable:
-               strlcpy(args->ar_locktable, param->string, GFS2_LOCKNAME_LEN);
+               strscpy(args->ar_locktable, param->string, GFS2_LOCKNAME_LEN);
                break;
        case Opt_hostdata:
-               strlcpy(args->ar_hostdata, param->string, GFS2_LOCKNAME_LEN);
+               strscpy(args->ar_hostdata, param->string, GFS2_LOCKNAME_LEN);
                break;
        case Opt_spectator:
                args->ar_spectator = 1;
index 8241029a2a5d25a18239171bafa11edfb4982ff4..88185a341504007c6d045d561023708c9de4c35a 100644 (file)
@@ -164,6 +164,11 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
                }
                if (!ret)
                        gfs2_make_fs_ro(sdp);
+               /*
+                * Dequeue any pending non-system glock holders that can no
+                * longer be granted because the file system is withdrawn.
+                */
+               gfs2_gl_dq_holders(sdp);
                gfs2_freeze_unlock(&freeze_gh);
        }
 
@@ -204,6 +209,7 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
         * exception code in glock_dq.
         */
        iput(inode);
+       sdp->sd_jdesc->jd_inode = NULL;
        /*
         * Wait until the journal inode's glock is freed. This allows try locks
         * on other nodes to be successful, otherwise we remain the owner of