The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git after rh7-3.10.0-862.14.4.vz7.72.9 ------> commit 455a8eaf76f3c0b844e24d50d5ab3111dd7b0cd9 Author: Kirill Tkhai <ktk...@virtuozzo.com> Date: Tue Oct 16 18:09:43 2018 +0300
fuse kio: Hold pcs_rpc counter till sio may be freed Socket callbacks dereference sio->parent, so pcs_rps mustn't be destroyed before RCU grace period end. Thus, the patch makes the counter be put in sio_destroy_rcu(). Also, rework waiting for all pcs_rps are destroyed in pcs_rpc_engine_fini() (wait for ep->eng->nrpcs == 0). Note, that flush_delayed_work(&ep->eng->stat_work) is removed from pcs_rpc_destroy() to use nrpcs as such the identifier (now it's not allowed to touch ep->eng after nrpcs == 0 since pcs_rpc_engine_fini() waits only this, and umount code may already free eng). We don't want introduce counter for eng instead of this, since this will be overkill. Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> Reviewed-by: Pavel Butsykin <pbutsy...@virtuozzo.com> ===================== Patchset description: Order pcs_rpc and pcs_sockio destruction and close leaked socket https://pmc.acronis.com/browse/VSTOR-15305 Ploop can asynchronously unmap regions by sending IOCB_CMD_UNMAP_ITER, but this command isn't quite correctly interpreted in Fuse. Moreover, in Fast-path mode, fallocate(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_ZERO_RANGE) falls to fuse user daemon and it can lead to data corruption. Let's fix it. Kirill Tkhai (9): fuse kio: Use __maybe_unused fuse kio: Use sio eof instead of parent to determ abort fuse kio: Reorder callback assignment fuse kio: Add pcs_cleanup_wq fuse kio: Destroy rpc in work func fuse kio: Introduce pcs_sk_kick_queue() fuse kio: Dereference sk_user_data under rcu fuse kio: Fix rpc socket leak on rpc_abort() fuse kio: Hold pcs_rpc counter till sio may be freed --- fs/fuse/kio/pcs/pcs_rpc.c | 29 ++++++++++++++--------------- fs/fuse/kio/pcs/pcs_sock_io.c | 2 ++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/fs/fuse/kio/pcs/pcs_rpc.c b/fs/fuse/kio/pcs/pcs_rpc.c index 7571523fe271..7ef69a842ce8 100644 --- a/fs/fuse/kio/pcs/pcs_rpc.c +++ b/fs/fuse/kio/pcs/pcs_rpc.c @@ -38,6 +38,8 @@ static unsigned long rpc_cpu_time_slice = PCS_RPC_CPU_SLICE; module_param(rpc_cpu_time_slice, ulong, 0644); MODULE_PARM_DESC(rpc_cpu_time_slice, "Time slice for RPC rebinding"); +DECLARE_WAIT_QUEUE_HEAD(pcs_waitq); + static void timer_work(struct work_struct *w); static int rpc_gc_classify(struct pcs_rpc * ep); @@ -300,7 +302,7 @@ void pcs_rpc_attach_new_ep(struct pcs_rpc * ep, struct pcs_rpc_engine * eng) static void pcs_rpc_destroy(struct pcs_rpc *ep) { - bool flush; + bool last_ep; BUG_ON(ep->state != PCS_RPC_DESTROY); BUG_ON(ep->flags & PCS_RPC_F_HASHED); BUG_ON(!(ep->flags & PCS_RPC_F_DEAD)); @@ -309,6 +311,8 @@ static void pcs_rpc_destroy(struct pcs_rpc *ep) BUG_ON(!list_empty(&ep->pending_queue)); BUG_ON(timer_pending(&ep->timer_work.timer)); + cancel_delayed_work_sync(&ep->calendar_work); + /* pcs_free(ep->sun); */ /* ep->sun = NULL; */ if (ep->gc) @@ -319,12 +323,11 @@ static void pcs_rpc_destroy(struct pcs_rpc *ep) */ spin_lock(&ep->eng->lock); hlist_del(&ep->link); - flush = !(--ep->eng->nrpcs); + last_ep = (!--ep->eng->nrpcs); spin_unlock(&ep->eng->lock); - cancel_delayed_work_sync(&ep->calendar_work); - if (flush) - flush_delayed_work(&ep->eng->stat_work); + if (last_ep) + wake_up_all(&pcs_waitq); memset(ep, 0xFF, sizeof(*ep)); kfree(ep); @@ -1308,18 +1311,13 @@ void pcs_rpc_engine_init(struct pcs_rpc_engine * eng, u8 role) static void pcs_rpc_fini_verify(struct pcs_rpc_engine *eng, struct hlist_head *rpc_list) { spin_lock(&eng->lock); - while (!hlist_empty(rpc_list)) { + if (!hlist_empty(rpc_list)) { struct pcs_rpc * ep = hlist_entry(rpc_list->first, struct pcs_rpc, link); - pr_warn("rpc connection isn't closed ep: %p (flags: %u, " + WARN(1, "rpc connection isn't closed ep: %p (flags: %u, " "state: %u, refcnt: %u)\n", ep, ep->flags, ep->state, atomic_read(&ep->refcnt)); - WARN_ON(!(ep->flags & PCS_RPC_F_DEAD)); - WARN_ON(atomic_read(&ep->refcnt) <= 0); - spin_unlock(&eng->lock); - schedule_timeout(5 * HZ); - spin_lock(&eng->lock); } spin_unlock(&eng->lock); } @@ -1328,8 +1326,9 @@ void pcs_rpc_engine_fini(struct pcs_rpc_engine * eng) { unsigned int i; - if (cancel_delayed_work_sync(&eng->stat_work)) - pr_err("fuse kio: stat_work was actually canceled\n"); + wait_event(pcs_waitq, (eng->nrpcs == 0)); + + cancel_delayed_work_sync(&eng->stat_work); for (i = 0; i < PCS_RPC_HASH_SIZE; i++) pcs_rpc_fini_verify(eng, &eng->ht[i]); @@ -1419,7 +1418,7 @@ void rpc_connect_done(struct pcs_rpc *ep, struct socket *sock) BUG(); ep->conn = &sio->ioconn; - sio->parent = ep; + sio->parent = pcs_rpc_get(ep); sio->get_msg = rpc_get_hdr; sio->eof = rpc_eof_cb; //pcs_ioconn_register(ep->conn); diff --git a/fs/fuse/kio/pcs/pcs_sock_io.c b/fs/fuse/kio/pcs/pcs_sock_io.c index 68829daaa00e..04b63b58dad6 100644 --- a/fs/fuse/kio/pcs/pcs_sock_io.c +++ b/fs/fuse/kio/pcs/pcs_sock_io.c @@ -485,7 +485,9 @@ static void pcs_restore_sockets(struct pcs_ioconn *ioconn) static void sio_destroy_rcu(struct rcu_head *head) { struct pcs_sockio *sio = container_of(head, struct pcs_sockio, rcu); + struct pcs_rpc *ep = sio->parent; + pcs_rpc_put(ep); memset(sio, 0xFF, sizeof(*sio)); kfree(sio); } _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel