Commit adc52461 authored by Xiubo Li's avatar Xiubo Li Committed by Ilya Dryomov

ceph: flush all caps releases when syncing the whole filesystem

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/67221Signed-off-by: default avatarXiubo Li <xiubli@redhat.com>
Reviewed-by: default avatarIlya Dryomov <idryomov@gmail.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent c085f6ca
...@@ -4702,6 +4702,28 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc) ...@@ -4702,6 +4702,28 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
ceph_mdsc_iterate_sessions(mdsc, flush_dirty_session_caps, true); 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, void __ceph_touch_fmode(struct ceph_inode_info *ci,
struct ceph_mds_client *mdsc, int fmode) struct ceph_mds_client *mdsc, int fmode)
{ {
......
...@@ -5877,6 +5877,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) ...@@ -5877,6 +5877,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
mutex_unlock(&mdsc->mutex); mutex_unlock(&mdsc->mutex);
ceph_flush_dirty_caps(mdsc); ceph_flush_dirty_caps(mdsc);
ceph_flush_cap_releases(mdsc);
spin_lock(&mdsc->cap_dirty_lock); spin_lock(&mdsc->cap_dirty_lock);
want_flush = mdsc->last_cap_flush_tid; want_flush = mdsc->last_cap_flush_tid;
if (!list_empty(&mdsc->cap_flush_list)) { if (!list_empty(&mdsc->cap_flush_list)) {
......
...@@ -126,6 +126,7 @@ static int ceph_sync_fs(struct super_block *sb, int wait) ...@@ -126,6 +126,7 @@ static int ceph_sync_fs(struct super_block *sb, int wait)
if (!wait) { if (!wait) {
doutc(cl, "(non-blocking)\n"); doutc(cl, "(non-blocking)\n");
ceph_flush_dirty_caps(fsc->mdsc); ceph_flush_dirty_caps(fsc->mdsc);
ceph_flush_cap_releases(fsc->mdsc);
doutc(cl, "(non-blocking) done\n"); doutc(cl, "(non-blocking) done\n");
return 0; return 0;
} }
......
...@@ -1268,6 +1268,7 @@ extern bool __ceph_should_report_size(struct ceph_inode_info *ci); ...@@ -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 void ceph_check_caps(struct ceph_inode_info *ci, int flags);
extern unsigned long ceph_check_delayed_caps(struct ceph_mds_client *mdsc); 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_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_drop_caps_for_unlink(struct inode *inode);
extern int ceph_encode_inode_release(void **p, struct inode *inode, extern int ceph_encode_inode_release(void **p, struct inode *inode,
int mds, int drop, int unless, int force); int mds, int drop, int unless, int force);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment