Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
3 : : * Written by David Howells (dhowells@redhat.com)
4 : : */
5 : : #include <linux/module.h>
6 : : #include <linux/nfs_fs.h>
7 : : #include <linux/nfs_idmap.h>
8 : : #include <linux/nfs_mount.h>
9 : : #include <linux/sunrpc/addr.h>
10 : : #include <linux/sunrpc/auth.h>
11 : : #include <linux/sunrpc/xprt.h>
12 : : #include <linux/sunrpc/bc_xprt.h>
13 : : #include "internal.h"
14 : : #include "callback.h"
15 : : #include "delegation.h"
16 : : #include "nfs4session.h"
17 : : #include "pnfs.h"
18 : : #include "netns.h"
19 : :
20 : : #define NFSDBG_FACILITY NFSDBG_CLIENT
21 : :
22 : : /*
23 : : * Get a unique NFSv4.0 callback identifier which will be used
24 : : * by the V4.0 callback service to lookup the nfs_client struct
25 : : */
26 : 0 : static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
27 : : {
28 : : int ret = 0;
29 : 0 : struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
30 : :
31 [ # # ][ # # ]: 0 : if (clp->rpc_ops->version != 4 || minorversion != 0)
32 : : return ret;
33 : 0 : idr_preload(GFP_KERNEL);
34 : : spin_lock(&nn->nfs_client_lock);
35 : 0 : ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
36 [ # # ]: 0 : if (ret >= 0)
37 : 0 : clp->cl_cb_ident = ret;
38 : : spin_unlock(&nn->nfs_client_lock);
39 : : idr_preload_end();
40 : 0 : return ret < 0 ? ret : 0;
41 : : }
42 : :
43 : : #ifdef CONFIG_NFS_V4_1
44 : : /**
45 : : * Per auth flavor data server rpc clients
46 : : */
47 : : struct nfs4_ds_server {
48 : : struct list_head list; /* ds_clp->cl_ds_clients */
49 : : struct rpc_clnt *rpc_clnt;
50 : : };
51 : :
52 : : /**
53 : : * Common lookup case for DS I/O
54 : : */
55 : : static struct nfs4_ds_server *
56 : : nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
57 : : {
58 : : struct nfs4_ds_server *dss;
59 : :
60 : : rcu_read_lock();
61 : : list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) {
62 : : if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
63 : : continue;
64 : : goto out;
65 : : }
66 : : dss = NULL;
67 : : out:
68 : : rcu_read_unlock();
69 : : return dss;
70 : : }
71 : :
72 : : static struct nfs4_ds_server *
73 : : nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor,
74 : : struct nfs4_ds_server *new)
75 : : {
76 : : struct nfs4_ds_server *dss;
77 : :
78 : : spin_lock(&ds_clp->cl_lock);
79 : : list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) {
80 : : if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
81 : : continue;
82 : : goto out;
83 : : }
84 : : if (new)
85 : : list_add_rcu(&new->list, &ds_clp->cl_ds_clients);
86 : : dss = new;
87 : : out:
88 : : spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */
89 : : return dss;
90 : : }
91 : :
92 : : static struct nfs4_ds_server *
93 : : nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
94 : : {
95 : : struct nfs4_ds_server *dss;
96 : :
97 : : dss = kmalloc(sizeof(*dss), GFP_NOFS);
98 : : if (dss == NULL)
99 : : return ERR_PTR(-ENOMEM);
100 : :
101 : : dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor);
102 : : if (IS_ERR(dss->rpc_clnt)) {
103 : : int err = PTR_ERR(dss->rpc_clnt);
104 : : kfree (dss);
105 : : return ERR_PTR(err);
106 : : }
107 : : INIT_LIST_HEAD(&dss->list);
108 : :
109 : : return dss;
110 : : }
111 : :
112 : : static void
113 : : nfs4_free_ds_server(struct nfs4_ds_server *dss)
114 : : {
115 : : rpc_release_client(dss->rpc_clnt);
116 : : kfree(dss);
117 : : }
118 : :
119 : : /**
120 : : * Find or create a DS rpc client with th MDS server rpc client auth flavor
121 : : * in the nfs_client cl_ds_clients list.
122 : : */
123 : : struct rpc_clnt *
124 : : nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode)
125 : : {
126 : : struct nfs4_ds_server *dss, *new;
127 : : rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor;
128 : :
129 : : dss = nfs4_find_ds_client(ds_clp, flavor);
130 : : if (dss != NULL)
131 : : goto out;
132 : : new = nfs4_alloc_ds_server(ds_clp, flavor);
133 : : if (IS_ERR(new))
134 : : return ERR_CAST(new);
135 : : dss = nfs4_add_ds_client(ds_clp, flavor, new);
136 : : if (dss != new)
137 : : nfs4_free_ds_server(new);
138 : : out:
139 : : return dss->rpc_clnt;
140 : : }
141 : : EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client);
142 : :
143 : : static void
144 : : nfs4_shutdown_ds_clients(struct nfs_client *clp)
145 : : {
146 : : struct nfs4_ds_server *dss;
147 : : LIST_HEAD(shutdown_list);
148 : :
149 : : while (!list_empty(&clp->cl_ds_clients)) {
150 : : dss = list_entry(clp->cl_ds_clients.next,
151 : : struct nfs4_ds_server, list);
152 : : list_del(&dss->list);
153 : : rpc_shutdown_client(dss->rpc_clnt);
154 : : kfree (dss);
155 : : }
156 : : }
157 : :
158 : : void nfs41_shutdown_client(struct nfs_client *clp)
159 : : {
160 : : if (nfs4_has_session(clp)) {
161 : : nfs4_shutdown_ds_clients(clp);
162 : : nfs4_destroy_session(clp->cl_session);
163 : : nfs4_destroy_clientid(clp);
164 : : }
165 : :
166 : : }
167 : : #endif /* CONFIG_NFS_V4_1 */
168 : :
169 : 0 : void nfs40_shutdown_client(struct nfs_client *clp)
170 : : {
171 [ # # ]: 0 : if (clp->cl_slot_tbl) {
172 : 0 : nfs4_release_slot_table(clp->cl_slot_tbl);
173 : 0 : kfree(clp->cl_slot_tbl);
174 : : }
175 : 0 : }
176 : :
177 : 0 : struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
178 : : {
179 : : int err;
180 : 0 : struct nfs_client *clp = nfs_alloc_client(cl_init);
181 [ # # ]: 0 : if (IS_ERR(clp))
182 : : return clp;
183 : :
184 : 0 : err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
185 [ # # ]: 0 : if (err)
186 : : goto error;
187 : :
188 [ # # ]: 0 : if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
189 : : err = -EINVAL;
190 : : goto error;
191 : : }
192 : :
193 : 0 : spin_lock_init(&clp->cl_lock);
194 : 0 : INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
195 : 0 : INIT_LIST_HEAD(&clp->cl_ds_clients);
196 : 0 : rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
197 : 0 : clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
198 : 0 : clp->cl_minorversion = cl_init->minorversion;
199 : 0 : clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
200 : 0 : clp->cl_mig_gen = 1;
201 : 0 : return clp;
202 : :
203 : : error:
204 : 0 : nfs_free_client(clp);
205 : 0 : return ERR_PTR(err);
206 : : }
207 : :
208 : : /*
209 : : * Destroy the NFS4 callback service
210 : : */
211 : 0 : static void nfs4_destroy_callback(struct nfs_client *clp)
212 : : {
213 [ # # ]: 0 : if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
214 : 0 : nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
215 : 0 : }
216 : :
217 : 0 : static void nfs4_shutdown_client(struct nfs_client *clp)
218 : : {
219 [ # # ]: 0 : if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
220 : 0 : nfs4_kill_renewd(clp);
221 : 0 : clp->cl_mvops->shutdown_client(clp);
222 : 0 : nfs4_destroy_callback(clp);
223 [ # # ]: 0 : if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
224 : 0 : nfs_idmap_delete(clp);
225 : :
226 : 0 : rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
227 : 0 : kfree(clp->cl_serverowner);
228 : 0 : kfree(clp->cl_serverscope);
229 : 0 : kfree(clp->cl_implid);
230 : 0 : }
231 : :
232 : 0 : void nfs4_free_client(struct nfs_client *clp)
233 : : {
234 : 0 : nfs4_shutdown_client(clp);
235 : 0 : nfs_free_client(clp);
236 : 0 : }
237 : :
238 : : /*
239 : : * Initialize the NFS4 callback service
240 : : */
241 : 0 : static int nfs4_init_callback(struct nfs_client *clp)
242 : : {
243 : : int error;
244 : :
245 [ # # ]: 0 : if (clp->rpc_ops->version == 4) {
246 : : struct rpc_xprt *xprt;
247 : :
248 : 0 : xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
249 : :
250 : : if (nfs4_has_session(clp)) {
251 : : error = xprt_setup_backchannel(xprt,
252 : : NFS41_BC_MIN_CALLBACKS);
253 : : if (error < 0)
254 : : return error;
255 : : }
256 : :
257 : 0 : error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
258 [ # # ]: 0 : if (error < 0) {
259 : : dprintk("%s: failed to start callback. Error = %d\n",
260 : : __func__, error);
261 : : return error;
262 : : }
263 : : __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
264 : : }
265 : : return 0;
266 : : }
267 : :
268 : : /**
269 : : * nfs40_init_client - nfs_client initialization tasks for NFSv4.0
270 : : * @clp - nfs_client to initialize
271 : : *
272 : : * Returns zero on success, or a negative errno if some error occurred.
273 : : */
274 : 0 : int nfs40_init_client(struct nfs_client *clp)
275 : : {
276 : : struct nfs4_slot_table *tbl;
277 : : int ret;
278 : :
279 : : tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
280 [ # # ]: 0 : if (tbl == NULL)
281 : : return -ENOMEM;
282 : :
283 : 0 : ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
284 : : "NFSv4.0 transport Slot table");
285 [ # # ]: 0 : if (ret) {
286 : 0 : kfree(tbl);
287 : 0 : return ret;
288 : : }
289 : :
290 : 0 : clp->cl_slot_tbl = tbl;
291 : 0 : return 0;
292 : : }
293 : :
294 : : #if defined(CONFIG_NFS_V4_1)
295 : :
296 : : /**
297 : : * nfs41_init_client - nfs_client initialization tasks for NFSv4.1+
298 : : * @clp - nfs_client to initialize
299 : : *
300 : : * Returns zero on success, or a negative errno if some error occurred.
301 : : */
302 : : int nfs41_init_client(struct nfs_client *clp)
303 : : {
304 : : struct nfs4_session *session = NULL;
305 : :
306 : : /*
307 : : * Create the session and mark it expired.
308 : : * When a SEQUENCE operation encounters the expired session
309 : : * it will do session recovery to initialize it.
310 : : */
311 : : session = nfs4_alloc_session(clp);
312 : : if (!session)
313 : : return -ENOMEM;
314 : :
315 : : clp->cl_session = session;
316 : :
317 : : /*
318 : : * The create session reply races with the server back
319 : : * channel probe. Mark the client NFS_CS_SESSION_INITING
320 : : * so that the client back channel can find the
321 : : * nfs_client struct
322 : : */
323 : : nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
324 : : return 0;
325 : : }
326 : :
327 : : #endif /* CONFIG_NFS_V4_1 */
328 : :
329 : : /*
330 : : * Initialize the minor version specific parts of an NFS4 client record
331 : : */
332 : 0 : static int nfs4_init_client_minor_version(struct nfs_client *clp)
333 : : {
334 : : int ret;
335 : :
336 : 0 : ret = clp->cl_mvops->init_client(clp);
337 [ # # ]: 0 : if (ret)
338 : : return ret;
339 : 0 : return nfs4_init_callback(clp);
340 : : }
341 : :
342 : : /**
343 : : * nfs4_init_client - Initialise an NFS4 client record
344 : : *
345 : : * @clp: nfs_client to initialise
346 : : * @timeparms: timeout parameters for underlying RPC transport
347 : : * @ip_addr: callback IP address in presentation format
348 : : * @authflavor: authentication flavor for underlying RPC transport
349 : : *
350 : : * Returns pointer to an NFS client, or an ERR_PTR value.
351 : : */
352 : 0 : struct nfs_client *nfs4_init_client(struct nfs_client *clp,
353 : : const struct rpc_timeout *timeparms,
354 : : const char *ip_addr)
355 : : {
356 : : char buf[INET6_ADDRSTRLEN + 1];
357 : : struct nfs_client *old;
358 : : int error;
359 : :
360 [ # # ]: 0 : if (clp->cl_cons_state == NFS_CS_READY) {
361 : : /* the client is initialised already */
362 : : dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
363 : : return clp;
364 : : }
365 : :
366 : : /* Check NFS protocol revision and initialize RPC op vector */
367 : 0 : clp->rpc_ops = &nfs_v4_clientops;
368 : :
369 [ # # ]: 0 : if (clp->cl_minorversion != 0)
370 : : __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
371 : : __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
372 : : __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
373 : 0 : error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
374 [ # # ]: 0 : if (error == -EINVAL)
375 : 0 : error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
376 [ # # ]: 0 : if (error < 0)
377 : : goto error;
378 : :
379 : : /* If no clientaddr= option was specified, find a usable cb address */
380 [ # # ]: 0 : if (ip_addr == NULL) {
381 : : struct sockaddr_storage cb_addr;
382 : : struct sockaddr *sap = (struct sockaddr *)&cb_addr;
383 : :
384 : 0 : error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
385 [ # # ]: 0 : if (error < 0)
386 : : goto error;
387 : 0 : error = rpc_ntop(sap, buf, sizeof(buf));
388 [ # # ]: 0 : if (error < 0)
389 : : goto error;
390 : : ip_addr = (const char *)buf;
391 : : }
392 : 0 : strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
393 : :
394 : 0 : error = nfs_idmap_new(clp);
395 [ # # ]: 0 : if (error < 0) {
396 : : dprintk("%s: failed to create idmapper. Error = %d\n",
397 : : __func__, error);
398 : : goto error;
399 : : }
400 : : __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
401 : :
402 : 0 : error = nfs4_init_client_minor_version(clp);
403 [ # # ]: 0 : if (error < 0)
404 : : goto error;
405 : :
406 : : if (!nfs4_has_session(clp))
407 : 0 : nfs_mark_client_ready(clp, NFS_CS_READY);
408 : :
409 : 0 : error = nfs4_discover_server_trunking(clp, &old);
410 [ # # ]: 0 : if (error < 0)
411 : : goto error;
412 : 0 : nfs_put_client(clp);
413 [ # # ]: 0 : if (clp != old) {
414 : 0 : clp->cl_preserve_clid = true;
415 : : clp = old;
416 : : }
417 : :
418 : 0 : return clp;
419 : :
420 : : error:
421 : 0 : nfs_mark_client_ready(clp, error);
422 : 0 : nfs_put_client(clp);
423 : : dprintk("<-- nfs4_init_client() = xerror %d\n", error);
424 : 0 : return ERR_PTR(error);
425 : : }
426 : :
427 : : /*
428 : : * SETCLIENTID just did a callback update with the callback ident in
429 : : * "drop," but server trunking discovery claims "drop" and "keep" are
430 : : * actually the same server. Swap the callback IDs so that "keep"
431 : : * will continue to use the callback ident the server now knows about,
432 : : * and so that "keep"'s original callback ident is destroyed when
433 : : * "drop" is freed.
434 : : */
435 : 0 : static void nfs4_swap_callback_idents(struct nfs_client *keep,
436 : : struct nfs_client *drop)
437 : : {
438 : 0 : struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
439 : 0 : unsigned int save = keep->cl_cb_ident;
440 : :
441 [ # # ]: 0 : if (keep->cl_cb_ident == drop->cl_cb_ident)
442 : 0 : return;
443 : :
444 : : dprintk("%s: keeping callback ident %u and dropping ident %u\n",
445 : : __func__, keep->cl_cb_ident, drop->cl_cb_ident);
446 : :
447 : : spin_lock(&nn->nfs_client_lock);
448 : :
449 : 0 : idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
450 : 0 : keep->cl_cb_ident = drop->cl_cb_ident;
451 : :
452 : 0 : idr_replace(&nn->cb_ident_idr, drop, save);
453 : 0 : drop->cl_cb_ident = save;
454 : :
455 : : spin_unlock(&nn->nfs_client_lock);
456 : : }
457 : :
458 : : /**
459 : : * nfs40_walk_client_list - Find server that recognizes a client ID
460 : : *
461 : : * @new: nfs_client with client ID to test
462 : : * @result: OUT: found nfs_client, or new
463 : : * @cred: credential to use for trunking test
464 : : *
465 : : * Returns zero, a negative errno, or a negative NFS4ERR status.
466 : : * If zero is returned, an nfs_client pointer is planted in "result."
467 : : *
468 : : * NB: nfs40_walk_client_list() relies on the new nfs_client being
469 : : * the last nfs_client on the list.
470 : : */
471 : 0 : int nfs40_walk_client_list(struct nfs_client *new,
472 : : struct nfs_client **result,
473 : : struct rpc_cred *cred)
474 : : {
475 : 0 : struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
476 : : struct nfs_client *pos, *prev = NULL;
477 : 0 : struct nfs4_setclientid_res clid = {
478 : 0 : .clientid = new->cl_clientid,
479 : : .confirm = new->cl_confirm,
480 : : };
481 : : int status = -NFS4ERR_STALE_CLIENTID;
482 : :
483 : : spin_lock(&nn->nfs_client_lock);
484 [ # # ]: 0 : list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
485 : : /* If "pos" isn't marked ready, we can't trust the
486 : : * remaining fields in "pos" */
487 [ # # ]: 0 : if (pos->cl_cons_state > NFS_CS_READY) {
488 : 0 : atomic_inc(&pos->cl_count);
489 : : spin_unlock(&nn->nfs_client_lock);
490 : :
491 [ # # ]: 0 : if (prev)
492 : 0 : nfs_put_client(prev);
493 : : prev = pos;
494 : :
495 : 0 : status = nfs_wait_client_init_complete(pos);
496 : : spin_lock(&nn->nfs_client_lock);
497 [ # # ]: 0 : if (status < 0)
498 : 0 : continue;
499 : : }
500 [ # # ]: 0 : if (pos->cl_cons_state != NFS_CS_READY)
501 : 0 : continue;
502 : :
503 [ # # ]: 0 : if (pos->rpc_ops != new->rpc_ops)
504 : 0 : continue;
505 : :
506 [ # # ]: 0 : if (pos->cl_proto != new->cl_proto)
507 : 0 : continue;
508 : :
509 [ # # ]: 0 : if (pos->cl_minorversion != new->cl_minorversion)
510 : 0 : continue;
511 : :
512 [ # # ]: 0 : if (pos->cl_clientid != new->cl_clientid)
513 : 0 : continue;
514 : :
515 : 0 : atomic_inc(&pos->cl_count);
516 : : spin_unlock(&nn->nfs_client_lock);
517 : :
518 [ # # ]: 0 : if (prev)
519 : 0 : nfs_put_client(prev);
520 : : prev = pos;
521 : :
522 : 0 : status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
523 [ # # # ]: 0 : switch (status) {
524 : : case -NFS4ERR_STALE_CLIENTID:
525 : : break;
526 : : case 0:
527 : 0 : nfs4_swap_callback_idents(pos, new);
528 : :
529 : : prev = NULL;
530 : 0 : *result = pos;
531 : : dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
532 : : __func__, pos, atomic_read(&pos->cl_count));
533 : : default:
534 : : goto out;
535 : : }
536 : :
537 : : spin_lock(&nn->nfs_client_lock);
538 : : }
539 : : spin_unlock(&nn->nfs_client_lock);
540 : :
541 : : /* No match found. The server lost our clientid */
542 : : out:
543 [ # # ]: 0 : if (prev)
544 : 0 : nfs_put_client(prev);
545 : : dprintk("NFS: <-- %s status = %d\n", __func__, status);
546 : 0 : return status;
547 : : }
548 : :
549 : : #ifdef CONFIG_NFS_V4_1
550 : : /*
551 : : * Returns true if the client IDs match
552 : : */
553 : : static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
554 : : {
555 : : if (a->cl_clientid != b->cl_clientid) {
556 : : dprintk("NFS: --> %s client ID %llx does not match %llx\n",
557 : : __func__, a->cl_clientid, b->cl_clientid);
558 : : return false;
559 : : }
560 : : dprintk("NFS: --> %s client ID %llx matches %llx\n",
561 : : __func__, a->cl_clientid, b->cl_clientid);
562 : : return true;
563 : : }
564 : :
565 : : /*
566 : : * Returns true if the server owners match
567 : : */
568 : : static bool
569 : : nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
570 : : {
571 : : struct nfs41_server_owner *o1 = a->cl_serverowner;
572 : : struct nfs41_server_owner *o2 = b->cl_serverowner;
573 : :
574 : : if (o1->minor_id != o2->minor_id) {
575 : : dprintk("NFS: --> %s server owner minor IDs do not match\n",
576 : : __func__);
577 : : return false;
578 : : }
579 : :
580 : : if (o1->major_id_sz != o2->major_id_sz)
581 : : goto out_major_mismatch;
582 : : if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
583 : : goto out_major_mismatch;
584 : :
585 : : dprintk("NFS: --> %s server owners match\n", __func__);
586 : : return true;
587 : :
588 : : out_major_mismatch:
589 : : dprintk("NFS: --> %s server owner major IDs do not match\n",
590 : : __func__);
591 : : return false;
592 : : }
593 : :
594 : : /**
595 : : * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
596 : : *
597 : : * @new: nfs_client with client ID to test
598 : : * @result: OUT: found nfs_client, or new
599 : : * @cred: credential to use for trunking test
600 : : *
601 : : * Returns zero, a negative errno, or a negative NFS4ERR status.
602 : : * If zero is returned, an nfs_client pointer is planted in "result."
603 : : *
604 : : * NB: nfs41_walk_client_list() relies on the new nfs_client being
605 : : * the last nfs_client on the list.
606 : : */
607 : : int nfs41_walk_client_list(struct nfs_client *new,
608 : : struct nfs_client **result,
609 : : struct rpc_cred *cred)
610 : : {
611 : : struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
612 : : struct nfs_client *pos, *prev = NULL;
613 : : int status = -NFS4ERR_STALE_CLIENTID;
614 : :
615 : : spin_lock(&nn->nfs_client_lock);
616 : : list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
617 : : /* If "pos" isn't marked ready, we can't trust the
618 : : * remaining fields in "pos", especially the client
619 : : * ID and serverowner fields. Wait for CREATE_SESSION
620 : : * to finish. */
621 : : if (pos->cl_cons_state > NFS_CS_READY) {
622 : : atomic_inc(&pos->cl_count);
623 : : spin_unlock(&nn->nfs_client_lock);
624 : :
625 : : if (prev)
626 : : nfs_put_client(prev);
627 : : prev = pos;
628 : :
629 : : status = nfs_wait_client_init_complete(pos);
630 : : if (status == 0) {
631 : : nfs4_schedule_lease_recovery(pos);
632 : : status = nfs4_wait_clnt_recover(pos);
633 : : }
634 : : spin_lock(&nn->nfs_client_lock);
635 : : if (status < 0)
636 : : continue;
637 : : }
638 : : if (pos->cl_cons_state != NFS_CS_READY)
639 : : continue;
640 : :
641 : : if (pos->rpc_ops != new->rpc_ops)
642 : : continue;
643 : :
644 : : if (pos->cl_proto != new->cl_proto)
645 : : continue;
646 : :
647 : : if (pos->cl_minorversion != new->cl_minorversion)
648 : : continue;
649 : :
650 : : if (!nfs4_match_clientids(pos, new))
651 : : continue;
652 : :
653 : : if (!nfs4_match_serverowners(pos, new))
654 : : continue;
655 : :
656 : : atomic_inc(&pos->cl_count);
657 : : *result = pos;
658 : : status = 0;
659 : : dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
660 : : __func__, pos, atomic_read(&pos->cl_count));
661 : : break;
662 : : }
663 : :
664 : : /* No matching nfs_client found. */
665 : : spin_unlock(&nn->nfs_client_lock);
666 : : dprintk("NFS: <-- %s status = %d\n", __func__, status);
667 : : if (prev)
668 : : nfs_put_client(prev);
669 : : return status;
670 : : }
671 : : #endif /* CONFIG_NFS_V4_1 */
672 : :
673 : 0 : static void nfs4_destroy_server(struct nfs_server *server)
674 : : {
675 : 0 : nfs_server_return_all_delegations(server);
676 : : unset_pnfs_layoutdriver(server);
677 : 0 : nfs4_purge_state_owners(server);
678 : 0 : }
679 : :
680 : : /*
681 : : * NFSv4.0 callback thread helper
682 : : *
683 : : * Find a client by callback identifier
684 : : */
685 : : struct nfs_client *
686 : 0 : nfs4_find_client_ident(struct net *net, int cb_ident)
687 : : {
688 : : struct nfs_client *clp;
689 : 0 : struct nfs_net *nn = net_generic(net, nfs_net_id);
690 : :
691 : : spin_lock(&nn->nfs_client_lock);
692 : 0 : clp = idr_find(&nn->cb_ident_idr, cb_ident);
693 [ # # ]: 0 : if (clp)
694 : 0 : atomic_inc(&clp->cl_count);
695 : : spin_unlock(&nn->nfs_client_lock);
696 : 0 : return clp;
697 : : }
698 : :
699 : : #if defined(CONFIG_NFS_V4_1)
700 : : /* Common match routine for v4.0 and v4.1 callback services */
701 : : static bool nfs4_cb_match_client(const struct sockaddr *addr,
702 : : struct nfs_client *clp, u32 minorversion)
703 : : {
704 : : struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
705 : :
706 : : /* Don't match clients that failed to initialise */
707 : : if (!(clp->cl_cons_state == NFS_CS_READY ||
708 : : clp->cl_cons_state == NFS_CS_SESSION_INITING))
709 : : return false;
710 : :
711 : : smp_rmb();
712 : :
713 : : /* Match the version and minorversion */
714 : : if (clp->rpc_ops->version != 4 ||
715 : : clp->cl_minorversion != minorversion)
716 : : return false;
717 : :
718 : : /* Match only the IP address, not the port number */
719 : : if (!nfs_sockaddr_match_ipaddr(addr, clap))
720 : : return false;
721 : :
722 : : return true;
723 : : }
724 : :
725 : : /*
726 : : * NFSv4.1 callback thread helper
727 : : * For CB_COMPOUND calls, find a client by IP address, protocol version,
728 : : * minorversion, and sessionID
729 : : *
730 : : * Returns NULL if no such client
731 : : */
732 : : struct nfs_client *
733 : : nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
734 : : struct nfs4_sessionid *sid, u32 minorversion)
735 : : {
736 : : struct nfs_client *clp;
737 : : struct nfs_net *nn = net_generic(net, nfs_net_id);
738 : :
739 : : spin_lock(&nn->nfs_client_lock);
740 : : list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
741 : : if (nfs4_cb_match_client(addr, clp, minorversion) == false)
742 : : continue;
743 : :
744 : : if (!nfs4_has_session(clp))
745 : : continue;
746 : :
747 : : /* Match sessionid*/
748 : : if (memcmp(clp->cl_session->sess_id.data,
749 : : sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
750 : : continue;
751 : :
752 : : atomic_inc(&clp->cl_count);
753 : : spin_unlock(&nn->nfs_client_lock);
754 : : return clp;
755 : : }
756 : : spin_unlock(&nn->nfs_client_lock);
757 : : return NULL;
758 : : }
759 : :
760 : : #else /* CONFIG_NFS_V4_1 */
761 : :
762 : : struct nfs_client *
763 : 0 : nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
764 : : struct nfs4_sessionid *sid, u32 minorversion)
765 : : {
766 : 0 : return NULL;
767 : : }
768 : : #endif /* CONFIG_NFS_V4_1 */
769 : :
770 : : /*
771 : : * Set up an NFS4 client
772 : : */
773 : 0 : static int nfs4_set_client(struct nfs_server *server,
774 : : const char *hostname,
775 : : const struct sockaddr *addr,
776 : : const size_t addrlen,
777 : : const char *ip_addr,
778 : : rpc_authflavor_t authflavour,
779 : : int proto, const struct rpc_timeout *timeparms,
780 : : u32 minorversion, struct net *net)
781 : : {
782 : 0 : struct nfs_client_initdata cl_init = {
783 : : .hostname = hostname,
784 : : .addr = addr,
785 : : .addrlen = addrlen,
786 : : .nfs_mod = &nfs_v4,
787 : : .proto = proto,
788 : : .minorversion = minorversion,
789 : : .net = net,
790 : : };
791 : : struct nfs_client *clp;
792 : : int error;
793 : :
794 : : dprintk("--> nfs4_set_client()\n");
795 : :
796 [ # # ]: 0 : if (server->flags & NFS_MOUNT_NORESVPORT)
797 : 0 : set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
798 [ # # ]: 0 : if (server->options & NFS_OPTION_MIGRATION)
799 : 0 : set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
800 : :
801 : : /* Allocate or find a client reference we can use */
802 : 0 : clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour);
803 [ # # ]: 0 : if (IS_ERR(clp)) {
804 : : error = PTR_ERR(clp);
805 : : goto error;
806 : : }
807 : :
808 : : /*
809 : : * Query for the lease time on clientid setup or renewal
810 : : *
811 : : * Note that this will be set on nfs_clients that were created
812 : : * only for the DS role and did not set this bit, but now will
813 : : * serve a dual role.
814 : : */
815 : 0 : set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
816 : :
817 : 0 : server->nfs_client = clp;
818 : : dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
819 : 0 : return 0;
820 : : error:
821 : : dprintk("<-- nfs4_set_client() = xerror %d\n", error);
822 : 0 : return error;
823 : : }
824 : :
825 : : /*
826 : : * Set up a pNFS Data Server client.
827 : : *
828 : : * Return any existing nfs_client that matches server address,port,version
829 : : * and minorversion.
830 : : *
831 : : * For a new nfs_client, use a soft mount (default), a low retrans and a
832 : : * low timeout interval so that if a connection is lost, we retry through
833 : : * the MDS.
834 : : */
835 : 0 : struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
836 : : const struct sockaddr *ds_addr, int ds_addrlen,
837 : : int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans)
838 : : {
839 : 0 : struct nfs_client_initdata cl_init = {
840 : : .addr = ds_addr,
841 : : .addrlen = ds_addrlen,
842 : : .nfs_mod = &nfs_v4,
843 : : .proto = ds_proto,
844 : 0 : .minorversion = mds_clp->cl_minorversion,
845 : 0 : .net = mds_clp->cl_net,
846 : : };
847 : : struct rpc_timeout ds_timeout;
848 : : struct nfs_client *clp;
849 : :
850 : : /*
851 : : * Set an authflavor equual to the MDS value. Use the MDS nfs_client
852 : : * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
853 : : * (section 13.1 RFC 5661).
854 : : */
855 : 0 : nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
856 : 0 : clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
857 : 0 : mds_clp->cl_rpcclient->cl_auth->au_flavor);
858 : :
859 : : dprintk("<-- %s %p\n", __func__, clp);
860 : 0 : return clp;
861 : : }
862 : : EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
863 : :
864 : : /*
865 : : * Session has been established, and the client marked ready.
866 : : * Set the mount rsize and wsize with negotiated fore channel
867 : : * attributes which will be bound checked in nfs_server_set_fsinfo.
868 : : */
869 : : static void nfs4_session_set_rwsize(struct nfs_server *server)
870 : : {
871 : : #ifdef CONFIG_NFS_V4_1
872 : : struct nfs4_session *sess;
873 : : u32 server_resp_sz;
874 : : u32 server_rqst_sz;
875 : :
876 : : if (!nfs4_has_session(server->nfs_client))
877 : : return;
878 : : sess = server->nfs_client->cl_session;
879 : : server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
880 : : server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
881 : :
882 : : if (server->rsize > server_resp_sz)
883 : : server->rsize = server_resp_sz;
884 : : if (server->wsize > server_rqst_sz)
885 : : server->wsize = server_rqst_sz;
886 : : #endif /* CONFIG_NFS_V4_1 */
887 : : }
888 : :
889 : 0 : static int nfs4_server_common_setup(struct nfs_server *server,
890 : : struct nfs_fh *mntfh, bool auth_probe)
891 : : {
892 : : struct nfs_fattr *fattr;
893 : : int error;
894 : :
895 : : /* data servers support only a subset of NFSv4.1 */
896 : : if (is_ds_only_client(server->nfs_client))
897 : : return -EPROTONOSUPPORT;
898 : :
899 : 0 : fattr = nfs_alloc_fattr();
900 [ # # ]: 0 : if (fattr == NULL)
901 : : return -ENOMEM;
902 : :
903 : : /* We must ensure the session is initialised first */
904 : : error = nfs4_init_session(server->nfs_client);
905 : : if (error < 0)
906 : : goto out;
907 : :
908 : : /* Set the basic capabilities */
909 : 0 : server->caps |= server->nfs_client->cl_mvops->init_caps;
910 [ # # ]: 0 : if (server->flags & NFS_MOUNT_NORDIRPLUS)
911 : 0 : server->caps &= ~NFS_CAP_READDIRPLUS;
912 : : /*
913 : : * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
914 : : * authentication.
915 : : */
916 [ # # ][ # # ]: 0 : if (nfs4_disable_idmapping &&
917 : 0 : server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
918 : 0 : server->caps |= NFS_CAP_UIDGID_NOMAP;
919 : :
920 : :
921 : : /* Probe the root fh to retrieve its FSID and filehandle */
922 : 0 : error = nfs4_get_rootfh(server, mntfh, auth_probe);
923 [ # # ]: 0 : if (error < 0)
924 : : goto out;
925 : :
926 : : dprintk("Server FSID: %llx:%llx\n",
927 : : (unsigned long long) server->fsid.major,
928 : : (unsigned long long) server->fsid.minor);
929 : : nfs_display_fhandle(mntfh, "Pseudo-fs root FH");
930 : :
931 : : nfs4_session_set_rwsize(server);
932 : :
933 : 0 : error = nfs_probe_fsinfo(server, mntfh, fattr);
934 [ # # ]: 0 : if (error < 0)
935 : : goto out;
936 : :
937 [ # # ]: 0 : if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
938 : 0 : server->namelen = NFS4_MAXNAMLEN;
939 : :
940 : 0 : nfs_server_insert_lists(server);
941 : 0 : server->mount_time = jiffies;
942 : 0 : server->destroy = nfs4_destroy_server;
943 : : out:
944 : : nfs_free_fattr(fattr);
945 : 0 : return error;
946 : : }
947 : :
948 : : /*
949 : : * Create a version 4 volume record
950 : : */
951 : 0 : static int nfs4_init_server(struct nfs_server *server,
952 : : struct nfs_parsed_mount_data *data)
953 : : {
954 : : struct rpc_timeout timeparms;
955 : : int error;
956 : :
957 : : dprintk("--> nfs4_init_server()\n");
958 : :
959 : 0 : nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
960 : : data->timeo, data->retrans);
961 : :
962 : : /* Initialise the client representation from the mount data */
963 : 0 : server->flags = data->flags;
964 : 0 : server->options = data->options;
965 : 0 : server->auth_info = data->auth_info;
966 : :
967 : : /* Use the first specified auth flavor. If this flavor isn't
968 : : * allowed by the server, use the SECINFO path to try the
969 : : * other specified flavors */
970 [ # # ]: 0 : if (data->auth_info.flavor_len >= 1)
971 : 0 : data->selected_flavor = data->auth_info.flavors[0];
972 : : else
973 : 0 : data->selected_flavor = RPC_AUTH_UNIX;
974 : :
975 : : /* Get a client record */
976 : 0 : error = nfs4_set_client(server,
977 : 0 : data->nfs_server.hostname,
978 : 0 : (const struct sockaddr *)&data->nfs_server.address,
979 : : data->nfs_server.addrlen,
980 : 0 : data->client_address,
981 : : data->selected_flavor,
982 : 0 : data->nfs_server.protocol,
983 : : &timeparms,
984 : : data->minorversion,
985 : : data->net);
986 [ # # ]: 0 : if (error < 0)
987 : : goto error;
988 : :
989 [ # # ]: 0 : if (data->rsize)
990 : 0 : server->rsize = nfs_block_size(data->rsize, NULL);
991 [ # # ]: 0 : if (data->wsize)
992 : 0 : server->wsize = nfs_block_size(data->wsize, NULL);
993 : :
994 : 0 : server->acregmin = data->acregmin * HZ;
995 : 0 : server->acregmax = data->acregmax * HZ;
996 : 0 : server->acdirmin = data->acdirmin * HZ;
997 : 0 : server->acdirmax = data->acdirmax * HZ;
998 : :
999 : 0 : server->port = data->nfs_server.port;
1000 : :
1001 : 0 : error = nfs_init_server_rpcclient(server, &timeparms,
1002 : : data->selected_flavor);
1003 : :
1004 : : error:
1005 : : /* Done */
1006 : : dprintk("<-- nfs4_init_server() = %d\n", error);
1007 : 0 : return error;
1008 : : }
1009 : :
1010 : : /*
1011 : : * Create a version 4 volume record
1012 : : * - keyed on server and FSID
1013 : : */
1014 : : /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
1015 : : struct nfs_fh *mntfh)*/
1016 : 0 : struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
1017 : : struct nfs_subversion *nfs_mod)
1018 : : {
1019 : : struct nfs_server *server;
1020 : : bool auth_probe;
1021 : : int error;
1022 : :
1023 : : dprintk("--> nfs4_create_server()\n");
1024 : :
1025 : 0 : server = nfs_alloc_server();
1026 [ # # ]: 0 : if (!server)
1027 : : return ERR_PTR(-ENOMEM);
1028 : :
1029 : 0 : auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
1030 : :
1031 : : /* set up the general RPC client */
1032 : 0 : error = nfs4_init_server(server, mount_info->parsed);
1033 [ # # ]: 0 : if (error < 0)
1034 : : goto error;
1035 : :
1036 : 0 : error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
1037 [ # # ]: 0 : if (error < 0)
1038 : : goto error;
1039 : :
1040 : : dprintk("<-- nfs4_create_server() = %p\n", server);
1041 : : return server;
1042 : :
1043 : : error:
1044 : 0 : nfs_free_server(server);
1045 : : dprintk("<-- nfs4_create_server() = error %d\n", error);
1046 : 0 : return ERR_PTR(error);
1047 : : }
1048 : :
1049 : : /*
1050 : : * Create an NFS4 referral server record
1051 : : */
1052 : 0 : struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
1053 : : struct nfs_fh *mntfh)
1054 : : {
1055 : : struct nfs_client *parent_client;
1056 : : struct nfs_server *server, *parent_server;
1057 : : bool auth_probe;
1058 : : int error;
1059 : :
1060 : : dprintk("--> nfs4_create_referral_server()\n");
1061 : :
1062 : 0 : server = nfs_alloc_server();
1063 [ # # ]: 0 : if (!server)
1064 : : return ERR_PTR(-ENOMEM);
1065 : :
1066 : 0 : parent_server = NFS_SB(data->sb);
1067 : 0 : parent_client = parent_server->nfs_client;
1068 : :
1069 : : /* Initialise the client representation from the parent server */
1070 : 0 : nfs_server_copy_userdata(server, parent_server);
1071 : :
1072 : : /* Get a client representation.
1073 : : * Note: NFSv4 always uses TCP, */
1074 : 0 : error = nfs4_set_client(server, data->hostname,
1075 : 0 : data->addr,
1076 : : data->addrlen,
1077 : 0 : parent_client->cl_ipaddr,
1078 : : data->authflavor,
1079 : : rpc_protocol(parent_server->client),
1080 : 0 : parent_server->client->cl_timeout,
1081 : 0 : parent_client->cl_mvops->minor_version,
1082 : : parent_client->cl_net);
1083 [ # # ]: 0 : if (error < 0)
1084 : : goto error;
1085 : :
1086 : 0 : error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
1087 [ # # ]: 0 : if (error < 0)
1088 : : goto error;
1089 : :
1090 : 0 : auth_probe = parent_server->auth_info.flavor_len < 1;
1091 : :
1092 : 0 : error = nfs4_server_common_setup(server, mntfh, auth_probe);
1093 [ # # ]: 0 : if (error < 0)
1094 : : goto error;
1095 : :
1096 : : dprintk("<-- nfs_create_referral_server() = %p\n", server);
1097 : : return server;
1098 : :
1099 : : error:
1100 : 0 : nfs_free_server(server);
1101 : : dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
1102 : 0 : return ERR_PTR(error);
1103 : : }
1104 : :
1105 : : /*
1106 : : * Grab the destination's particulars, including lease expiry time.
1107 : : *
1108 : : * Returns zero if probe succeeded and retrieved FSID matches the FSID
1109 : : * we have cached.
1110 : : */
1111 : 0 : static int nfs_probe_destination(struct nfs_server *server)
1112 : : {
1113 : 0 : struct inode *inode = server->super->s_root->d_inode;
1114 : : struct nfs_fattr *fattr;
1115 : : int error;
1116 : :
1117 : 0 : fattr = nfs_alloc_fattr();
1118 [ # # ]: 0 : if (fattr == NULL)
1119 : : return -ENOMEM;
1120 : :
1121 : : /* Sanity: the probe won't work if the destination server
1122 : : * does not recognize the migrated FH. */
1123 : 0 : error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr);
1124 : :
1125 : : nfs_free_fattr(fattr);
1126 : 0 : return error;
1127 : : }
1128 : :
1129 : : /**
1130 : : * nfs4_update_server - Move an nfs_server to a different nfs_client
1131 : : *
1132 : : * @server: represents FSID to be moved
1133 : : * @hostname: new end-point's hostname
1134 : : * @sap: new end-point's socket address
1135 : : * @salen: size of "sap"
1136 : : *
1137 : : * The nfs_server must be quiescent before this function is invoked.
1138 : : * Either its session is drained (NFSv4.1+), or its transport is
1139 : : * plugged and drained (NFSv4.0).
1140 : : *
1141 : : * Returns zero on success, or a negative errno value.
1142 : : */
1143 : 0 : int nfs4_update_server(struct nfs_server *server, const char *hostname,
1144 : : struct sockaddr *sap, size_t salen)
1145 : : {
1146 : 0 : struct nfs_client *clp = server->nfs_client;
1147 : 0 : struct rpc_clnt *clnt = server->client;
1148 : 0 : struct xprt_create xargs = {
1149 : 0 : .ident = clp->cl_proto,
1150 : : .net = &init_net,
1151 : : .dstaddr = sap,
1152 : : .addrlen = salen,
1153 : : .servername = hostname,
1154 : : };
1155 : : char buf[INET6_ADDRSTRLEN + 1];
1156 : : struct sockaddr_storage address;
1157 : : struct sockaddr *localaddr = (struct sockaddr *)&address;
1158 : : int error;
1159 : :
1160 : : dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
1161 : : (unsigned long long)server->fsid.major,
1162 : : (unsigned long long)server->fsid.minor,
1163 : : hostname);
1164 : :
1165 : 0 : error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
1166 [ # # ]: 0 : if (error != 0) {
1167 : : dprintk("<-- %s(): rpc_switch_client_transport returned %d\n",
1168 : : __func__, error);
1169 : : goto out;
1170 : : }
1171 : :
1172 : 0 : error = rpc_localaddr(clnt, localaddr, sizeof(address));
1173 [ # # ]: 0 : if (error != 0) {
1174 : : dprintk("<-- %s(): rpc_localaddr returned %d\n",
1175 : : __func__, error);
1176 : : goto out;
1177 : : }
1178 : :
1179 : : error = -EAFNOSUPPORT;
1180 [ # # ]: 0 : if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
1181 : : dprintk("<-- %s(): rpc_ntop returned %d\n",
1182 : : __func__, error);
1183 : : goto out;
1184 : : }
1185 : :
1186 : 0 : nfs_server_remove_lists(server);
1187 : 0 : error = nfs4_set_client(server, hostname, sap, salen, buf,
1188 : 0 : clp->cl_rpcclient->cl_auth->au_flavor,
1189 : : clp->cl_proto, clnt->cl_timeout,
1190 : : clp->cl_minorversion, clp->cl_net);
1191 : 0 : nfs_put_client(clp);
1192 [ # # ]: 0 : if (error != 0) {
1193 : 0 : nfs_server_insert_lists(server);
1194 : : dprintk("<-- %s(): nfs4_set_client returned %d\n",
1195 : : __func__, error);
1196 : 0 : goto out;
1197 : : }
1198 : :
1199 [ # # ]: 0 : if (server->nfs_client->cl_hostname == NULL)
1200 : 0 : server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
1201 : 0 : nfs_server_insert_lists(server);
1202 : :
1203 : 0 : error = nfs_probe_destination(server);
1204 : : if (error < 0)
1205 : : goto out;
1206 : :
1207 : : dprintk("<-- %s() succeeded\n", __func__);
1208 : :
1209 : : out:
1210 : 0 : return error;
1211 : : }
|