xref: /openbmc/linux/fs/nfs/nfs4client.c (revision 97da55fc)
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 static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
27 {
28 	int ret = 0;
29 	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
30 
31 	if (clp->rpc_ops->version != 4 || minorversion != 0)
32 		return ret;
33 	idr_preload(GFP_KERNEL);
34 	spin_lock(&nn->nfs_client_lock);
35 	ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
36 	if (ret >= 0)
37 		clp->cl_cb_ident = ret;
38 	spin_unlock(&nn->nfs_client_lock);
39 	idr_preload_end();
40 	return ret < 0 ? ret : 0;
41 }
42 
43 #ifdef CONFIG_NFS_V4_1
44 static void nfs4_shutdown_session(struct nfs_client *clp)
45 {
46 	if (nfs4_has_session(clp)) {
47 		nfs4_destroy_session(clp->cl_session);
48 		nfs4_destroy_clientid(clp);
49 	}
50 
51 }
52 #else /* CONFIG_NFS_V4_1 */
53 static void nfs4_shutdown_session(struct nfs_client *clp)
54 {
55 }
56 #endif /* CONFIG_NFS_V4_1 */
57 
58 struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
59 {
60 	int err;
61 	struct nfs_client *clp = nfs_alloc_client(cl_init);
62 	if (IS_ERR(clp))
63 		return clp;
64 
65 	err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
66 	if (err)
67 		goto error;
68 
69 	spin_lock_init(&clp->cl_lock);
70 	INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
71 	rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
72 	clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
73 	clp->cl_minorversion = cl_init->minorversion;
74 	clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
75 	return clp;
76 
77 error:
78 	nfs_free_client(clp);
79 	return ERR_PTR(err);
80 }
81 
82 /*
83  * Destroy the NFS4 callback service
84  */
85 static void nfs4_destroy_callback(struct nfs_client *clp)
86 {
87 	if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
88 		nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
89 }
90 
91 static void nfs4_shutdown_client(struct nfs_client *clp)
92 {
93 	if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
94 		nfs4_kill_renewd(clp);
95 	nfs4_shutdown_session(clp);
96 	nfs4_destroy_callback(clp);
97 	if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
98 		nfs_idmap_delete(clp);
99 
100 	rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
101 	kfree(clp->cl_serverowner);
102 	kfree(clp->cl_serverscope);
103 	kfree(clp->cl_implid);
104 }
105 
106 void nfs4_free_client(struct nfs_client *clp)
107 {
108 	nfs4_shutdown_client(clp);
109 	nfs_free_client(clp);
110 }
111 
112 /*
113  * Initialize the NFS4 callback service
114  */
115 static int nfs4_init_callback(struct nfs_client *clp)
116 {
117 	int error;
118 
119 	if (clp->rpc_ops->version == 4) {
120 		struct rpc_xprt *xprt;
121 
122 		xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
123 
124 		if (nfs4_has_session(clp)) {
125 			error = xprt_setup_backchannel(xprt,
126 						NFS41_BC_MIN_CALLBACKS);
127 			if (error < 0)
128 				return error;
129 		}
130 
131 		error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
132 		if (error < 0) {
133 			dprintk("%s: failed to start callback. Error = %d\n",
134 				__func__, error);
135 			return error;
136 		}
137 		__set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
138 	}
139 	return 0;
140 }
141 
142 /*
143  * Initialize the minor version specific parts of an NFS4 client record
144  */
145 static int nfs4_init_client_minor_version(struct nfs_client *clp)
146 {
147 #if defined(CONFIG_NFS_V4_1)
148 	if (clp->cl_mvops->minor_version) {
149 		struct nfs4_session *session = NULL;
150 		/*
151 		 * Create the session and mark it expired.
152 		 * When a SEQUENCE operation encounters the expired session
153 		 * it will do session recovery to initialize it.
154 		 */
155 		session = nfs4_alloc_session(clp);
156 		if (!session)
157 			return -ENOMEM;
158 
159 		clp->cl_session = session;
160 		/*
161 		 * The create session reply races with the server back
162 		 * channel probe. Mark the client NFS_CS_SESSION_INITING
163 		 * so that the client back channel can find the
164 		 * nfs_client struct
165 		 */
166 		nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
167 	}
168 #endif /* CONFIG_NFS_V4_1 */
169 
170 	return nfs4_init_callback(clp);
171 }
172 
173 /**
174  * nfs4_init_client - Initialise an NFS4 client record
175  *
176  * @clp: nfs_client to initialise
177  * @timeparms: timeout parameters for underlying RPC transport
178  * @ip_addr: callback IP address in presentation format
179  * @authflavor: authentication flavor for underlying RPC transport
180  *
181  * Returns pointer to an NFS client, or an ERR_PTR value.
182  */
183 struct nfs_client *nfs4_init_client(struct nfs_client *clp,
184 				    const struct rpc_timeout *timeparms,
185 				    const char *ip_addr,
186 				    rpc_authflavor_t authflavour)
187 {
188 	char buf[INET6_ADDRSTRLEN + 1];
189 	struct nfs_client *old;
190 	int error;
191 
192 	if (clp->cl_cons_state == NFS_CS_READY) {
193 		/* the client is initialised already */
194 		dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
195 		return clp;
196 	}
197 
198 	/* Check NFS protocol revision and initialize RPC op vector */
199 	clp->rpc_ops = &nfs_v4_clientops;
200 
201 	__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
202 	error = nfs_create_rpc_client(clp, timeparms, authflavour);
203 	if (error < 0)
204 		goto error;
205 
206 	/* If no clientaddr= option was specified, find a usable cb address */
207 	if (ip_addr == NULL) {
208 		struct sockaddr_storage cb_addr;
209 		struct sockaddr *sap = (struct sockaddr *)&cb_addr;
210 
211 		error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
212 		if (error < 0)
213 			goto error;
214 		error = rpc_ntop(sap, buf, sizeof(buf));
215 		if (error < 0)
216 			goto error;
217 		ip_addr = (const char *)buf;
218 	}
219 	strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
220 
221 	error = nfs_idmap_new(clp);
222 	if (error < 0) {
223 		dprintk("%s: failed to create idmapper. Error = %d\n",
224 			__func__, error);
225 		goto error;
226 	}
227 	__set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
228 
229 	error = nfs4_init_client_minor_version(clp);
230 	if (error < 0)
231 		goto error;
232 
233 	if (!nfs4_has_session(clp))
234 		nfs_mark_client_ready(clp, NFS_CS_READY);
235 
236 	error = nfs4_discover_server_trunking(clp, &old);
237 	if (error < 0)
238 		goto error;
239 	nfs_put_client(clp);
240 	if (clp != old) {
241 		clp->cl_preserve_clid = true;
242 		clp = old;
243 	}
244 
245 	return clp;
246 
247 error:
248 	nfs_mark_client_ready(clp, error);
249 	nfs_put_client(clp);
250 	dprintk("<-- nfs4_init_client() = xerror %d\n", error);
251 	return ERR_PTR(error);
252 }
253 
254 /*
255  * SETCLIENTID just did a callback update with the callback ident in
256  * "drop," but server trunking discovery claims "drop" and "keep" are
257  * actually the same server.  Swap the callback IDs so that "keep"
258  * will continue to use the callback ident the server now knows about,
259  * and so that "keep"'s original callback ident is destroyed when
260  * "drop" is freed.
261  */
262 static void nfs4_swap_callback_idents(struct nfs_client *keep,
263 				      struct nfs_client *drop)
264 {
265 	struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
266 	unsigned int save = keep->cl_cb_ident;
267 
268 	if (keep->cl_cb_ident == drop->cl_cb_ident)
269 		return;
270 
271 	dprintk("%s: keeping callback ident %u and dropping ident %u\n",
272 		__func__, keep->cl_cb_ident, drop->cl_cb_ident);
273 
274 	spin_lock(&nn->nfs_client_lock);
275 
276 	idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
277 	keep->cl_cb_ident = drop->cl_cb_ident;
278 
279 	idr_replace(&nn->cb_ident_idr, drop, save);
280 	drop->cl_cb_ident = save;
281 
282 	spin_unlock(&nn->nfs_client_lock);
283 }
284 
285 /**
286  * nfs40_walk_client_list - Find server that recognizes a client ID
287  *
288  * @new: nfs_client with client ID to test
289  * @result: OUT: found nfs_client, or new
290  * @cred: credential to use for trunking test
291  *
292  * Returns zero, a negative errno, or a negative NFS4ERR status.
293  * If zero is returned, an nfs_client pointer is planted in "result."
294  *
295  * NB: nfs40_walk_client_list() relies on the new nfs_client being
296  *     the last nfs_client on the list.
297  */
298 int nfs40_walk_client_list(struct nfs_client *new,
299 			   struct nfs_client **result,
300 			   struct rpc_cred *cred)
301 {
302 	struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
303 	struct nfs_client *pos, *n, *prev = NULL;
304 	struct nfs4_setclientid_res clid = {
305 		.clientid	= new->cl_clientid,
306 		.confirm	= new->cl_confirm,
307 	};
308 	int status = -NFS4ERR_STALE_CLIENTID;
309 
310 	spin_lock(&nn->nfs_client_lock);
311 	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
312 		/* If "pos" isn't marked ready, we can't trust the
313 		 * remaining fields in "pos" */
314 		if (pos->cl_cons_state < NFS_CS_READY)
315 			continue;
316 
317 		if (pos->rpc_ops != new->rpc_ops)
318 			continue;
319 
320 		if (pos->cl_proto != new->cl_proto)
321 			continue;
322 
323 		if (pos->cl_minorversion != new->cl_minorversion)
324 			continue;
325 
326 		if (pos->cl_clientid != new->cl_clientid)
327 			continue;
328 
329 		atomic_inc(&pos->cl_count);
330 		spin_unlock(&nn->nfs_client_lock);
331 
332 		if (prev)
333 			nfs_put_client(prev);
334 		prev = pos;
335 
336 		status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
337 		switch (status) {
338 		case -NFS4ERR_STALE_CLIENTID:
339 			break;
340 		case 0:
341 			nfs4_swap_callback_idents(pos, new);
342 
343 			prev = NULL;
344 			*result = pos;
345 			dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
346 				__func__, pos, atomic_read(&pos->cl_count));
347 		default:
348 			goto out;
349 		}
350 
351 		spin_lock(&nn->nfs_client_lock);
352 	}
353 	spin_unlock(&nn->nfs_client_lock);
354 
355 	/* No match found. The server lost our clientid */
356 out:
357 	if (prev)
358 		nfs_put_client(prev);
359 	dprintk("NFS: <-- %s status = %d\n", __func__, status);
360 	return status;
361 }
362 
363 #ifdef CONFIG_NFS_V4_1
364 /*
365  * Returns true if the client IDs match
366  */
367 static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
368 {
369 	if (a->cl_clientid != b->cl_clientid) {
370 		dprintk("NFS: --> %s client ID %llx does not match %llx\n",
371 			__func__, a->cl_clientid, b->cl_clientid);
372 		return false;
373 	}
374 	dprintk("NFS: --> %s client ID %llx matches %llx\n",
375 		__func__, a->cl_clientid, b->cl_clientid);
376 	return true;
377 }
378 
379 /*
380  * Returns true if the server owners match
381  */
382 static bool
383 nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
384 {
385 	struct nfs41_server_owner *o1 = a->cl_serverowner;
386 	struct nfs41_server_owner *o2 = b->cl_serverowner;
387 
388 	if (o1->minor_id != o2->minor_id) {
389 		dprintk("NFS: --> %s server owner minor IDs do not match\n",
390 			__func__);
391 		return false;
392 	}
393 
394 	if (o1->major_id_sz != o2->major_id_sz)
395 		goto out_major_mismatch;
396 	if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
397 		goto out_major_mismatch;
398 
399 	dprintk("NFS: --> %s server owners match\n", __func__);
400 	return true;
401 
402 out_major_mismatch:
403 	dprintk("NFS: --> %s server owner major IDs do not match\n",
404 		__func__);
405 	return false;
406 }
407 
408 /**
409  * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
410  *
411  * @new: nfs_client with client ID to test
412  * @result: OUT: found nfs_client, or new
413  * @cred: credential to use for trunking test
414  *
415  * Returns zero, a negative errno, or a negative NFS4ERR status.
416  * If zero is returned, an nfs_client pointer is planted in "result."
417  *
418  * NB: nfs41_walk_client_list() relies on the new nfs_client being
419  *     the last nfs_client on the list.
420  */
421 int nfs41_walk_client_list(struct nfs_client *new,
422 			   struct nfs_client **result,
423 			   struct rpc_cred *cred)
424 {
425 	struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
426 	struct nfs_client *pos, *n, *prev = NULL;
427 	int status = -NFS4ERR_STALE_CLIENTID;
428 
429 	spin_lock(&nn->nfs_client_lock);
430 	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
431 		/* If "pos" isn't marked ready, we can't trust the
432 		 * remaining fields in "pos", especially the client
433 		 * ID and serverowner fields.  Wait for CREATE_SESSION
434 		 * to finish. */
435 		if (pos->cl_cons_state < NFS_CS_READY) {
436 			atomic_inc(&pos->cl_count);
437 			spin_unlock(&nn->nfs_client_lock);
438 
439 			if (prev)
440 				nfs_put_client(prev);
441 			prev = pos;
442 
443 			nfs4_schedule_lease_recovery(pos);
444 			status = nfs_wait_client_init_complete(pos);
445 			if (status < 0) {
446 				nfs_put_client(pos);
447 				spin_lock(&nn->nfs_client_lock);
448 				continue;
449 			}
450 			status = pos->cl_cons_state;
451 			spin_lock(&nn->nfs_client_lock);
452 			if (status < 0)
453 				continue;
454 		}
455 
456 		if (pos->rpc_ops != new->rpc_ops)
457 			continue;
458 
459 		if (pos->cl_proto != new->cl_proto)
460 			continue;
461 
462 		if (pos->cl_minorversion != new->cl_minorversion)
463 			continue;
464 
465 		if (!nfs4_match_clientids(pos, new))
466 			continue;
467 
468 		if (!nfs4_match_serverowners(pos, new))
469 			continue;
470 
471 		atomic_inc(&pos->cl_count);
472 		spin_unlock(&nn->nfs_client_lock);
473 		dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
474 			__func__, pos, atomic_read(&pos->cl_count));
475 
476 		*result = pos;
477 		return 0;
478 	}
479 
480 	/* No matching nfs_client found. */
481 	spin_unlock(&nn->nfs_client_lock);
482 	dprintk("NFS: <-- %s status = %d\n", __func__, status);
483 	return status;
484 }
485 #endif	/* CONFIG_NFS_V4_1 */
486 
487 static void nfs4_destroy_server(struct nfs_server *server)
488 {
489 	nfs_server_return_all_delegations(server);
490 	unset_pnfs_layoutdriver(server);
491 	nfs4_purge_state_owners(server);
492 }
493 
494 /*
495  * NFSv4.0 callback thread helper
496  *
497  * Find a client by callback identifier
498  */
499 struct nfs_client *
500 nfs4_find_client_ident(struct net *net, int cb_ident)
501 {
502 	struct nfs_client *clp;
503 	struct nfs_net *nn = net_generic(net, nfs_net_id);
504 
505 	spin_lock(&nn->nfs_client_lock);
506 	clp = idr_find(&nn->cb_ident_idr, cb_ident);
507 	if (clp)
508 		atomic_inc(&clp->cl_count);
509 	spin_unlock(&nn->nfs_client_lock);
510 	return clp;
511 }
512 
513 #if defined(CONFIG_NFS_V4_1)
514 /* Common match routine for v4.0 and v4.1 callback services */
515 static bool nfs4_cb_match_client(const struct sockaddr *addr,
516 		struct nfs_client *clp, u32 minorversion)
517 {
518 	struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
519 
520 	/* Don't match clients that failed to initialise */
521 	if (!(clp->cl_cons_state == NFS_CS_READY ||
522 	    clp->cl_cons_state == NFS_CS_SESSION_INITING))
523 		return false;
524 
525 	smp_rmb();
526 
527 	/* Match the version and minorversion */
528 	if (clp->rpc_ops->version != 4 ||
529 	    clp->cl_minorversion != minorversion)
530 		return false;
531 
532 	/* Match only the IP address, not the port number */
533 	if (!nfs_sockaddr_match_ipaddr(addr, clap))
534 		return false;
535 
536 	return true;
537 }
538 
539 /*
540  * NFSv4.1 callback thread helper
541  * For CB_COMPOUND calls, find a client by IP address, protocol version,
542  * minorversion, and sessionID
543  *
544  * Returns NULL if no such client
545  */
546 struct nfs_client *
547 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
548 			   struct nfs4_sessionid *sid)
549 {
550 	struct nfs_client *clp;
551 	struct nfs_net *nn = net_generic(net, nfs_net_id);
552 
553 	spin_lock(&nn->nfs_client_lock);
554 	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
555 		if (nfs4_cb_match_client(addr, clp, 1) == false)
556 			continue;
557 
558 		if (!nfs4_has_session(clp))
559 			continue;
560 
561 		/* Match sessionid*/
562 		if (memcmp(clp->cl_session->sess_id.data,
563 		    sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
564 			continue;
565 
566 		atomic_inc(&clp->cl_count);
567 		spin_unlock(&nn->nfs_client_lock);
568 		return clp;
569 	}
570 	spin_unlock(&nn->nfs_client_lock);
571 	return NULL;
572 }
573 
574 #else /* CONFIG_NFS_V4_1 */
575 
576 struct nfs_client *
577 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
578 			   struct nfs4_sessionid *sid)
579 {
580 	return NULL;
581 }
582 #endif /* CONFIG_NFS_V4_1 */
583 
584 /*
585  * Set up an NFS4 client
586  */
587 static int nfs4_set_client(struct nfs_server *server,
588 		const char *hostname,
589 		const struct sockaddr *addr,
590 		const size_t addrlen,
591 		const char *ip_addr,
592 		rpc_authflavor_t authflavour,
593 		int proto, const struct rpc_timeout *timeparms,
594 		u32 minorversion, struct net *net)
595 {
596 	struct nfs_client_initdata cl_init = {
597 		.hostname = hostname,
598 		.addr = addr,
599 		.addrlen = addrlen,
600 		.nfs_mod = &nfs_v4,
601 		.proto = proto,
602 		.minorversion = minorversion,
603 		.net = net,
604 	};
605 	struct nfs_client *clp;
606 	int error;
607 
608 	dprintk("--> nfs4_set_client()\n");
609 
610 	if (server->flags & NFS_MOUNT_NORESVPORT)
611 		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
612 
613 	/* Allocate or find a client reference we can use */
614 	clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour);
615 	if (IS_ERR(clp)) {
616 		error = PTR_ERR(clp);
617 		goto error;
618 	}
619 
620 	/*
621 	 * Query for the lease time on clientid setup or renewal
622 	 *
623 	 * Note that this will be set on nfs_clients that were created
624 	 * only for the DS role and did not set this bit, but now will
625 	 * serve a dual role.
626 	 */
627 	set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
628 
629 	server->nfs_client = clp;
630 	dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
631 	return 0;
632 error:
633 	dprintk("<-- nfs4_set_client() = xerror %d\n", error);
634 	return error;
635 }
636 
637 /*
638  * Set up a pNFS Data Server client.
639  *
640  * Return any existing nfs_client that matches server address,port,version
641  * and minorversion.
642  *
643  * For a new nfs_client, use a soft mount (default), a low retrans and a
644  * low timeout interval so that if a connection is lost, we retry through
645  * the MDS.
646  */
647 struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
648 		const struct sockaddr *ds_addr, int ds_addrlen,
649 		int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans)
650 {
651 	struct nfs_client_initdata cl_init = {
652 		.addr = ds_addr,
653 		.addrlen = ds_addrlen,
654 		.nfs_mod = &nfs_v4,
655 		.proto = ds_proto,
656 		.minorversion = mds_clp->cl_minorversion,
657 		.net = mds_clp->cl_net,
658 	};
659 	struct rpc_timeout ds_timeout;
660 	struct nfs_client *clp;
661 
662 	/*
663 	 * Set an authflavor equual to the MDS value. Use the MDS nfs_client
664 	 * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
665 	 * (section 13.1 RFC 5661).
666 	 */
667 	nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
668 	clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
669 			     mds_clp->cl_rpcclient->cl_auth->au_flavor);
670 
671 	dprintk("<-- %s %p\n", __func__, clp);
672 	return clp;
673 }
674 EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
675 
676 /*
677  * Session has been established, and the client marked ready.
678  * Set the mount rsize and wsize with negotiated fore channel
679  * attributes which will be bound checked in nfs_server_set_fsinfo.
680  */
681 static void nfs4_session_set_rwsize(struct nfs_server *server)
682 {
683 #ifdef CONFIG_NFS_V4_1
684 	struct nfs4_session *sess;
685 	u32 server_resp_sz;
686 	u32 server_rqst_sz;
687 
688 	if (!nfs4_has_session(server->nfs_client))
689 		return;
690 	sess = server->nfs_client->cl_session;
691 	server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
692 	server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
693 
694 	if (server->rsize > server_resp_sz)
695 		server->rsize = server_resp_sz;
696 	if (server->wsize > server_rqst_sz)
697 		server->wsize = server_rqst_sz;
698 #endif /* CONFIG_NFS_V4_1 */
699 }
700 
701 static int nfs4_server_common_setup(struct nfs_server *server,
702 		struct nfs_fh *mntfh)
703 {
704 	struct nfs_fattr *fattr;
705 	int error;
706 
707 	/* data servers support only a subset of NFSv4.1 */
708 	if (is_ds_only_client(server->nfs_client))
709 		return -EPROTONOSUPPORT;
710 
711 	fattr = nfs_alloc_fattr();
712 	if (fattr == NULL)
713 		return -ENOMEM;
714 
715 	/* We must ensure the session is initialised first */
716 	error = nfs4_init_session(server);
717 	if (error < 0)
718 		goto out;
719 
720 	/* Probe the root fh to retrieve its FSID and filehandle */
721 	error = nfs4_get_rootfh(server, mntfh);
722 	if (error < 0)
723 		goto out;
724 
725 	dprintk("Server FSID: %llx:%llx\n",
726 			(unsigned long long) server->fsid.major,
727 			(unsigned long long) server->fsid.minor);
728 	dprintk("Mount FH: %d\n", mntfh->size);
729 
730 	nfs4_session_set_rwsize(server);
731 
732 	error = nfs_probe_fsinfo(server, mntfh, fattr);
733 	if (error < 0)
734 		goto out;
735 
736 	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
737 		server->namelen = NFS4_MAXNAMLEN;
738 
739 	nfs_server_insert_lists(server);
740 	server->mount_time = jiffies;
741 	server->destroy = nfs4_destroy_server;
742 out:
743 	nfs_free_fattr(fattr);
744 	return error;
745 }
746 
747 /*
748  * Create a version 4 volume record
749  */
750 static int nfs4_init_server(struct nfs_server *server,
751 		const struct nfs_parsed_mount_data *data)
752 {
753 	struct rpc_timeout timeparms;
754 	int error;
755 
756 	dprintk("--> nfs4_init_server()\n");
757 
758 	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
759 			data->timeo, data->retrans);
760 
761 	/* Initialise the client representation from the mount data */
762 	server->flags = data->flags;
763 	server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
764 	if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
765 			server->caps |= NFS_CAP_READDIRPLUS;
766 	server->options = data->options;
767 
768 	/* Get a client record */
769 	error = nfs4_set_client(server,
770 			data->nfs_server.hostname,
771 			(const struct sockaddr *)&data->nfs_server.address,
772 			data->nfs_server.addrlen,
773 			data->client_address,
774 			data->auth_flavors[0],
775 			data->nfs_server.protocol,
776 			&timeparms,
777 			data->minorversion,
778 			data->net);
779 	if (error < 0)
780 		goto error;
781 
782 	/*
783 	 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
784 	 * authentication.
785 	 */
786 	if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
787 		server->caps |= NFS_CAP_UIDGID_NOMAP;
788 
789 	if (data->rsize)
790 		server->rsize = nfs_block_size(data->rsize, NULL);
791 	if (data->wsize)
792 		server->wsize = nfs_block_size(data->wsize, NULL);
793 
794 	server->acregmin = data->acregmin * HZ;
795 	server->acregmax = data->acregmax * HZ;
796 	server->acdirmin = data->acdirmin * HZ;
797 	server->acdirmax = data->acdirmax * HZ;
798 
799 	server->port = data->nfs_server.port;
800 
801 	error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]);
802 
803 error:
804 	/* Done */
805 	dprintk("<-- nfs4_init_server() = %d\n", error);
806 	return error;
807 }
808 
809 /*
810  * Create a version 4 volume record
811  * - keyed on server and FSID
812  */
813 /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
814 				      struct nfs_fh *mntfh)*/
815 struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
816 				      struct nfs_subversion *nfs_mod)
817 {
818 	struct nfs_server *server;
819 	int error;
820 
821 	dprintk("--> nfs4_create_server()\n");
822 
823 	server = nfs_alloc_server();
824 	if (!server)
825 		return ERR_PTR(-ENOMEM);
826 
827 	/* set up the general RPC client */
828 	error = nfs4_init_server(server, mount_info->parsed);
829 	if (error < 0)
830 		goto error;
831 
832 	error = nfs4_server_common_setup(server, mount_info->mntfh);
833 	if (error < 0)
834 		goto error;
835 
836 	dprintk("<-- nfs4_create_server() = %p\n", server);
837 	return server;
838 
839 error:
840 	nfs_free_server(server);
841 	dprintk("<-- nfs4_create_server() = error %d\n", error);
842 	return ERR_PTR(error);
843 }
844 
845 /*
846  * Create an NFS4 referral server record
847  */
848 struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
849 					       struct nfs_fh *mntfh)
850 {
851 	struct nfs_client *parent_client;
852 	struct nfs_server *server, *parent_server;
853 	int error;
854 
855 	dprintk("--> nfs4_create_referral_server()\n");
856 
857 	server = nfs_alloc_server();
858 	if (!server)
859 		return ERR_PTR(-ENOMEM);
860 
861 	parent_server = NFS_SB(data->sb);
862 	parent_client = parent_server->nfs_client;
863 
864 	/* Initialise the client representation from the parent server */
865 	nfs_server_copy_userdata(server, parent_server);
866 	server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
867 
868 	/* Get a client representation.
869 	 * Note: NFSv4 always uses TCP, */
870 	error = nfs4_set_client(server, data->hostname,
871 				data->addr,
872 				data->addrlen,
873 				parent_client->cl_ipaddr,
874 				data->authflavor,
875 				rpc_protocol(parent_server->client),
876 				parent_server->client->cl_timeout,
877 				parent_client->cl_mvops->minor_version,
878 				parent_client->cl_net);
879 	if (error < 0)
880 		goto error;
881 
882 	error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
883 	if (error < 0)
884 		goto error;
885 
886 	error = nfs4_server_common_setup(server, mntfh);
887 	if (error < 0)
888 		goto error;
889 
890 	dprintk("<-- nfs_create_referral_server() = %p\n", server);
891 	return server;
892 
893 error:
894 	nfs_free_server(server);
895 	dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
896 	return ERR_PTR(error);
897 }
898