ceph: switch to use cap_delay_lock for the unlink delay list
authorXiubo Li <xiubli@redhat.com>
Tue, 9 Apr 2024 00:56:03 +0000 (08:56 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 11 Apr 2024 20:56:28 +0000 (22:56 +0200)
The same list item will be used in both cap_delay_list and
cap_unlink_delay_list, so it's buggy to use two different locks
to protect them.

Cc: stable@vger.kernel.org
Fixes: dbc347ef7f0c ("ceph: add ceph_cap_unlink_work to fire check_caps() immediately")
Link: https://lists.ceph.io/hyperkitty/list/ceph-users@ceph.io/thread/AODC76VXRAMXKLFDCTK4TKFDDPWUSCN5
Reported-by: Marc Ruhmann <ruhmann@luis.uni-hannover.de>
Signed-off-by: Xiubo Li <xiubli@redhat.com>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Tested-by: Marc Ruhmann <ruhmann@luis.uni-hannover.de>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/caps.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h

index 55051ad09c19197e9b12d5d17068d20b04d6d3e6..c4941ba245ac3d0d3ae4e0f2598838b4ceb69ca9 100644 (file)
@@ -4783,13 +4783,13 @@ int ceph_drop_caps_for_unlink(struct inode *inode)
 
                        doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode,
                              ceph_vinop(inode));
-                       spin_lock(&mdsc->cap_unlink_delay_lock);
+                       spin_lock(&mdsc->cap_delay_lock);
                        ci->i_ceph_flags |= CEPH_I_FLUSH;
                        if (!list_empty(&ci->i_cap_delay_list))
                                list_del_init(&ci->i_cap_delay_list);
                        list_add_tail(&ci->i_cap_delay_list,
                                      &mdsc->cap_unlink_delay_list);
-                       spin_unlock(&mdsc->cap_unlink_delay_lock);
+                       spin_unlock(&mdsc->cap_delay_lock);
 
                        /*
                         * Fire the work immediately, because the MDS maybe
index 3ab9c268a8bb398b779cc93d3da98f3d13df8fe3..360b686c3c67cfd1f256c656642957f6ca278427 100644 (file)
@@ -2504,7 +2504,7 @@ static void ceph_cap_unlink_work(struct work_struct *work)
        struct ceph_client *cl = mdsc->fsc->client;
 
        doutc(cl, "begin\n");
-       spin_lock(&mdsc->cap_unlink_delay_lock);
+       spin_lock(&mdsc->cap_delay_lock);
        while (!list_empty(&mdsc->cap_unlink_delay_list)) {
                struct ceph_inode_info *ci;
                struct inode *inode;
@@ -2516,15 +2516,15 @@ static void ceph_cap_unlink_work(struct work_struct *work)
 
                inode = igrab(&ci->netfs.inode);
                if (inode) {
-                       spin_unlock(&mdsc->cap_unlink_delay_lock);
+                       spin_unlock(&mdsc->cap_delay_lock);
                        doutc(cl, "on %p %llx.%llx\n", inode,
                              ceph_vinop(inode));
                        ceph_check_caps(ci, CHECK_CAPS_FLUSH);
                        iput(inode);
-                       spin_lock(&mdsc->cap_unlink_delay_lock);
+                       spin_lock(&mdsc->cap_delay_lock);
                }
        }
-       spin_unlock(&mdsc->cap_unlink_delay_lock);
+       spin_unlock(&mdsc->cap_delay_lock);
        doutc(cl, "done\n");
 }
 
@@ -5404,7 +5404,6 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        INIT_LIST_HEAD(&mdsc->cap_wait_list);
        spin_lock_init(&mdsc->cap_delay_lock);
        INIT_LIST_HEAD(&mdsc->cap_unlink_delay_list);
-       spin_lock_init(&mdsc->cap_unlink_delay_lock);
        INIT_LIST_HEAD(&mdsc->snap_flush_list);
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->last_cap_flush_tid = 1;
index 03f8ff00874f727adff8b88cc8d538fc989692d8..b88e804152241281e5d1cd5ca90057d9deff9240 100644 (file)
@@ -461,9 +461,8 @@ struct ceph_mds_client {
        struct delayed_work    delayed_work;  /* delayed work */
        unsigned long    last_renew_caps;  /* last time we renewed our caps */
        struct list_head cap_delay_list;   /* caps with delayed release */
-       spinlock_t       cap_delay_lock;   /* protects cap_delay_list */
        struct list_head cap_unlink_delay_list;  /* caps with delayed release for unlink */
-       spinlock_t       cap_unlink_delay_lock;  /* protects cap_unlink_delay_list */
+       spinlock_t       cap_delay_lock;   /* protects cap_delay_list and cap_unlink_delay_list */
        struct list_head snap_flush_list;  /* cap_snaps ready to flush */
        spinlock_t       snap_flush_lock;