[Devel] [PATCH VZ9] fs/fuse kio: fix krpc state transition on connect

Alexey Kuznetsov kuznet at virtuozzo.com
Tue Oct 1 11:07:31 MSK 2024


Ack

On Tue, Oct 1, 2024 at 1:11 PM Liu Kui <kui.liu at virtuozzo.com> wrote:
>
> Currently krpc would report to userspace to be in work state immediately
> after connect, even though kernel rpc may not be in work state. Userspace
> will start sending msg immediately after connect while kernel is still
> establishing the underlying connection. It's not uncommon that it may take
> very long time for a connection to be fully established. When this happens,
> userspace may abort the connection due to timeout. However krpc abort needs
> to acquire rpc's mutex lock, which could have been held for connection
> establishment, thus blocking the userspace evloop process.
>
> To avoid above problem, a proper krpc state transition on connect is
> implemented here. It now blocks userspace from transiting to work state
> on connect until the underlying kernel rpc transits to work state.
> Userspace can abort the krpc connection without being blocked while kernel
> rpc is still in establishment phrase.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-93162
>
> Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
> ---
>  fs/fuse/kio/pcs/pcs_krpc.c | 63 ++++++++++++++++++++++++++++++++++----
>  fs/fuse/kio/pcs/pcs_krpc.h |  7 +++++
>  2 files changed, 64 insertions(+), 6 deletions(-)
>
> diff --git a/fs/fuse/kio/pcs/pcs_krpc.c b/fs/fuse/kio/pcs/pcs_krpc.c
> index 0ef33b730204..ee88bc17e6d9 100644
> --- a/fs/fuse/kio/pcs/pcs_krpc.c
> +++ b/fs/fuse/kio/pcs/pcs_krpc.c
> @@ -474,6 +474,8 @@ static int pcs_krpc_abort(struct pcs_krpc *krpc)
>         spin_lock(&krpc->lock);
>
>         if (krpc->state != PCS_KRPC_STATE_CONNECTED) {
> +               if (krpc->state == PCS_KRPC_STATE_CONNECT)
> +                       krpc->state = PCS_KRPC_STATE_UNCONN;
>                 spin_unlock(&krpc->lock);
>                 return 0;
>         }
> @@ -723,6 +725,38 @@ int pcs_krpc_update_addr(struct pcs_krpc_set *krpcs, PCS_NODE_ID_T *id,
>
>         return 0;
>  }
> +
> +static void krpc_connect_done(struct pcs_msg *msg)
> +{
> +       struct krpc_connect_req *req = container_of(msg, struct krpc_connect_req, msg);
> +       struct pcs_krpc *krpc = req->krpc;
> +       __poll_t pollflags = EPOLLHUP;
> +
> +       if (msg->rpc) {
> +               pcs_rpc_put(msg->rpc);
> +               msg->rpc = NULL;
> +       }
> +
> +       spin_lock(&krpc->lock);
> +       /* from a stale session, do nothing  */
> +       if (req->gen != krpc->gen || krpc->state != PCS_KRPC_STATE_CONNECT) {
> +               spin_unlock(&krpc->lock);
> +               goto out;
> +       }
> +
> +       if (!pcs_if_error(&msg->error)) {
> +               krpc->state = PCS_KRPC_STATE_CONNECTED;
> +               pollflags = EPOLLOUT;
> +       }
> +       spin_unlock(&krpc->lock);
> +
> +       wake_up_poll(&krpc->poll_wait, pollflags);
> +
> +out:
> +       pcs_krpc_put(krpc);
> +       kfree(req);
> +}
> +
>  /*
>   * Connect to a pcs_krpc, return a valid fd on success.
>   */
> @@ -732,6 +766,8 @@ int pcs_krpc_connect(struct pcs_krpc_set *krpcs, PCS_NODE_ID_T *id)
>         int fd;
>         struct file *file;
>         struct pcs_krpc_context *ctx;
> +       struct krpc_connect_req *connect_req;
> +       struct pcs_msg *msg;
>
>         krpc = pcs_krpc_lookup(krpcs, id);
>         if (!krpc)
> @@ -741,18 +777,26 @@ int pcs_krpc_connect(struct pcs_krpc_set *krpcs, PCS_NODE_ID_T *id)
>                 krpc->state == PCS_KRPC_STATE_DESTROYED)
>                 return -EPERM;
>
> +       connect_req = kzalloc(sizeof(*connect_req), GFP_KERNEL);
> +       if (!connect_req)
> +               return -ENOMEM;
> +
>         ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
> -       if (!ctx)
> +       if (!ctx) {
> +               kfree(connect_req);
>                 return -ENOMEM;
> +       }
>
>         fd = get_unused_fd_flags(O_CLOEXEC);
>         if (fd < 0) {
> +               kfree(connect_req);
>                 kfree(ctx);
>                 return fd;
>         }
>
>         file = anon_inode_getfile("[pcs_krpc]", &pcs_krpc_fops, ctx, 0);
>         if (IS_ERR(file)) {
> +               kfree(connect_req);
>                 kfree(ctx);
>                 put_unused_fd(fd);
>                 fd = PTR_ERR(file);
> @@ -764,13 +808,20 @@ int pcs_krpc_connect(struct pcs_krpc_set *krpcs, PCS_NODE_ID_T *id)
>         spin_lock(&krpc->lock);
>         ctx->gen = ++krpc->gen;
>         ctx->krpc = pcs_krpc_get(krpc);
> -       /*
> -        * the krpc should always be connected regardless state of
> -        * underlying RPC
> -        */
> -       krpc->state = PCS_KRPC_STATE_CONNECTED;
> +       connect_req->gen = krpc->gen;
> +       connect_req->krpc = pcs_krpc_get(krpc);
> +       krpc->state = PCS_KRPC_STATE_CONNECT;
>         spin_unlock(&krpc->lock);
>
> +       /* Send a zero-size msg which should be completed after the rpc enters work state */
> +       msg = &connect_req->msg;
> +       msg->size = 0;
> +       msg->timeout = 0;
> +       msg->rpc = NULL;
> +       msg->done = krpc_connect_done;
> +       pcs_clear_error(&msg->error);
> +       pcs_rpc_queue(krpc->rpc, msg);
> +
>         return fd;
>  }
>
> diff --git a/fs/fuse/kio/pcs/pcs_krpc.h b/fs/fuse/kio/pcs/pcs_krpc.h
> index 8100dfb2629d..db13b71f6357 100644
> --- a/fs/fuse/kio/pcs/pcs_krpc.h
> +++ b/fs/fuse/kio/pcs/pcs_krpc.h
> @@ -37,11 +37,18 @@ struct pcs_krpc_set {
>
>  enum {
>         PCS_KRPC_STATE_UNCONN,
> +       PCS_KRPC_STATE_CONNECT,
>         PCS_KRPC_STATE_CONNECTED,
>         PCS_KRPC_STATE_ABORTED,
>         PCS_KRPC_STATE_DESTROYED,
>  };
>
> +struct krpc_connect_req {
> +       struct pcs_msg  msg;
> +       struct pcs_krpc *krpc;
> +       u32     gen;
> +};
> +
>  struct pcs_krpc {
>         struct hlist_node               hlist;
>         struct list_head                link;
> --
> 2.39.3 (Apple Git-146)



More information about the Devel mailing list