2 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
3 * Written by David Howells (dhowells@redhat.com)
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/auth.h>
10 #include <linux/sunrpc/xprt.h>
11 #include <linux/sunrpc/bc_xprt.h>
14 #include "delegation.h"
18 #define NFSDBG_FACILITY NFSDBG_CLIENT
21 * Get a unique NFSv4.0 callback identifier which will be used
22 * by the V4.0 callback service to lookup the nfs_client struct
24 static int nfs_get_cb_ident_idr(struct nfs_client
*clp
, int minorversion
)
27 struct nfs_net
*nn
= net_generic(clp
->cl_net
, nfs_net_id
);
29 if (clp
->rpc_ops
->version
!= 4 || minorversion
!= 0)
32 if (!idr_pre_get(&nn
->cb_ident_idr
, GFP_KERNEL
))
34 spin_lock(&nn
->nfs_client_lock
);
35 ret
= idr_get_new(&nn
->cb_ident_idr
, clp
, &clp
->cl_cb_ident
);
36 spin_unlock(&nn
->nfs_client_lock
);
42 #ifdef CONFIG_NFS_V4_1
43 static void nfs4_shutdown_session(struct nfs_client
*clp
)
45 if (nfs4_has_session(clp
)) {
46 nfs4_destroy_session(clp
->cl_session
);
47 nfs4_destroy_clientid(clp
);
51 #else /* CONFIG_NFS_V4_1 */
52 static void nfs4_shutdown_session(struct nfs_client
*clp
)
55 #endif /* CONFIG_NFS_V4_1 */
57 struct nfs_client
*nfs4_alloc_client(const struct nfs_client_initdata
*cl_init
)
60 struct nfs_client
*clp
= nfs_alloc_client(cl_init
);
64 err
= nfs_get_cb_ident_idr(clp
, cl_init
->minorversion
);
68 spin_lock_init(&clp
->cl_lock
);
69 INIT_DELAYED_WORK(&clp
->cl_renewd
, nfs4_renew_state
);
70 rpc_init_wait_queue(&clp
->cl_rpcwaitq
, "NFS client");
71 clp
->cl_state
= 1 << NFS4CLNT_LEASE_EXPIRED
;
72 clp
->cl_minorversion
= cl_init
->minorversion
;
73 clp
->cl_mvops
= nfs_v4_minor_ops
[cl_init
->minorversion
];
82 * Destroy the NFS4 callback service
84 static void nfs4_destroy_callback(struct nfs_client
*clp
)
86 if (__test_and_clear_bit(NFS_CS_CALLBACK
, &clp
->cl_res_state
))
87 nfs_callback_down(clp
->cl_mvops
->minor_version
);
90 static void nfs4_shutdown_client(struct nfs_client
*clp
)
92 if (__test_and_clear_bit(NFS_CS_RENEWD
, &clp
->cl_res_state
))
93 nfs4_kill_renewd(clp
);
94 nfs4_shutdown_session(clp
);
95 nfs4_destroy_callback(clp
);
96 if (__test_and_clear_bit(NFS_CS_IDMAP
, &clp
->cl_res_state
))
97 nfs_idmap_delete(clp
);
99 rpc_destroy_wait_queue(&clp
->cl_rpcwaitq
);
100 kfree(clp
->cl_serverowner
);
101 kfree(clp
->cl_serverscope
);
102 kfree(clp
->cl_implid
);
105 void nfs4_free_client(struct nfs_client
*clp
)
107 nfs4_shutdown_client(clp
);
108 nfs_free_client(clp
);
112 * Initialize the NFS4 callback service
114 static int nfs4_init_callback(struct nfs_client
*clp
)
118 if (clp
->rpc_ops
->version
== 4) {
119 struct rpc_xprt
*xprt
;
121 xprt
= rcu_dereference_raw(clp
->cl_rpcclient
->cl_xprt
);
123 if (nfs4_has_session(clp
)) {
124 error
= xprt_setup_backchannel(xprt
,
125 NFS41_BC_MIN_CALLBACKS
);
130 error
= nfs_callback_up(clp
->cl_mvops
->minor_version
, xprt
);
132 dprintk("%s: failed to start callback. Error = %d\n",
136 __set_bit(NFS_CS_CALLBACK
, &clp
->cl_res_state
);
142 * Initialize the minor version specific parts of an NFS4 client record
144 static int nfs4_init_client_minor_version(struct nfs_client
*clp
)
146 #if defined(CONFIG_NFS_V4_1)
147 if (clp
->cl_mvops
->minor_version
) {
148 struct nfs4_session
*session
= NULL
;
150 * Create the session and mark it expired.
151 * When a SEQUENCE operation encounters the expired session
152 * it will do session recovery to initialize it.
154 session
= nfs4_alloc_session(clp
);
158 clp
->cl_session
= session
;
160 * The create session reply races with the server back
161 * channel probe. Mark the client NFS_CS_SESSION_INITING
162 * so that the client back channel can find the
165 nfs_mark_client_ready(clp
, NFS_CS_SESSION_INITING
);
167 #endif /* CONFIG_NFS_V4_1 */
169 return nfs4_init_callback(clp
);
173 * nfs4_init_client - Initialise an NFS4 client record
175 * @clp: nfs_client to initialise
176 * @timeparms: timeout parameters for underlying RPC transport
177 * @ip_addr: callback IP address in presentation format
178 * @authflavor: authentication flavor for underlying RPC transport
180 * Returns pointer to an NFS client, or an ERR_PTR value.
182 struct nfs_client
*nfs4_init_client(struct nfs_client
*clp
,
183 const struct rpc_timeout
*timeparms
,
185 rpc_authflavor_t authflavour
)
187 char buf
[INET6_ADDRSTRLEN
+ 1];
190 if (clp
->cl_cons_state
== NFS_CS_READY
) {
191 /* the client is initialised already */
192 dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp
);
196 /* Check NFS protocol revision and initialize RPC op vector */
197 clp
->rpc_ops
= &nfs_v4_clientops
;
199 __set_bit(NFS_CS_DISCRTRY
, &clp
->cl_flags
);
200 error
= nfs_create_rpc_client(clp
, timeparms
, authflavour
);
204 /* If no clientaddr= option was specified, find a usable cb address */
205 if (ip_addr
== NULL
) {
206 struct sockaddr_storage cb_addr
;
207 struct sockaddr
*sap
= (struct sockaddr
*)&cb_addr
;
209 error
= rpc_localaddr(clp
->cl_rpcclient
, sap
, sizeof(cb_addr
));
212 error
= rpc_ntop(sap
, buf
, sizeof(buf
));
215 ip_addr
= (const char *)buf
;
217 strlcpy(clp
->cl_ipaddr
, ip_addr
, sizeof(clp
->cl_ipaddr
));
219 error
= nfs_idmap_new(clp
);
221 dprintk("%s: failed to create idmapper. Error = %d\n",
225 __set_bit(NFS_CS_IDMAP
, &clp
->cl_res_state
);
227 error
= nfs4_init_client_minor_version(clp
);
231 if (!nfs4_has_session(clp
))
232 nfs_mark_client_ready(clp
, NFS_CS_READY
);
236 nfs_mark_client_ready(clp
, error
);
238 dprintk("<-- nfs4_init_client() = xerror %d\n", error
);
239 return ERR_PTR(error
);
242 static void nfs4_destroy_server(struct nfs_server
*server
)
244 nfs_server_return_all_delegations(server
);
245 unset_pnfs_layoutdriver(server
);
246 nfs4_purge_state_owners(server
);
250 * NFSv4.0 callback thread helper
252 * Find a client by callback identifier
255 nfs4_find_client_ident(struct net
*net
, int cb_ident
)
257 struct nfs_client
*clp
;
258 struct nfs_net
*nn
= net_generic(net
, nfs_net_id
);
260 spin_lock(&nn
->nfs_client_lock
);
261 clp
= idr_find(&nn
->cb_ident_idr
, cb_ident
);
263 atomic_inc(&clp
->cl_count
);
264 spin_unlock(&nn
->nfs_client_lock
);
268 #if defined(CONFIG_NFS_V4_1)
269 /* Common match routine for v4.0 and v4.1 callback services */
270 static bool nfs4_cb_match_client(const struct sockaddr
*addr
,
271 struct nfs_client
*clp
, u32 minorversion
)
273 struct sockaddr
*clap
= (struct sockaddr
*)&clp
->cl_addr
;
275 /* Don't match clients that failed to initialise */
276 if (!(clp
->cl_cons_state
== NFS_CS_READY
||
277 clp
->cl_cons_state
== NFS_CS_SESSION_INITING
))
282 /* Match the version and minorversion */
283 if (clp
->rpc_ops
->version
!= 4 ||
284 clp
->cl_minorversion
!= minorversion
)
287 /* Match only the IP address, not the port number */
288 if (!nfs_sockaddr_match_ipaddr(addr
, clap
))
295 * NFSv4.1 callback thread helper
296 * For CB_COMPOUND calls, find a client by IP address, protocol version,
297 * minorversion, and sessionID
299 * Returns NULL if no such client
302 nfs4_find_client_sessionid(struct net
*net
, const struct sockaddr
*addr
,
303 struct nfs4_sessionid
*sid
)
305 struct nfs_client
*clp
;
306 struct nfs_net
*nn
= net_generic(net
, nfs_net_id
);
308 spin_lock(&nn
->nfs_client_lock
);
309 list_for_each_entry(clp
, &nn
->nfs_client_list
, cl_share_link
) {
310 if (nfs4_cb_match_client(addr
, clp
, 1) == false)
313 if (!nfs4_has_session(clp
))
317 if (memcmp(clp
->cl_session
->sess_id
.data
,
318 sid
->data
, NFS4_MAX_SESSIONID_LEN
) != 0)
321 atomic_inc(&clp
->cl_count
);
322 spin_unlock(&nn
->nfs_client_lock
);
325 spin_unlock(&nn
->nfs_client_lock
);
329 #else /* CONFIG_NFS_V4_1 */
332 nfs4_find_client_sessionid(struct net
*net
, const struct sockaddr
*addr
,
333 struct nfs4_sessionid
*sid
)
337 #endif /* CONFIG_NFS_V4_1 */
340 * Set up an NFS4 client
342 static int nfs4_set_client(struct nfs_server
*server
,
343 const char *hostname
,
344 const struct sockaddr
*addr
,
345 const size_t addrlen
,
347 rpc_authflavor_t authflavour
,
348 int proto
, const struct rpc_timeout
*timeparms
,
349 u32 minorversion
, struct net
*net
)
351 struct nfs_client_initdata cl_init
= {
352 .hostname
= hostname
,
357 .minorversion
= minorversion
,
360 struct nfs_client
*clp
;
363 dprintk("--> nfs4_set_client()\n");
365 if (server
->flags
& NFS_MOUNT_NORESVPORT
)
366 set_bit(NFS_CS_NORESVPORT
, &cl_init
.init_flags
);
368 /* Allocate or find a client reference we can use */
369 clp
= nfs_get_client(&cl_init
, timeparms
, ip_addr
, authflavour
);
371 error
= PTR_ERR(clp
);
376 * Query for the lease time on clientid setup or renewal
378 * Note that this will be set on nfs_clients that were created
379 * only for the DS role and did not set this bit, but now will
382 set_bit(NFS_CS_CHECK_LEASE_TIME
, &clp
->cl_res_state
);
384 server
->nfs_client
= clp
;
385 dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp
);
388 dprintk("<-- nfs4_set_client() = xerror %d\n", error
);
393 * Set up a pNFS Data Server client.
395 * Return any existing nfs_client that matches server address,port,version
398 * For a new nfs_client, use a soft mount (default), a low retrans and a
399 * low timeout interval so that if a connection is lost, we retry through
402 struct nfs_client
*nfs4_set_ds_client(struct nfs_client
* mds_clp
,
403 const struct sockaddr
*ds_addr
, int ds_addrlen
,
404 int ds_proto
, unsigned int ds_timeo
, unsigned int ds_retrans
)
406 struct nfs_client_initdata cl_init
= {
408 .addrlen
= ds_addrlen
,
411 .minorversion
= mds_clp
->cl_minorversion
,
412 .net
= mds_clp
->cl_net
,
414 struct rpc_timeout ds_timeout
;
415 struct nfs_client
*clp
;
418 * Set an authflavor equual to the MDS value. Use the MDS nfs_client
419 * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
420 * (section 13.1 RFC 5661).
422 nfs_init_timeout_values(&ds_timeout
, ds_proto
, ds_timeo
, ds_retrans
);
423 clp
= nfs_get_client(&cl_init
, &ds_timeout
, mds_clp
->cl_ipaddr
,
424 mds_clp
->cl_rpcclient
->cl_auth
->au_flavor
);
426 dprintk("<-- %s %p\n", __func__
, clp
);
429 EXPORT_SYMBOL_GPL(nfs4_set_ds_client
);
432 * Session has been established, and the client marked ready.
433 * Set the mount rsize and wsize with negotiated fore channel
434 * attributes which will be bound checked in nfs_server_set_fsinfo.
436 static void nfs4_session_set_rwsize(struct nfs_server
*server
)
438 #ifdef CONFIG_NFS_V4_1
439 struct nfs4_session
*sess
;
443 if (!nfs4_has_session(server
->nfs_client
))
445 sess
= server
->nfs_client
->cl_session
;
446 server_resp_sz
= sess
->fc_attrs
.max_resp_sz
- nfs41_maxread_overhead
;
447 server_rqst_sz
= sess
->fc_attrs
.max_rqst_sz
- nfs41_maxwrite_overhead
;
449 if (server
->rsize
> server_resp_sz
)
450 server
->rsize
= server_resp_sz
;
451 if (server
->wsize
> server_rqst_sz
)
452 server
->wsize
= server_rqst_sz
;
453 #endif /* CONFIG_NFS_V4_1 */
456 static int nfs4_server_common_setup(struct nfs_server
*server
,
457 struct nfs_fh
*mntfh
)
459 struct nfs_fattr
*fattr
;
462 BUG_ON(!server
->nfs_client
);
463 BUG_ON(!server
->nfs_client
->rpc_ops
);
464 BUG_ON(!server
->nfs_client
->rpc_ops
->file_inode_ops
);
466 /* data servers support only a subset of NFSv4.1 */
467 if (is_ds_only_client(server
->nfs_client
))
468 return -EPROTONOSUPPORT
;
470 fattr
= nfs_alloc_fattr();
474 /* We must ensure the session is initialised first */
475 error
= nfs4_init_session(server
);
479 /* Probe the root fh to retrieve its FSID and filehandle */
480 error
= nfs4_get_rootfh(server
, mntfh
);
484 dprintk("Server FSID: %llx:%llx\n",
485 (unsigned long long) server
->fsid
.major
,
486 (unsigned long long) server
->fsid
.minor
);
487 dprintk("Mount FH: %d\n", mntfh
->size
);
489 nfs4_session_set_rwsize(server
);
491 error
= nfs_probe_fsinfo(server
, mntfh
, fattr
);
495 if (server
->namelen
== 0 || server
->namelen
> NFS4_MAXNAMLEN
)
496 server
->namelen
= NFS4_MAXNAMLEN
;
498 nfs_server_insert_lists(server
);
499 server
->mount_time
= jiffies
;
500 server
->destroy
= nfs4_destroy_server
;
502 nfs_free_fattr(fattr
);
507 * Create a version 4 volume record
509 static int nfs4_init_server(struct nfs_server
*server
,
510 const struct nfs_parsed_mount_data
*data
)
512 struct rpc_timeout timeparms
;
515 dprintk("--> nfs4_init_server()\n");
517 nfs_init_timeout_values(&timeparms
, data
->nfs_server
.protocol
,
518 data
->timeo
, data
->retrans
);
520 /* Initialise the client representation from the mount data */
521 server
->flags
= data
->flags
;
522 server
->caps
|= NFS_CAP_ATOMIC_OPEN
|NFS_CAP_CHANGE_ATTR
|NFS_CAP_POSIX_LOCK
;
523 if (!(data
->flags
& NFS_MOUNT_NORDIRPLUS
))
524 server
->caps
|= NFS_CAP_READDIRPLUS
;
525 server
->options
= data
->options
;
527 /* Get a client record */
528 error
= nfs4_set_client(server
,
529 data
->nfs_server
.hostname
,
530 (const struct sockaddr
*)&data
->nfs_server
.address
,
531 data
->nfs_server
.addrlen
,
532 data
->client_address
,
533 data
->auth_flavors
[0],
534 data
->nfs_server
.protocol
,
542 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
545 if (nfs4_disable_idmapping
&& data
->auth_flavors
[0] == RPC_AUTH_UNIX
)
546 server
->caps
|= NFS_CAP_UIDGID_NOMAP
;
549 server
->rsize
= nfs_block_size(data
->rsize
, NULL
);
551 server
->wsize
= nfs_block_size(data
->wsize
, NULL
);
553 server
->acregmin
= data
->acregmin
* HZ
;
554 server
->acregmax
= data
->acregmax
* HZ
;
555 server
->acdirmin
= data
->acdirmin
* HZ
;
556 server
->acdirmax
= data
->acdirmax
* HZ
;
558 server
->port
= data
->nfs_server
.port
;
560 error
= nfs_init_server_rpcclient(server
, &timeparms
, data
->auth_flavors
[0]);
564 dprintk("<-- nfs4_init_server() = %d\n", error
);
569 * Create a version 4 volume record
570 * - keyed on server and FSID
572 /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
573 struct nfs_fh *mntfh)*/
574 struct nfs_server
*nfs4_create_server(struct nfs_mount_info
*mount_info
,
575 struct nfs_subversion
*nfs_mod
)
577 struct nfs_server
*server
;
580 dprintk("--> nfs4_create_server()\n");
582 server
= nfs_alloc_server();
584 return ERR_PTR(-ENOMEM
);
586 /* set up the general RPC client */
587 error
= nfs4_init_server(server
, mount_info
->parsed
);
591 error
= nfs4_server_common_setup(server
, mount_info
->mntfh
);
595 dprintk("<-- nfs4_create_server() = %p\n", server
);
599 nfs_free_server(server
);
600 dprintk("<-- nfs4_create_server() = error %d\n", error
);
601 return ERR_PTR(error
);
605 * Create an NFS4 referral server record
607 struct nfs_server
*nfs4_create_referral_server(struct nfs_clone_mount
*data
,
608 struct nfs_fh
*mntfh
)
610 struct nfs_client
*parent_client
;
611 struct nfs_server
*server
, *parent_server
;
614 dprintk("--> nfs4_create_referral_server()\n");
616 server
= nfs_alloc_server();
618 return ERR_PTR(-ENOMEM
);
620 parent_server
= NFS_SB(data
->sb
);
621 parent_client
= parent_server
->nfs_client
;
623 /* Initialise the client representation from the parent server */
624 nfs_server_copy_userdata(server
, parent_server
);
625 server
->caps
|= NFS_CAP_ATOMIC_OPEN
|NFS_CAP_CHANGE_ATTR
;
627 /* Get a client representation.
628 * Note: NFSv4 always uses TCP, */
629 error
= nfs4_set_client(server
, data
->hostname
,
632 parent_client
->cl_ipaddr
,
634 rpc_protocol(parent_server
->client
),
635 parent_server
->client
->cl_timeout
,
636 parent_client
->cl_mvops
->minor_version
,
637 parent_client
->cl_net
);
641 error
= nfs_init_server_rpcclient(server
, parent_server
->client
->cl_timeout
, data
->authflavor
);
645 error
= nfs4_server_common_setup(server
, mntfh
);
649 dprintk("<-- nfs_create_referral_server() = %p\n", server
);
653 nfs_free_server(server
);
654 dprintk("<-- nfs4_create_referral_server() = error %d\n", error
);
655 return ERR_PTR(error
);