]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
NFSv4.1: fix handling of backchannel binding in BIND_CONN_TO_SESSION
authorOlga Kornievskaia <olga.kornievskaia@gmail.com>
Fri, 24 Apr 2020 21:45:50 +0000 (17:45 -0400)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Mon, 25 May 2020 08:42:17 +0000 (10:42 +0200)
BugLink: https://bugs.launchpad.net/bugs/1877592
commit dff58530c4ca8ce7ee5a74db431c6e35362cf682 upstream.

Currently, if the client sends BIND_CONN_TO_SESSION with
NFS4_CDFC4_FORE_OR_BOTH but only gets NFS4_CDFS4_FORE back it ignores
that it wasn't able to enable a backchannel.

To make sure, the client sends BIND_CONN_TO_SESSION as the first
operation on the connections (ie., no other session compounds haven't
been sent before), and if the client's request to bind the backchannel
is not satisfied, then reset the connection and retry.

Cc: stable@vger.kernel.org
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
fs/nfs/nfs4proc.c
include/linux/nfs_xdr.h
include/linux/sunrpc/clnt.h

index 6b29703d2fe1e2767456e431aff29492dfb8a9ca..e257653f25abd6ac716e6b4f072191bdf2982e57 100644 (file)
@@ -7852,6 +7852,7 @@ static void
 nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
 {
        struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp;
+       struct nfs41_bind_conn_to_session_res *res = task->tk_msg.rpc_resp;
        struct nfs_client *clp = args->client;
 
        switch (task->tk_status) {
@@ -7860,6 +7861,12 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
                nfs4_schedule_session_recovery(clp->cl_session,
                                task->tk_status);
        }
+       if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
+                       res->dir != NFS4_CDFS4_BOTH) {
+               rpc_task_close_connection(task);
+               if (args->retries++ < MAX_BIND_CONN_TO_SESSION_RETRIES)
+                       rpc_restart_call(task);
+       }
 }
 
 static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
@@ -7882,6 +7889,7 @@ int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
        struct nfs41_bind_conn_to_session_args args = {
                .client = clp,
                .dir = NFS4_CDFC4_FORE_OR_BOTH,
+               .retries = 0,
        };
        struct nfs41_bind_conn_to_session_res res;
        struct rpc_message msg = {
index 9b8324ec08f3191f7ff95944ed0d0cb07df67194..99d327d0bccb48a1c8c23415854f15a469e5c818 100644 (file)
@@ -1307,11 +1307,13 @@ struct nfs41_impl_id {
        struct nfstime4                 date;
 };
 
+#define MAX_BIND_CONN_TO_SESSION_RETRIES 3
 struct nfs41_bind_conn_to_session_args {
        struct nfs_client               *client;
        struct nfs4_sessionid           sessionid;
        u32                             dir;
        bool                            use_conn_in_rdma_mode;
+       int                             retries;
 };
 
 struct nfs41_bind_conn_to_session_res {
index abc63bd1be2b5c792ab17747b6917ff571bf86bc..336802acc629b7cd5e2a5345aefbd09771db524a 100644 (file)
@@ -237,5 +237,10 @@ static inline int rpc_reply_expected(struct rpc_task *task)
                (task->tk_msg.rpc_proc->p_decode != NULL);
 }
 
+static inline void rpc_task_close_connection(struct rpc_task *task)
+{
+       if (task->tk_xprt)
+               xprt_force_disconnect(task->tk_xprt);
+}
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */