aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-05-21 22:45:41 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-05-22 16:45:46 -0400
commitf092075dd33ea04000590e8ffea65c2e7d03d764 (patch)
tree626ce6b85084d50e9d2d81e32850e494eadbc8cb /fs
parent2c820d9a97f07b273b2c8a5960bd52b1b5864c68 (diff)
NFS: Always use the same SETCLIENTID boot verifier
Currently our NFS client assigns a unique SETCLIENTID boot verifier for each server IP address it knows about. It's set to CURRENT_TIME when the struct nfs_client for that server IP is created. During the SETCLIENTID operation, our client also presents an nfs_client_id4 string to servers, as an identifier on which the server can hang all of this client's NFSv4 state. Our client's nfs_client_id4 string is unique for each server IP address. An NFSv4 server is obligated to wipe all NFSv4 state associated with an nfs_client_id4 string when the client presents the same nfs_client_id4 string along with a changed SETCLIENTID boot verifier. When our client unmounts the last of a server's shares, it destroys that server's struct nfs_client. The next time the client mounts that NFS server, it creates a fresh struct nfs_client with a fresh boot verifier. On seeing the fresh verifer, the server wipes any previous NFSv4 state associated with that nfs_client_id4. However, NFSv4.1 clients are supposed to present the same nfs_client_id4 string to all servers. And, to support Transparent State Migration, the same nfs_client_id4 string should be presented to all NFSv4.0 servers so they recognize that migrated state for this client belongs with state a server may already have for this client. (This is known as the Uniform Client String model). If the nfs_client_id4 string is the same but the boot verifier changes for each server IP address, SETCLIENTID and EXCHANGE_ID operations from such a client could unintentionally result in a server wiping a client's previously obtained lease. Thus, if our NFS client is going to use a fixed nfs_client_id4 string, either for NFSv4.0 or NFSv4.1 mounts, our NFS client should use a boot verifier that does not change depending on server IP address. Replace our current per-nfs_client boot verifier with a per-nfs_net boot verifier. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/client.c2
-rw-r--r--fs/nfs/netns.h5
-rw-r--r--fs/nfs/nfs4proc.c14
-rw-r--r--fs/nfs/nfs4xdr.c5
4 files changed, 18 insertions, 8 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 9b9df71df09a..af9b7e4b9df2 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -184,7 +184,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
184 spin_lock_init(&clp->cl_lock); 184 spin_lock_init(&clp->cl_lock);
185 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); 185 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
186 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); 186 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
187 clp->cl_boot_time = CURRENT_TIME;
188 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; 187 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
189 clp->cl_minorversion = cl_init->minorversion; 188 clp->cl_minorversion = cl_init->minorversion;
190 clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; 189 clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
@@ -1813,6 +1812,7 @@ void nfs_clients_init(struct net *net)
1813 idr_init(&nn->cb_ident_idr); 1812 idr_init(&nn->cb_ident_idr);
1814#endif 1813#endif
1815 spin_lock_init(&nn->nfs_client_lock); 1814 spin_lock_init(&nn->nfs_client_lock);
1815 nn->boot_time = CURRENT_TIME;
1816} 1816}
1817 1817
1818#ifdef CONFIG_PROC_FS 1818#ifdef CONFIG_PROC_FS
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
index aa14ec303e94..8a6394edb8b0 100644
--- a/fs/nfs/netns.h
+++ b/fs/nfs/netns.h
@@ -1,3 +1,7 @@
1/*
2 * NFS-private data for each "struct net". Accessed with net_generic().
3 */
4
1#ifndef __NFS_NETNS_H__ 5#ifndef __NFS_NETNS_H__
2#define __NFS_NETNS_H__ 6#define __NFS_NETNS_H__
3 7
@@ -20,6 +24,7 @@ struct nfs_net {
20 struct idr cb_ident_idr; /* Protected by nfs_client_lock */ 24 struct idr cb_ident_idr; /* Protected by nfs_client_lock */
21#endif 25#endif
22 spinlock_t nfs_client_lock; 26 spinlock_t nfs_client_lock;
27 struct timespec boot_time;
23}; 28};
24 29
25extern int nfs_net_id; 30extern int nfs_net_id;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 81ccdbbb43e8..9e9334a172cf 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -64,6 +64,7 @@
64#include "iostat.h" 64#include "iostat.h"
65#include "callback.h" 65#include "callback.h"
66#include "pnfs.h" 66#include "pnfs.h"
67#include "netns.h"
67 68
68#define NFSDBG_FACILITY NFSDBG_PROC 69#define NFSDBG_FACILITY NFSDBG_PROC
69 70
@@ -3903,8 +3904,8 @@ wait_on_recovery:
3903 return -EAGAIN; 3904 return -EAGAIN;
3904} 3905}
3905 3906
3906static void nfs4_construct_boot_verifier(struct nfs_client *clp, 3907static void nfs4_init_boot_verifier(const struct nfs_client *clp,
3907 nfs4_verifier *bootverf) 3908 nfs4_verifier *bootverf)
3908{ 3909{
3909 __be32 verf[2]; 3910 __be32 verf[2];
3910 3911
@@ -3914,8 +3915,9 @@ static void nfs4_construct_boot_verifier(struct nfs_client *clp,
3914 verf[0] = 0; 3915 verf[0] = 0;
3915 verf[1] = (__be32)(NSEC_PER_SEC + 1); 3916 verf[1] = (__be32)(NSEC_PER_SEC + 1);
3916 } else { 3917 } else {
3917 verf[0] = (__be32)clp->cl_boot_time.tv_sec; 3918 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
3918 verf[1] = (__be32)clp->cl_boot_time.tv_nsec; 3919 verf[0] = (__be32)nn->boot_time.tv_sec;
3920 verf[1] = (__be32)nn->boot_time.tv_nsec;
3919 } 3921 }
3920 memcpy(bootverf->data, verf, sizeof(bootverf->data)); 3922 memcpy(bootverf->data, verf, sizeof(bootverf->data));
3921} 3923}
@@ -3939,7 +3941,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
3939 int loop = 0; 3941 int loop = 0;
3940 int status; 3942 int status;
3941 3943
3942 nfs4_construct_boot_verifier(clp, &sc_verifier); 3944 nfs4_init_boot_verifier(clp, &sc_verifier);
3943 3945
3944 for(;;) { 3946 for(;;) {
3945 rcu_read_lock(); 3947 rcu_read_lock();
@@ -5099,7 +5101,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
5099 dprintk("--> %s\n", __func__); 5101 dprintk("--> %s\n", __func__);
5100 BUG_ON(clp == NULL); 5102 BUG_ON(clp == NULL);
5101 5103
5102 nfs4_construct_boot_verifier(clp, &verifier); 5104 nfs4_init_boot_verifier(clp, &verifier);
5103 5105
5104 args.id_len = scnprintf(args.id, sizeof(args.id), 5106 args.id_len = scnprintf(args.id, sizeof(args.id),
5105 "%s/%s/%u", 5107 "%s/%s/%u",
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index db040e971932..12b99825a1c1 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -53,9 +53,11 @@
53#include <linux/nfs4.h> 53#include <linux/nfs4.h>
54#include <linux/nfs_fs.h> 54#include <linux/nfs_fs.h>
55#include <linux/nfs_idmap.h> 55#include <linux/nfs_idmap.h>
56
56#include "nfs4_fs.h" 57#include "nfs4_fs.h"
57#include "internal.h" 58#include "internal.h"
58#include "pnfs.h" 59#include "pnfs.h"
60#include "netns.h"
59 61
60#define NFSDBG_FACILITY NFSDBG_XDR 62#define NFSDBG_FACILITY NFSDBG_XDR
61 63
@@ -1702,6 +1704,7 @@ static void encode_create_session(struct xdr_stream *xdr,
1702 char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; 1704 char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
1703 uint32_t len; 1705 uint32_t len;
1704 struct nfs_client *clp = args->client; 1706 struct nfs_client *clp = args->client;
1707 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
1705 u32 max_resp_sz_cached; 1708 u32 max_resp_sz_cached;
1706 1709
1707 /* 1710 /*
@@ -1743,7 +1746,7 @@ static void encode_create_session(struct xdr_stream *xdr,
1743 *p++ = cpu_to_be32(RPC_AUTH_UNIX); /* auth_sys */ 1746 *p++ = cpu_to_be32(RPC_AUTH_UNIX); /* auth_sys */
1744 1747
1745 /* authsys_parms rfc1831 */ 1748 /* authsys_parms rfc1831 */
1746 *p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ 1749 *p++ = (__be32)nn->boot_time.tv_nsec; /* stamp */
1747 p = xdr_encode_opaque(p, machine_name, len); 1750 p = xdr_encode_opaque(p, machine_name, len);
1748 *p++ = cpu_to_be32(0); /* UID */ 1751 *p++ = cpu_to_be32(0); /* UID */
1749 *p++ = cpu_to_be32(0); /* GID */ 1752 *p++ = cpu_to_be32(0); /* GID */