]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ceph: flush all caps releases when syncing the whole filesystem
authorXiubo Li <xiubli@redhat.com>
Mon, 29 Jul 2024 08:04:11 +0000 (16:04 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Tue, 24 Sep 2024 20:51:28 +0000 (22:51 +0200)
We have hit a race between cap releases and cap revoke request
that will cause the check_caps() to miss sending a cap revoke ack
to MDS. And the client will depend on the cap release to release
that revoking caps, which could be delayed for some unknown reasons.

In Kclient we have figured out the RCA about race and we need
a way to explictly trigger this manually could help to get rid
of the caps revoke stuck issue.

Link: https://tracker.ceph.com/issues/67221
Signed-off-by: Xiubo Li <xiubli@redhat.com>
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/caps.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/super.h

index 888bf9a290a83f1d323e9132839e33e6eefa0e2c..329516b1eaffeebf9e075e5bf53187ab4a5af591 100644 (file)
@@ -4702,6 +4702,28 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
        ceph_mdsc_iterate_sessions(mdsc, flush_dirty_session_caps, true);
 }
 
+/*
+ * Flush all cap releases to the mds
+ */
+static void flush_cap_releases(struct ceph_mds_session *s)
+{
+       struct ceph_mds_client *mdsc = s->s_mdsc;
+       struct ceph_client *cl = mdsc->fsc->client;
+
+       doutc(cl, "begin\n");
+       spin_lock(&s->s_cap_lock);
+       if (s->s_num_cap_releases)
+               ceph_flush_session_cap_releases(mdsc, s);
+       spin_unlock(&s->s_cap_lock);
+       doutc(cl, "done\n");
+
+}
+
+void ceph_flush_cap_releases(struct ceph_mds_client *mdsc)
+{
+       ceph_mdsc_iterate_sessions(mdsc, flush_cap_releases, true);
+}
+
 void __ceph_touch_fmode(struct ceph_inode_info *ci,
                        struct ceph_mds_client *mdsc, int fmode)
 {
index 36c5886b5aac06d9d8c16473f77eb220c759a327..9682c6ae38662effaaae382b796e05a00470024d 100644 (file)
@@ -5877,6 +5877,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
        mutex_unlock(&mdsc->mutex);
 
        ceph_flush_dirty_caps(mdsc);
+       ceph_flush_cap_releases(mdsc);
        spin_lock(&mdsc->cap_dirty_lock);
        want_flush = mdsc->last_cap_flush_tid;
        if (!list_empty(&mdsc->cap_flush_list)) {
index 0cdf84cd179128d118c7e9a0d34287c27859698d..73f321b52895ea8b06717835f627db4dde0e2782 100644 (file)
@@ -126,6 +126,7 @@ static int ceph_sync_fs(struct super_block *sb, int wait)
        if (!wait) {
                doutc(cl, "(non-blocking)\n");
                ceph_flush_dirty_caps(fsc->mdsc);
+               ceph_flush_cap_releases(fsc->mdsc);
                doutc(cl, "(non-blocking) done\n");
                return 0;
        }
index c88bf53f68e9f876658399d1fe388555ffc59f99..0020746622fd00b90fbcb10ea63204d4e3a6cc74 100644 (file)
@@ -1268,6 +1268,7 @@ extern bool __ceph_should_report_size(struct ceph_inode_info *ci);
 extern void ceph_check_caps(struct ceph_inode_info *ci, int flags);
 extern unsigned long ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
 extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);
+extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc);
 extern int  ceph_drop_caps_for_unlink(struct inode *inode);
 extern int ceph_encode_inode_release(void **p, struct inode *inode,
                                     int mds, int drop, int unless, int force);