Commit 17f8dc2d authored by Xiubo Li's avatar Xiubo Li Committed by Ilya Dryomov
Browse files

ceph: switch to use cap_delay_lock for the unlink delay list

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: dbc347ef ("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: default avatarMarc Ruhmann <ruhmann@luis.uni-hannover.de>
Signed-off-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-by: default avatarIlya Dryomov <idryomov@gmail.com>
Tested-by: default avatarMarc Ruhmann <ruhmann@luis.uni-hannover.de>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent b372e96b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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
+4 −5
Original line number Diff line number Diff line
@@ -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;
+1 −2
Original line number Diff line number Diff line
@@ -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;