NFS: Eliminate client_sys in favour of cl_rpcclient
[safe/jmp/linux-2.6] / fs / nfs / client.c
1 /* client.c: NFS client sharing and management code
2  *
3  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/init.h>
16
17 #include <linux/time.h>
18 #include <linux/kernel.h>
19 #include <linux/mm.h>
20 #include <linux/string.h>
21 #include <linux/stat.h>
22 #include <linux/errno.h>
23 #include <linux/unistd.h>
24 #include <linux/sunrpc/clnt.h>
25 #include <linux/sunrpc/stats.h>
26 #include <linux/sunrpc/metrics.h>
27 #include <linux/nfs_fs.h>
28 #include <linux/nfs_mount.h>
29 #include <linux/nfs4_mount.h>
30 #include <linux/lockd/bind.h>
31 #include <linux/smp_lock.h>
32 #include <linux/seq_file.h>
33 #include <linux/mount.h>
34 #include <linux/nfs_idmap.h>
35 #include <linux/vfs.h>
36 #include <linux/inet.h>
37 #include <linux/nfs_xdr.h>
38
39 #include <asm/system.h>
40
41 #include "nfs4_fs.h"
42 #include "callback.h"
43 #include "delegation.h"
44 #include "iostat.h"
45 #include "internal.h"
46
47 #define NFSDBG_FACILITY         NFSDBG_CLIENT
48
49 static DEFINE_SPINLOCK(nfs_client_lock);
50 static LIST_HEAD(nfs_client_list);
51 static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
52
53 /*
54  * RPC cruft for NFS
55  */
56 static struct rpc_version *nfs_version[5] = {
57         [2]                     = &nfs_version2,
58 #ifdef CONFIG_NFS_V3
59         [3]                     = &nfs_version3,
60 #endif
61 #ifdef CONFIG_NFS_V4
62         [4]                     = &nfs_version4,
63 #endif
64 };
65
66 struct rpc_program nfs_program = {
67         .name                   = "nfs",
68         .number                 = NFS_PROGRAM,
69         .nrvers                 = ARRAY_SIZE(nfs_version),
70         .version                = nfs_version,
71         .stats                  = &nfs_rpcstat,
72         .pipe_dir_name          = "/nfs",
73 };
74
75 struct rpc_stat nfs_rpcstat = {
76         .program                = &nfs_program
77 };
78
79
80 #ifdef CONFIG_NFS_V3_ACL
81 static struct rpc_stat          nfsacl_rpcstat = { &nfsacl_program };
82 static struct rpc_version *     nfsacl_version[] = {
83         [3]                     = &nfsacl_version3,
84 };
85
86 struct rpc_program              nfsacl_program = {
87         .name                   = "nfsacl",
88         .number                 = NFS_ACL_PROGRAM,
89         .nrvers                 = ARRAY_SIZE(nfsacl_version),
90         .version                = nfsacl_version,
91         .stats                  = &nfsacl_rpcstat,
92 };
93 #endif  /* CONFIG_NFS_V3_ACL */
94
95 /*
96  * Allocate a shared client record
97  *
98  * Since these are allocated/deallocated very rarely, we don't
99  * bother putting them in a slab cache...
100  */
101 static struct nfs_client *nfs_alloc_client(const char *hostname,
102                                            const struct sockaddr_in *addr,
103                                            int nfsversion)
104 {
105         struct nfs_client *clp;
106         int error;
107
108         if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
109                 goto error_0;
110
111         error = rpciod_up();
112         if (error < 0) {
113                 dprintk("%s: couldn't start rpciod! Error = %d\n",
114                                 __FUNCTION__, error);
115                 __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
116                 goto error_1;
117         }
118
119         if (nfsversion == 4) {
120                 if (nfs_callback_up() < 0)
121                         goto error_2;
122                 __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
123         }
124
125         atomic_set(&clp->cl_count, 1);
126         clp->cl_cons_state = NFS_CS_INITING;
127
128         clp->cl_nfsversion = nfsversion;
129         memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
130
131         if (hostname) {
132                 clp->cl_hostname = kstrdup(hostname, GFP_KERNEL);
133                 if (!clp->cl_hostname)
134                         goto error_3;
135         }
136
137         INIT_LIST_HEAD(&clp->cl_superblocks);
138         clp->cl_rpcclient = ERR_PTR(-EINVAL);
139
140 #ifdef CONFIG_NFS_V4
141         init_rwsem(&clp->cl_sem);
142         INIT_LIST_HEAD(&clp->cl_delegations);
143         INIT_LIST_HEAD(&clp->cl_state_owners);
144         INIT_LIST_HEAD(&clp->cl_unused);
145         spin_lock_init(&clp->cl_lock);
146         INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
147         rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
148         clp->cl_boot_time = CURRENT_TIME;
149         clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
150 #endif
151
152         return clp;
153
154 error_3:
155         nfs_callback_down();
156         __clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
157 error_2:
158         rpciod_down();
159         __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
160 error_1:
161         kfree(clp);
162 error_0:
163         return NULL;
164 }
165
166 /*
167  * Destroy a shared client record
168  */
169 static void nfs_free_client(struct nfs_client *clp)
170 {
171         dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion);
172
173 #ifdef CONFIG_NFS_V4
174         if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) {
175                 while (!list_empty(&clp->cl_unused)) {
176                         struct nfs4_state_owner *sp;
177
178                         sp = list_entry(clp->cl_unused.next,
179                                         struct nfs4_state_owner,
180                                         so_list);
181                         list_del(&sp->so_list);
182                         kfree(sp);
183                 }
184                 BUG_ON(!list_empty(&clp->cl_state_owners));
185                 nfs_idmap_delete(clp);
186         }
187 #endif
188
189         /* -EIO all pending I/O */
190         if (!IS_ERR(clp->cl_rpcclient))
191                 rpc_shutdown_client(clp->cl_rpcclient);
192
193         if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
194                 nfs_callback_down();
195
196         if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state))
197         rpciod_down();
198
199         kfree(clp->cl_hostname);
200         kfree(clp);
201
202         dprintk("<-- nfs_free_client()\n");
203 }
204
205 /*
206  * Release a reference to a shared client record
207  */
208 void nfs_put_client(struct nfs_client *clp)
209 {
210         dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
211
212         if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
213                 list_del(&clp->cl_share_link);
214                 spin_unlock(&nfs_client_lock);
215
216                 BUG_ON(!list_empty(&clp->cl_superblocks));
217
218                 nfs_free_client(clp);
219         }
220 }
221
222 /*
223  * Find a client by address
224  * - caller must hold nfs_client_lock
225  */
226 static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
227 {
228         struct nfs_client *clp;
229
230         list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
231                 /* Different NFS versions cannot share the same nfs_client */
232                 if (clp->cl_nfsversion != nfsversion)
233                         continue;
234
235                 if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr,
236                            sizeof(clp->cl_addr.sin_addr)) != 0)
237                         continue;
238
239                 if (clp->cl_addr.sin_port == addr->sin_port)
240                         goto found;
241         }
242
243         return NULL;
244
245 found:
246         atomic_inc(&clp->cl_count);
247         return clp;
248 }
249
250 /*
251  * Find a client by IP address and protocol version
252  * - returns NULL if no such client
253  */
254 struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
255 {
256         struct nfs_client *clp;
257
258         spin_lock(&nfs_client_lock);
259         clp = __nfs_find_client(addr, nfsversion);
260         spin_unlock(&nfs_client_lock);
261
262         BUG_ON(clp->cl_cons_state == 0);
263
264         return clp;
265 }
266
267 /*
268  * Look up a client by IP address and protocol version
269  * - creates a new record if one doesn't yet exist
270  */
271 struct nfs_client *nfs_get_client(const char *hostname,
272                                   const struct sockaddr_in *addr,
273                                   int nfsversion)
274 {
275         struct nfs_client *clp, *new = NULL;
276         int error;
277
278         dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n",
279                 hostname ?: "", NIPQUAD(addr->sin_addr),
280                 addr->sin_port, nfsversion);
281
282         /* see if the client already exists */
283         do {
284                 spin_lock(&nfs_client_lock);
285
286                 clp = __nfs_find_client(addr, nfsversion);
287                 if (clp)
288                         goto found_client;
289                 if (new)
290                         goto install_client;
291
292                 spin_unlock(&nfs_client_lock);
293
294                 new = nfs_alloc_client(hostname, addr, nfsversion);
295         } while (new);
296
297         return ERR_PTR(-ENOMEM);
298
299         /* install a new client and return with it unready */
300 install_client:
301         clp = new;
302         list_add(&clp->cl_share_link, &nfs_client_list);
303         spin_unlock(&nfs_client_lock);
304         dprintk("--> nfs_get_client() = %p [new]\n", clp);
305         return clp;
306
307         /* found an existing client
308          * - make sure it's ready before returning
309          */
310 found_client:
311         spin_unlock(&nfs_client_lock);
312
313         if (new)
314                 nfs_free_client(new);
315
316         if (clp->cl_cons_state == NFS_CS_INITING) {
317                 DECLARE_WAITQUEUE(myself, current);
318
319                 add_wait_queue(&nfs_client_active_wq, &myself);
320
321                 for (;;) {
322                         set_current_state(TASK_INTERRUPTIBLE);
323                         if (signal_pending(current) ||
324                             clp->cl_cons_state > NFS_CS_READY)
325                                 break;
326                         schedule();
327                 }
328
329                 remove_wait_queue(&nfs_client_active_wq, &myself);
330
331                 if (signal_pending(current)) {
332                         nfs_put_client(clp);
333                         return ERR_PTR(-ERESTARTSYS);
334                 }
335         }
336
337         if (clp->cl_cons_state < NFS_CS_READY) {
338                 error = clp->cl_cons_state;
339                 nfs_put_client(clp);
340                 return ERR_PTR(error);
341         }
342
343         dprintk("--> nfs_get_client() = %p [share]\n", clp);
344         return clp;
345 }
346
347 /*
348  * Mark a server as ready or failed
349  */
350 void nfs_mark_client_ready(struct nfs_client *clp, int state)
351 {
352         clp->cl_cons_state = state;
353         wake_up_all(&nfs_client_active_wq);
354 }
355
356 /*
357  * Initialise the timeout values for a connection
358  */
359 static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
360                                     unsigned int timeo, unsigned int retrans)
361 {
362         to->to_initval = timeo * HZ / 10;
363         to->to_retries = retrans;
364         if (!to->to_retries)
365                 to->to_retries = 2;
366
367         switch (proto) {
368         case IPPROTO_TCP:
369                 if (!to->to_initval)
370                         to->to_initval = 60 * HZ;
371                 if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
372                         to->to_initval = NFS_MAX_TCP_TIMEOUT;
373                 to->to_increment = to->to_initval;
374                 to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
375                 to->to_exponential = 0;
376                 break;
377         case IPPROTO_UDP:
378         default:
379                 if (!to->to_initval)
380                         to->to_initval = 11 * HZ / 10;
381                 if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
382                         to->to_initval = NFS_MAX_UDP_TIMEOUT;
383                 to->to_maxval = NFS_MAX_UDP_TIMEOUT;
384                 to->to_exponential = 1;
385                 break;
386         }
387 }
388
389 /*
390  * Create an RPC client handle
391  */
392 int nfs_create_rpc_client(struct nfs_client *clp, int proto,
393                           unsigned int timeo,
394                           unsigned int retrans,
395                           rpc_authflavor_t flavor)
396 {
397         struct rpc_timeout      timeparms;
398         struct rpc_xprt         *xprt = NULL;
399         struct rpc_clnt         *clnt = NULL;
400
401         if (!IS_ERR(clp->cl_rpcclient))
402                 return 0;
403
404         nfs_init_timeout_values(&timeparms, proto, timeo, retrans);
405         clp->retrans_timeo = timeparms.to_initval;
406         clp->retrans_count = timeparms.to_retries;
407
408         /* create transport and client */
409         xprt = xprt_create_proto(proto, &clp->cl_addr, &timeparms);
410         if (IS_ERR(xprt)) {
411                 dprintk("%s: cannot create RPC transport. Error = %ld\n",
412                                 __FUNCTION__, PTR_ERR(xprt));
413                 return PTR_ERR(xprt);
414         }
415
416         /* Bind to a reserved port! */
417         xprt->resvport = 1;
418         /* Create the client RPC handle */
419         clnt = rpc_create_client(xprt, clp->cl_hostname, &nfs_program,
420                                  clp->rpc_ops->version, RPC_AUTH_UNIX);
421         if (IS_ERR(clnt)) {
422                 dprintk("%s: cannot create RPC client. Error = %ld\n",
423                                 __FUNCTION__, PTR_ERR(clnt));
424                 return PTR_ERR(clnt);
425         }
426
427         clnt->cl_intr     = 1;
428         clnt->cl_softrtry = 1;
429         clp->cl_rpcclient = clnt;
430         return 0;
431 }