[pnfs] [PATCH 23/29] nfs41: sessions exchange_id AUTH_SYS root cred

Benny Halevy bhalevy at panasas.com
Fri Dec 28 03:45:59 EST 2007


From: Andy Adamson <andros at umich.edu>

Unlike NFSv4.0, NFSv4.1 requires machine credentials. RPC_AUTH_GSS machine
credentials will be passed into the kernel at mount time to be available for
the exchange_id operation.

RPC_AUTH_UNIX root mounts can use the UNIX root credential. Store the root
credential in the nfs_client struct.

Without a credential, NFSv4.1 state renewal fails.

Signed-off-by: Andy Adamson<andros at umich.edu>
Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfs/client.c           |    5 +++++
 fs/nfs/nfs4_fs.h          |    4 ++++
 fs/nfs/nfs4proc.c         |   26 ++++++++++++++++++++++++++
 fs/nfs/nfs4renewd.c       |   10 ++--------
 fs/nfs/nfs4state.c        |   10 +++++++++-
 include/linux/nfs_fs_sb.h |    1 +
 6 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 4848559..f96aa40 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -185,6 +185,11 @@ static void nfs_free_client(struct nfs_client *clp)
 	if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
 		nfs_callback_down();
 
+#ifdef CONFIG_NFS_V4_1
+	if (clp->cl_ex_cred)
+		put_rpccred(clp->cl_ex_cred);
+#endif /* CONFIG_NFS_V4_1 */
+
 	kfree(clp->cl_hostname);
 	kfree(clp);
 
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index dcd354d..fe8fb9c 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -170,6 +170,7 @@ struct nfs4_state_recovery_ops {
 #if defined(CONFIG_NFS_V4_1)
 struct nfs4_state_maintenance_ops {
 	int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *);
+	struct rpc_cred * (*get_state_renewal_cred)(struct nfs_client *);
 };
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -225,6 +226,9 @@ extern void nfs4_renew_state(struct work_struct *);
 
 /* nfs4state.c */
 struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
+#ifdef CONFIG_NFS_V4_1
+struct rpc_cred *nfs41_get_state_renewal_cred(struct nfs_client *clp);
+#endif /* CONFIG_NFS_V4_1 */
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 63db97d..40492e1 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4529,6 +4529,30 @@ int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 		else if (++clp->cl_id_uniquifier == 0)
 			break;
 	}
+	if (status == 0) {
+		struct rpc_clnt *clnt = clp->cl_rpcclient;
+
+		/* NFSv4.1 will use machine creds acquired at mount, and will
+		 * need to remember which creds were used for the EXCHANGE_ID.
+		 * Add an rpc cred pointer to struct nfs_client to hold
+		 * the EXCHANGE_ID cred, and enable AUTH_UNIX mounts.
+		 */
+		if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX &&
+						current->fsuid == 0) {
+
+			dprintk("%s cl_ex_cred %p [NULL]\n", __func__,
+						clp->cl_ex_cred);
+
+			clp->cl_ex_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+			atomic_inc(&clp->cl_ex_cred->cr_count);
+
+			dprintk("%s set cl_ex_cred %p\n",
+						__func__, clp->cl_ex_cred);
+		} else {
+			dprintk("%s not AUTH_SYS don't save EXCHANGE_ID cred\n",
+				__func__);
+		}
+	}
 
 	dprintk("<-- %s status= %d\n", __FUNCTION__, status);
 	return status;
@@ -5192,11 +5216,13 @@ struct nfs4_state_recovery_ops nfs41_network_partition_recovery_ops = {
 
 struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
 	.sched_state_renewal = nfs4_proc_async_renew,
+	.get_state_renewal_cred = nfs41_get_state_renewal_cred,
 };
 
 #if defined(CONFIG_NFS_V4_1)
 struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
 	.sched_state_renewal = nfs41_proc_async_sequence,
+	.get_state_renewal_cred = nfs4_get_renew_cred,
 };
 #endif
 
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index c1e000e..20667d8 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -64,7 +64,7 @@ nfs4_renew_state(struct work_struct *work)
 	struct nfs4_state_maintenance_ops *ops;
 	struct nfs_client *clp =
 		container_of(work, struct nfs_client, cl_renewd.work);
-	struct rpc_cred *cred;
+	struct rpc_cred *cred = NULL;
 	long lease, timeout;
 	unsigned long last, now;
 
@@ -81,13 +81,7 @@ nfs4_renew_state(struct work_struct *work)
 	timeout = (2 * lease) / 3 + (long)last - (long)now;
 	/* Are we close to a lease timeout? */
 	if (time_after(now, last + lease/3)) {
-#if defined(CONFIG_NFS_V4_1)
-		dprintk("%s NO STATE RENEWAL: ops->sched_state_renewal() "
-			"not implemented\n", __func__);
-		cred = NULL;
-#else /* CONFIG_NFS_V4_1 */
-		cred = nfs4_get_renew_cred(clp);
-#endif /* CONFIG_NFS_V4_1 */
+		cred = ops->get_state_renewal_cred(clp);
 		if (cred == NULL) {
 			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
 			spin_unlock(&clp->cl_lock);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 4456935..f67563d 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -90,7 +90,15 @@ u64 nfs41_clientid(struct nfs_client *clp)
 {
 	return 0;
 }
-#endif
+
+struct rpc_cred *
+nfs41_get_state_renewal_cred(struct nfs_client *clp)
+{
+	if (clp->cl_ex_cred)
+		get_rpccred(clp->cl_ex_cred);
+	return (clp->cl_ex_cred);
+}
+#endif /* CONFIG_NFS_V4_1 */
 
 struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
 {
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 594089e..34e7981 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -77,6 +77,7 @@ struct nfs_client {
 	u32			cl_seqid;
 	/* The flags used for obtaining the clientid during EXCHANGE_ID */
 	u32			cl_exchange_flags;
+	struct rpc_cred *	cl_ex_cred;	/* exchange_id credential */
 #endif
 #ifdef CONFIG_PNFS
 	struct nfs4_session *	cl_ds_session; /* pNFS data server session */
-- 
1.5.3.3



More information about the pNFS mailing list