Acquiring rpc's mutex lock in krpc ioctl operation could potentially
block the calling userspace process for very long time, thus stall the
evloop process in case of vstorage client.

https://virtuozzo.atlassian.net/browse/VSTOR-93139

Signed-off-by: Liu Kui <kui....@virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_cs.c       |  2 +-
 fs/fuse/kio/pcs/pcs_krpc.c     |  2 +-
 fs/fuse/kio/pcs/pcs_rpc.c      | 32 +++++++++++++++++++++++++-------
 fs/fuse/kio/pcs/pcs_rpc.h      |  2 ++
 fs/fuse/kio/pcs/pcs_rpc_clnt.c | 28 ++++++----------------------
 5 files changed, 35 insertions(+), 31 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_cs.c b/fs/fuse/kio/pcs/pcs_cs.c
index 2e16b8dabc91..efa69cd352ab 100644
--- a/fs/fuse/kio/pcs/pcs_cs.c
+++ b/fs/fuse/kio/pcs/pcs_cs.c
@@ -1019,7 +1019,7 @@ static void pcs_cs_destroy(struct pcs_cs *cs)
 
        if (cs->rpc) {
                cs->rpc->clnt_cs = NULL;
-               pcs_rpc_clnt_close(cs->rpc);
+               pcs_rpc_close(cs->rpc);
                cs->rpc = NULL;
        }
        call_rcu(&cs->rcu, cs_destroy_rcu);
diff --git a/fs/fuse/kio/pcs/pcs_krpc.c b/fs/fuse/kio/pcs/pcs_krpc.c
index ee88bc17e6d9..f40252770dcc 100644
--- a/fs/fuse/kio/pcs/pcs_krpc.c
+++ b/fs/fuse/kio/pcs/pcs_krpc.c
@@ -842,7 +842,7 @@ static void __pcs_krpc_destroy(struct pcs_krpc *krpc)
 
        if (krpc->rpc) {
                krpc->rpc->clnt_krpc = NULL;
-               pcs_rpc_clnt_close(krpc->rpc);
+               pcs_rpc_close(krpc->rpc);
                krpc->rpc = NULL;
        }
        pcs_krpc_put(krpc);
diff --git a/fs/fuse/kio/pcs/pcs_rpc.c b/fs/fuse/kio/pcs/pcs_rpc.c
index a4f3ae1fdf5b..79254431592a 100644
--- a/fs/fuse/kio/pcs/pcs_rpc.c
+++ b/fs/fuse/kio/pcs/pcs_rpc.c
@@ -265,21 +265,37 @@ void rpc_abort(struct pcs_rpc * ep, int fatal, int error)
        pcs_rpc_put(ep);
 }
 
-/* Client close. */
-void pcs_rpc_close(struct pcs_rpc * ep)
+static void rpc_close_work(struct work_struct *w)
 {
-       TRACE("pcs_rpc_close");
-       mutex_lock(&ep->mutex);
-       BUG_ON(ep->flags & PCS_RPC_F_DEAD);
-       BUG_ON(ep->flags & PCS_RPC_F_PASSIVE);
+       struct pcs_rpc *ep = container_of(w, struct pcs_rpc, close_work);
 
-       ep->flags |= PCS_RPC_F_DEAD;
+       mutex_lock(&ep->mutex);
        rpc_abort(ep, 1, PCS_ERR_NET_ABORT);
        ep->state = PCS_RPC_DESTROY;
        mutex_unlock(&ep->mutex);
 
        pcs_rpc_put(ep);
+}
+
+/* Client close. */
+void pcs_rpc_close(struct pcs_rpc *ep)
+{
+       TRACE("pcs_rpc_close, nr_clnts=%d", ep->nr_clnts);
+
+       spin_lock(&ep->clnt_lock);
+       BUG_ON(ep->flags & PCS_RPC_F_DEAD);
 
+       ep->nr_clnts--;
+       if (!ep->nr_clnts) {
+               /* close the rpc if we're the last rpc client */
+               ep->flags |= PCS_RPC_F_DEAD;
+               memset(&ep->peer_id, 0, sizeof(PCS_NODE_ID_T));
+               pcs_rpc_get(ep);
+               queue_work(pcs_cleanup_wq, &ep->close_work);
+       }
+       spin_unlock(&ep->clnt_lock);
+
+       pcs_rpc_put(ep);
 }
 
 void pcs_rpc_attach_new_ep(struct pcs_rpc * ep, struct pcs_rpc_engine * eng)
@@ -300,6 +316,7 @@ void pcs_rpc_attach_new_ep(struct pcs_rpc * ep, struct 
pcs_rpc_engine * eng)
        INIT_LIST_HEAD(&ep->lru_link);
 
        spin_lock_init(&ep->q_lock);
+       spin_lock_init(&ep->clnt_lock);
        mutex_init(&ep->mutex);
        ep->accounted = 0;
        ep->netlat_min = ~0U;
@@ -1000,6 +1017,7 @@ void pcs_rpc_configure_new_ep(struct pcs_rpc * ep, struct 
pcs_rpc_params *parm,
        ep->kill_arrow = 0;
 
        INIT_WORK(&ep->work, rpc_queue_work);
+       INIT_WORK(&ep->close_work, rpc_close_work);
        INIT_DELAYED_WORK(&ep->timer_work, timer_work);
        INIT_DELAYED_WORK(&ep->calendar_work, calendar_work);
 
diff --git a/fs/fuse/kio/pcs/pcs_rpc.h b/fs/fuse/kio/pcs/pcs_rpc.h
index 9a651a812cf7..613b711c7822 100644
--- a/fs/fuse/kio/pcs/pcs_rpc.h
+++ b/fs/fuse/kio/pcs/pcs_rpc.h
@@ -153,9 +153,11 @@ struct pcs_rpc
        struct hlist_head       kill_calendar[RPC_MAX_CALENDAR];
        struct llist_node       cleanup_node;
 
+       spinlock_t      clnt_lock;      /* protect following field */
        struct pcs_cs           *clnt_cs;
        struct pcs_krpc         *clnt_krpc;
        int nr_clnts;
+       struct work_struct  close_work;
 };
 
 struct pcs_rpc_engine
diff --git a/fs/fuse/kio/pcs/pcs_rpc_clnt.c b/fs/fuse/kio/pcs/pcs_rpc_clnt.c
index bd1eec849abc..cfc81c053254 100644
--- a/fs/fuse/kio/pcs/pcs_rpc_clnt.c
+++ b/fs/fuse/kio/pcs/pcs_rpc_clnt.c
@@ -136,10 +136,10 @@ struct pcs_rpc *pcs_rpc_clnt_create(struct pcs_rpc_engine 
*eng, PCS_NODE_ID_T *p
        spin_unlock(&eng->lock);
 
        if (ep) {
-               mutex_lock(&ep->mutex);
-               if (ep->state != PCS_RPC_DESTROY)
+               spin_lock(&ep->clnt_lock);
+               if (!(ep->flags & PCS_RPC_F_DEAD))
                        goto found;
-               mutex_unlock(&ep->mutex);
+               spin_unlock(&ep->clnt_lock);
                pcs_rpc_put(ep);
        }
 
@@ -159,28 +159,12 @@ struct pcs_rpc *pcs_rpc_clnt_create(struct pcs_rpc_engine 
*eng, PCS_NODE_ID_T *p
        else
                ep->flags &= ~PCS_RPC_F_LOCAL;
 
-       mutex_lock(&ep->mutex);
+       spin_lock(&ep->clnt_lock);
+
 found:
        ep->nr_clnts++;
-       mutex_unlock(&ep->mutex);
+       spin_unlock(&ep->clnt_lock);
 
        return ep;
 }
 
-void pcs_rpc_clnt_close(struct pcs_rpc *ep)
-{
-       mutex_lock(&ep->mutex);
-       BUG_ON(ep->flags & PCS_RPC_F_DEAD);
-       BUG_ON(ep->flags & PCS_RPC_F_PASSIVE);
-
-       ep->nr_clnts--;
-       if (!ep->nr_clnts) {
-               /* close the rpc if we're the last rpc client */
-               ep->flags |= PCS_RPC_F_DEAD;
-               rpc_abort(ep, 1, PCS_ERR_NET_ABORT);
-               ep->state = PCS_RPC_DESTROY;
-       }
-       mutex_unlock(&ep->mutex);
-
-       pcs_rpc_put(ep);
-}
-- 
2.39.3 (Apple Git-146)

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to