Apparently fc->kio.ctx needs to be checked before being used. However the check should be done in a way that can avoid a race condition between kpcs_dev_ioctl() and fuse_conn_destroy() where both can run concurrently
Related to #VSTOR-102040 Signed-off-by: Liu Kui <kui....@virtuozzo.com> --- fs/fuse/inode.c | 4 +--- fs/fuse/kio/pcs/pcs_cluster.c | 4 ++++ fs/fuse/kio/pcs/pcs_cluster.h | 3 +++ fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 29 +++++++++++++++++++++++------ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index b27422d1ee38..a22e0ffb3a8f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -2221,10 +2221,8 @@ void fuse_conn_destroy(struct fuse_mount *fm) { struct fuse_conn *fc = fm->fc; - if (fc->kio.op) { /* At this point all pending kio must be completed. */ + if (fc->kio.op) /* At this point all pending kio must be completed. */ fc->kio.op->conn_fini(fm); - fc->kio.ctx = NULL; - } fuse_abort_conn(fc); fuse_wait_aborted(fc); diff --git a/fs/fuse/kio/pcs/pcs_cluster.c b/fs/fuse/kio/pcs/pcs_cluster.c index c87313b90ab3..710087c83fe6 100644 --- a/fs/fuse/kio/pcs/pcs_cluster.c +++ b/fs/fuse/kio/pcs/pcs_cluster.c @@ -603,6 +603,8 @@ int pcs_cluster_init(struct pcs_fuse_cluster *pfc, struct workqueue_struct *wq, INIT_LIST_HEAD(&pfc->list); pfc->fc = fc; + atomic_set(&pfc->refcnt, 1); + init_waitqueue_head(&pfc->waitq); /* core init */ if (pcs_cc_init(&pfc->cc, wq, info->cluster_name, &attr)) @@ -617,6 +619,8 @@ int pcs_cluster_init(struct pcs_fuse_cluster *pfc, struct workqueue_struct *wq, void pcs_cluster_fini(struct pcs_fuse_cluster *pfc) { + if (!atomic_dec_and_test(&pfc->refcnt)) + wait_event(pfc->waitq, atomic_read(&pfc->refcnt) == 0); pcs_cc_fini(&pfc->cc); kvfree(pfc); } diff --git a/fs/fuse/kio/pcs/pcs_cluster.h b/fs/fuse/kio/pcs/pcs_cluster.h index 8693d1bf38d7..914d1ad7865c 100644 --- a/fs/fuse/kio/pcs/pcs_cluster.h +++ b/fs/fuse/kio/pcs/pcs_cluster.h @@ -54,6 +54,9 @@ struct pcs_fuse_cluster { struct list_head list; struct pcs_cluster_core cc; struct fuse_conn *fc; + + atomic_t refcnt; + wait_queue_head_t waitq; }; struct pcs_fuse_work { diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c index 8da9550cc156..e3049ddaa091 100644 --- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c +++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c @@ -296,17 +296,19 @@ static int kpcs_conn_init(struct fuse_mount *fm) static void kpcs_conn_fini(struct fuse_mount *fm) { struct fuse_conn *fc = fm->fc; + struct pcs_fuse_cluster *pfc = READ_ONCE(fc->kio.ctx); - if (!fc->kio.ctx) + if (!pfc) return; - TRACE("%s fc:%p\n", __FUNCTION__, fc); - unregister_client(fc->kio.ctx); + + WRITE_ONCE(fc->kio.ctx, NULL); + unregister_client(pfc); synchronize_rcu(); flush_workqueue(pcs_wq); flush_workqueue(pcs_cpu_wq); flush_workqueue(pcs_cleanup_wq); - pcs_cluster_fini((struct pcs_fuse_cluster *) fc->kio.ctx); + pcs_cluster_fini(pfc); if (fc->ktrace) fuse_ktrace_remove(fc); @@ -1921,10 +1923,21 @@ static int kpcs_ioctl(struct file *file, struct inode *inode, unsigned int cmd, static int kpcs_dev_ioctl(struct fuse_conn *fc, unsigned int cmd, unsigned long arg, int len) { - struct pcs_fuse_cluster *pfc = fc->kio.ctx; - struct pcs_cluster_core *cc = &pfc->cc; + struct pcs_fuse_cluster *pfc; + struct pcs_cluster_core *cc; int res; + rcu_read_lock(); + pfc = READ_ONCE(fc->kio.ctx); + if (!pfc) { + rcu_read_unlock(); + return -EINVAL; + } + atomic_inc(&pfc->refcnt); + rcu_read_unlock(); + + cc = &pfc->cc; + switch (cmd) { case PCS_IOC_KRPC_CREATE: { @@ -2007,6 +2020,10 @@ static int kpcs_dev_ioctl(struct fuse_conn *fc, unsigned int cmd, unsigned long res = -ENOIOCTLCMD; break; } + + if (atomic_dec_and_test(&pfc->refcnt)) + wake_up(&pfc->waitq); + return res; } -- 2.39.5 (Apple Git-154) _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel