[PATCH] SUNRPC: Allow rpc_clone_client() to share rpc_auth objects

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



J. Bruce Fields reports:
> On 3.7-rc1:
>
> 	client# mount -tnfs -osec=krb5,vers=3 server:/exports/ext4 /mnt/
>
> 		server# ls -l /exports/ext4|grep TMP
> 		server#
>
> 	# mkdir /mnt/TMP
> 	mkdir: cannot create directory `/mnt/TMP': Permission denied
>
> 		server# ls -l /exports/ext4|grep TMP
> 		drwxr-xr-x  2 nfsnobody nfsnobody 4096 Oct 16 08:56 TMP
> 		server#
>
> Wireshark also shows that the create succeeds.

The NFS3 MKDIR operation succeeds but the mkdir(2) system call fails
because the NFS client attempts to retrieve the ACL on the new
directory, but encounters a problem that appears to have been
introduced by commit 1b63a751 "SUNRPC: Refactor rpc_clone_client()",
Sep 14 17:23:52 2012.

NFSv3 ACL requests are part of a side-band protocol called NFSACL.
Unlike the MNT or NLM side-band protocols, an NFS client sends
NFSACL protocol requests on the same transport as it sends NFS
protocol requests.

The Linux NFS client clones the rpc_clnt for the NFS protocol to
make an rpc_clnt for NFSACL protocol requests, but they share the
underlying transport (rpc_xprt).  Normally the original rpc_clnt's
rpc_auth object should also be shared by both rpc_clnt's.  See
rpc_bind_new_program() and rpc_clone_client().

Thanks to 1b63a751, however, rpc_clone_client() create a _new_
rpc_auth object for the NFSACL rpc_clnt.  With AUTH_GSS, this means
a fresh GSS context must be created for the new rpc_auth object.
rpc.gssd tries to create the context with the service name
"nfsacl@servername".  The NFS server does not recognize that service
name.

The solution is to restore the original pre-1b63a751 behavior of
rpc_clone_client().  This behavior is to share an rpc_auth
object between the original rpc_clnt and the cloned rpc_clnt.  A
fresh GSS context for the NFSACL rpc_clnt is then no longer
required.  It simply uses the one that is already established for
the NFS rpc_clnt.

Reported-by: J. Bruce Fields <bfields@xxxxxxxxxxxx>
Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---

 include/linux/sunrpc/clnt.h |    1 +
 net/sunrpc/clnt.c           |   21 +++++++++++++++------
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 34206b8..2931952 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -112,6 +112,7 @@ struct rpc_create_args {
 	u32			prognumber;	/* overrides program->number */
 	u32			version;
 	rpc_authflavor_t	authflavor;
+	struct rpc_auth		*auth;
 	unsigned long		flags;
 	char			*client_name;
 	struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index cdc7564..c75630a 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -356,12 +356,17 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
 	if (err < 0)
 		goto out_no_path;
 
-	auth = rpcauth_create(args->authflavor, clnt);
-	if (IS_ERR(auth)) {
-		printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
-				args->authflavor);
-		err = PTR_ERR(auth);
-		goto out_no_auth;
+	if (args->auth == NULL) {
+		auth = rpcauth_create(args->authflavor, clnt);
+		if (IS_ERR(auth)) {
+			printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
+					args->authflavor);
+			err = PTR_ERR(auth);
+			goto out_no_auth;
+		}
+	} else {
+		atomic_inc(&args->auth->au_count);
+		clnt->cl_auth = args->auth;
 	}
 
 	/* save the nodename */
@@ -542,6 +547,7 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
 		.prognumber	= clnt->cl_prog,
 		.version	= clnt->cl_vers,
 		.authflavor	= clnt->cl_auth->au_flavor,
+		.auth		= clnt->cl_auth,
 		.client_name	= clnt->cl_principal,
 	};
 	return __rpc_clone_client(&args, clnt);
@@ -566,6 +572,9 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 		.authflavor	= flavor,
 		.client_name	= clnt->cl_principal,
 	};
+
+	if (flavor == clnt->cl_auth->au_flavor)
+		args.auth = clnt->cl_auth;
 	return __rpc_clone_client(&args, clnt);
 }
 EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux