aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-08-22 20:06:10 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:33 -0400
commit24c8dbbb5f777187d660393599641ab3307b4b97 (patch)
tree9d50fdd57c7593d925a21e4bb049095a4e4ead6f /fs/nfs/nfs4state.c
parente9326dcab413848e70ab746c7c5363da13e5f801 (diff)
NFS: Generalise the nfs_client structure
Generalise the nfs_client structure by: (1) Moving nfs_client to a more general place (nfs_fs_sb.h). (2) Renaming its maintenance routines to be non-NFS4 specific. (3) Move those maintenance routines to a new non-NFS4 specific file (client.c) and move the declarations to internal.h. (4) Make nfs_find/get_client() take a full sockaddr_in to include the port number (will be required for NFS2/3). (5) Make nfs_find/get_client() take the NFS protocol version (again will be required to differentiate NFS2, 3 & 4 client records). Also: (6) Make nfs_client construction proceed akin to inodes, marking them as under construction and providing a function to indicate completion. (7) Make nfs_get_client() wait interruptibly if it finds a client that it can share, but that client is currently being constructed. (8) Make nfs4_create_client() use (6) and (7) instead of locking cl_sem. Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c128
1 files changed, 6 insertions, 122 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index fa51a7d4c022..058811e39555 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -50,12 +50,12 @@
50#include "nfs4_fs.h" 50#include "nfs4_fs.h"
51#include "callback.h" 51#include "callback.h"
52#include "delegation.h" 52#include "delegation.h"
53#include "internal.h"
53 54
54#define OPENOWNER_POOL_SIZE 8 55#define OPENOWNER_POOL_SIZE 8
55 56
56const nfs4_stateid zero_stateid; 57const nfs4_stateid zero_stateid;
57 58
58static DEFINE_SPINLOCK(state_spinlock);
59static LIST_HEAD(nfs4_clientid_list); 59static LIST_HEAD(nfs4_clientid_list);
60 60
61void 61void
@@ -71,127 +71,11 @@ destroy_nfsv4_state(struct nfs_server *server)
71 kfree(server->mnt_path); 71 kfree(server->mnt_path);
72 server->mnt_path = NULL; 72 server->mnt_path = NULL;
73 if (server->nfs_client) { 73 if (server->nfs_client) {
74 nfs4_put_client(server->nfs_client); 74 nfs_put_client(server->nfs_client);
75 server->nfs_client = NULL; 75 server->nfs_client = NULL;
76 } 76 }
77} 77}
78 78
79/*
80 * nfs4_get_client(): returns an empty client structure
81 * nfs4_put_client(): drops reference to client structure
82 *
83 * Since these are allocated/deallocated very rarely, we don't
84 * bother putting them in a slab cache...
85 */
86static struct nfs_client *
87nfs4_alloc_client(struct in_addr *addr)
88{
89 struct nfs_client *clp;
90
91 if (nfs_callback_up() < 0)
92 return NULL;
93 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
94 nfs_callback_down();
95 return NULL;
96 }
97 memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
98 init_rwsem(&clp->cl_sem);
99 INIT_LIST_HEAD(&clp->cl_delegations);
100 INIT_LIST_HEAD(&clp->cl_state_owners);
101 INIT_LIST_HEAD(&clp->cl_unused);
102 spin_lock_init(&clp->cl_lock);
103 atomic_set(&clp->cl_count, 1);
104 INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
105 INIT_LIST_HEAD(&clp->cl_superblocks);
106 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
107 clp->cl_rpcclient = ERR_PTR(-EINVAL);
108 clp->cl_boot_time = CURRENT_TIME;
109 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
110 return clp;
111}
112
113static void
114nfs4_free_client(struct nfs_client *clp)
115{
116 struct nfs4_state_owner *sp;
117
118 while (!list_empty(&clp->cl_unused)) {
119 sp = list_entry(clp->cl_unused.next,
120 struct nfs4_state_owner,
121 so_list);
122 list_del(&sp->so_list);
123 kfree(sp);
124 }
125 BUG_ON(!list_empty(&clp->cl_state_owners));
126 nfs_idmap_delete(clp);
127 if (!IS_ERR(clp->cl_rpcclient))
128 rpc_shutdown_client(clp->cl_rpcclient);
129 kfree(clp);
130 nfs_callback_down();
131}
132
133static struct nfs_client *__nfs4_find_client(struct in_addr *addr)
134{
135 struct nfs_client *clp;
136 list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
137 if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) {
138 atomic_inc(&clp->cl_count);
139 return clp;
140 }
141 }
142 return NULL;
143}
144
145struct nfs_client *nfs4_find_client(struct in_addr *addr)
146{
147 struct nfs_client *clp;
148 spin_lock(&state_spinlock);
149 clp = __nfs4_find_client(addr);
150 spin_unlock(&state_spinlock);
151 return clp;
152}
153
154struct nfs_client *
155nfs4_get_client(struct in_addr *addr)
156{
157 struct nfs_client *clp, *new = NULL;
158
159 spin_lock(&state_spinlock);
160 for (;;) {
161 clp = __nfs4_find_client(addr);
162 if (clp != NULL)
163 break;
164 clp = new;
165 if (clp != NULL) {
166 list_add(&clp->cl_servers, &nfs4_clientid_list);
167 new = NULL;
168 break;
169 }
170 spin_unlock(&state_spinlock);
171 new = nfs4_alloc_client(addr);
172 spin_lock(&state_spinlock);
173 if (new == NULL)
174 break;
175 }
176 spin_unlock(&state_spinlock);
177 if (new)
178 nfs4_free_client(new);
179 return clp;
180}
181
182void
183nfs4_put_client(struct nfs_client *clp)
184{
185 if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock))
186 return;
187 list_del(&clp->cl_servers);
188 spin_unlock(&state_spinlock);
189 BUG_ON(!list_empty(&clp->cl_superblocks));
190 rpc_wake_up(&clp->cl_rpcwaitq);
191 nfs4_kill_renewd(clp);
192 nfs4_free_client(clp);
193}
194
195static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) 79static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
196{ 80{
197 int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, 81 int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
@@ -771,11 +655,11 @@ static void nfs4_recover_state(struct nfs_client *clp)
771 __module_get(THIS_MODULE); 655 __module_get(THIS_MODULE);
772 atomic_inc(&clp->cl_count); 656 atomic_inc(&clp->cl_count);
773 task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", 657 task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim",
774 NIPQUAD(clp->cl_addr)); 658 NIPQUAD(clp->cl_addr.sin_addr));
775 if (!IS_ERR(task)) 659 if (!IS_ERR(task))
776 return; 660 return;
777 nfs4_clear_recover_bit(clp); 661 nfs4_clear_recover_bit(clp);
778 nfs4_put_client(clp); 662 nfs_put_client(clp);
779 module_put(THIS_MODULE); 663 module_put(THIS_MODULE);
780} 664}
781 665
@@ -970,12 +854,12 @@ out:
970 if (status == -NFS4ERR_CB_PATH_DOWN) 854 if (status == -NFS4ERR_CB_PATH_DOWN)
971 nfs_handle_cb_pathdown(clp); 855 nfs_handle_cb_pathdown(clp);
972 nfs4_clear_recover_bit(clp); 856 nfs4_clear_recover_bit(clp);
973 nfs4_put_client(clp); 857 nfs_put_client(clp);
974 module_put_and_exit(0); 858 module_put_and_exit(0);
975 return 0; 859 return 0;
976out_error: 860out_error:
977 printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", 861 printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
978 NIPQUAD(clp->cl_addr.s_addr), -status); 862 NIPQUAD(clp->cl_addr.sin_addr), -status);
979 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); 863 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
980 goto out; 864 goto out;
981} 865}