diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 364 |
1 files changed, 241 insertions, 123 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 70587f383f10..c5c0175898f6 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <linux/nfs_idmap.h> | 34 | #include <linux/nfs_idmap.h> |
35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
37 | #include <linux/in6.h> | ||
38 | #include <net/ipv6.h> | ||
37 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
38 | 40 | ||
39 | #include <asm/system.h> | 41 | #include <asm/system.h> |
@@ -93,22 +95,30 @@ struct rpc_program nfsacl_program = { | |||
93 | }; | 95 | }; |
94 | #endif /* CONFIG_NFS_V3_ACL */ | 96 | #endif /* CONFIG_NFS_V3_ACL */ |
95 | 97 | ||
98 | struct nfs_client_initdata { | ||
99 | const char *hostname; | ||
100 | const struct sockaddr *addr; | ||
101 | size_t addrlen; | ||
102 | const struct nfs_rpc_ops *rpc_ops; | ||
103 | int proto; | ||
104 | }; | ||
105 | |||
96 | /* | 106 | /* |
97 | * Allocate a shared client record | 107 | * Allocate a shared client record |
98 | * | 108 | * |
99 | * Since these are allocated/deallocated very rarely, we don't | 109 | * Since these are allocated/deallocated very rarely, we don't |
100 | * bother putting them in a slab cache... | 110 | * bother putting them in a slab cache... |
101 | */ | 111 | */ |
102 | static struct nfs_client *nfs_alloc_client(const char *hostname, | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
103 | const struct sockaddr_in *addr, | ||
104 | int nfsversion) | ||
105 | { | 113 | { |
106 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
107 | 115 | ||
108 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
109 | goto error_0; | 117 | goto error_0; |
110 | 118 | ||
111 | if (nfsversion == 4) { | 119 | clp->rpc_ops = cl_init->rpc_ops; |
120 | |||
121 | if (cl_init->rpc_ops->version == 4) { | ||
112 | if (nfs_callback_up() < 0) | 122 | if (nfs_callback_up() < 0) |
113 | goto error_2; | 123 | goto error_2; |
114 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | 124 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); |
@@ -117,11 +127,11 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
117 | atomic_set(&clp->cl_count, 1); | 127 | atomic_set(&clp->cl_count, 1); |
118 | clp->cl_cons_state = NFS_CS_INITING; | 128 | clp->cl_cons_state = NFS_CS_INITING; |
119 | 129 | ||
120 | clp->cl_nfsversion = nfsversion; | 130 | memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen); |
121 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | 131 | clp->cl_addrlen = cl_init->addrlen; |
122 | 132 | ||
123 | if (hostname) { | 133 | if (cl_init->hostname) { |
124 | clp->cl_hostname = kstrdup(hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
125 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
126 | goto error_3; | 136 | goto error_3; |
127 | } | 137 | } |
@@ -129,6 +139,8 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |||
129 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
130 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | 140 | clp->cl_rpcclient = ERR_PTR(-EINVAL); |
131 | 141 | ||
142 | clp->cl_proto = cl_init->proto; | ||
143 | |||
132 | #ifdef CONFIG_NFS_V4 | 144 | #ifdef CONFIG_NFS_V4 |
133 | init_rwsem(&clp->cl_sem); | 145 | init_rwsem(&clp->cl_sem); |
134 | INIT_LIST_HEAD(&clp->cl_delegations); | 146 | INIT_LIST_HEAD(&clp->cl_delegations); |
@@ -166,7 +178,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
166 | */ | 178 | */ |
167 | static void nfs_free_client(struct nfs_client *clp) | 179 | static void nfs_free_client(struct nfs_client *clp) |
168 | { | 180 | { |
169 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | 181 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
170 | 182 | ||
171 | nfs4_shutdown_client(clp); | 183 | nfs4_shutdown_client(clp); |
172 | 184 | ||
@@ -203,76 +215,148 @@ void nfs_put_client(struct nfs_client *clp) | |||
203 | } | 215 | } |
204 | } | 216 | } |
205 | 217 | ||
218 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
219 | const struct sockaddr_in *sa2) | ||
220 | { | ||
221 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | ||
222 | } | ||
223 | |||
224 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, | ||
225 | const struct sockaddr_in6 *sa2) | ||
226 | { | ||
227 | return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); | ||
228 | } | ||
229 | |||
230 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
231 | const struct sockaddr *sa2) | ||
232 | { | ||
233 | switch (sa1->sa_family) { | ||
234 | case AF_INET: | ||
235 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | ||
236 | (const struct sockaddr_in *)sa2); | ||
237 | case AF_INET6: | ||
238 | return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1, | ||
239 | (const struct sockaddr_in6 *)sa2); | ||
240 | } | ||
241 | BUG(); | ||
242 | } | ||
243 | |||
206 | /* | 244 | /* |
207 | * Find a client by address | 245 | * Find a client by IP address and protocol version |
208 | * - caller must hold nfs_client_lock | 246 | * - returns NULL if no such client |
209 | */ | 247 | */ |
210 | static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port) | 248 | struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) |
211 | { | 249 | { |
212 | struct nfs_client *clp; | 250 | struct nfs_client *clp; |
213 | 251 | ||
252 | spin_lock(&nfs_client_lock); | ||
214 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | 253 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { |
254 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
255 | |||
215 | /* Don't match clients that failed to initialise properly */ | 256 | /* Don't match clients that failed to initialise properly */ |
216 | if (clp->cl_cons_state < 0) | 257 | if (clp->cl_cons_state != NFS_CS_READY) |
217 | continue; | 258 | continue; |
218 | 259 | ||
219 | /* Different NFS versions cannot share the same nfs_client */ | 260 | /* Different NFS versions cannot share the same nfs_client */ |
220 | if (clp->cl_nfsversion != nfsversion) | 261 | if (clp->rpc_ops->version != nfsversion) |
221 | continue; | 262 | continue; |
222 | 263 | ||
223 | if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, | 264 | if (addr->sa_family != clap->sa_family) |
224 | sizeof(clp->cl_addr.sin_addr)) != 0) | 265 | continue; |
266 | /* Match only the IP address, not the port number */ | ||
267 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | ||
225 | continue; | 268 | continue; |
226 | 269 | ||
227 | if (!match_port || clp->cl_addr.sin_port == addr->sin_port) | 270 | atomic_inc(&clp->cl_count); |
228 | goto found; | 271 | spin_unlock(&nfs_client_lock); |
272 | return clp; | ||
229 | } | 273 | } |
230 | 274 | spin_unlock(&nfs_client_lock); | |
231 | return NULL; | 275 | return NULL; |
232 | |||
233 | found: | ||
234 | atomic_inc(&clp->cl_count); | ||
235 | return clp; | ||
236 | } | 276 | } |
237 | 277 | ||
238 | /* | 278 | /* |
239 | * Find a client by IP address and protocol version | 279 | * Find a client by IP address and protocol version |
240 | * - returns NULL if no such client | 280 | * - returns NULL if no such client |
241 | */ | 281 | */ |
242 | struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | 282 | struct nfs_client *nfs_find_client_next(struct nfs_client *clp) |
243 | { | 283 | { |
244 | struct nfs_client *clp; | 284 | struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr; |
285 | u32 nfsvers = clp->rpc_ops->version; | ||
245 | 286 | ||
246 | spin_lock(&nfs_client_lock); | 287 | spin_lock(&nfs_client_lock); |
247 | clp = __nfs_find_client(addr, nfsversion, 0); | 288 | list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) { |
289 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | ||
290 | |||
291 | /* Don't match clients that failed to initialise properly */ | ||
292 | if (clp->cl_cons_state != NFS_CS_READY) | ||
293 | continue; | ||
294 | |||
295 | /* Different NFS versions cannot share the same nfs_client */ | ||
296 | if (clp->rpc_ops->version != nfsvers) | ||
297 | continue; | ||
298 | |||
299 | if (sap->sa_family != clap->sa_family) | ||
300 | continue; | ||
301 | /* Match only the IP address, not the port number */ | ||
302 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | ||
303 | continue; | ||
304 | |||
305 | atomic_inc(&clp->cl_count); | ||
306 | spin_unlock(&nfs_client_lock); | ||
307 | return clp; | ||
308 | } | ||
248 | spin_unlock(&nfs_client_lock); | 309 | spin_unlock(&nfs_client_lock); |
249 | if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) { | 310 | return NULL; |
250 | nfs_put_client(clp); | 311 | } |
251 | clp = NULL; | 312 | |
313 | /* | ||
314 | * Find an nfs_client on the list that matches the initialisation data | ||
315 | * that is supplied. | ||
316 | */ | ||
317 | static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data) | ||
318 | { | ||
319 | struct nfs_client *clp; | ||
320 | |||
321 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
322 | /* Don't match clients that failed to initialise properly */ | ||
323 | if (clp->cl_cons_state < 0) | ||
324 | continue; | ||
325 | |||
326 | /* Different NFS versions cannot share the same nfs_client */ | ||
327 | if (clp->rpc_ops != data->rpc_ops) | ||
328 | continue; | ||
329 | |||
330 | if (clp->cl_proto != data->proto) | ||
331 | continue; | ||
332 | |||
333 | /* Match the full socket address */ | ||
334 | if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0) | ||
335 | continue; | ||
336 | |||
337 | atomic_inc(&clp->cl_count); | ||
338 | return clp; | ||
252 | } | 339 | } |
253 | return clp; | 340 | return NULL; |
254 | } | 341 | } |
255 | 342 | ||
256 | /* | 343 | /* |
257 | * Look up a client by IP address and protocol version | 344 | * Look up a client by IP address and protocol version |
258 | * - creates a new record if one doesn't yet exist | 345 | * - creates a new record if one doesn't yet exist |
259 | */ | 346 | */ |
260 | static struct nfs_client *nfs_get_client(const char *hostname, | 347 | static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) |
261 | const struct sockaddr_in *addr, | ||
262 | int nfsversion) | ||
263 | { | 348 | { |
264 | struct nfs_client *clp, *new = NULL; | 349 | struct nfs_client *clp, *new = NULL; |
265 | int error; | 350 | int error; |
266 | 351 | ||
267 | dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n", | 352 | dprintk("--> nfs_get_client(%s,v%u)\n", |
268 | hostname ?: "", NIPQUAD(addr->sin_addr), | 353 | cl_init->hostname ?: "", cl_init->rpc_ops->version); |
269 | addr->sin_port, nfsversion); | ||
270 | 354 | ||
271 | /* see if the client already exists */ | 355 | /* see if the client already exists */ |
272 | do { | 356 | do { |
273 | spin_lock(&nfs_client_lock); | 357 | spin_lock(&nfs_client_lock); |
274 | 358 | ||
275 | clp = __nfs_find_client(addr, nfsversion, 1); | 359 | clp = nfs_match_client(cl_init); |
276 | if (clp) | 360 | if (clp) |
277 | goto found_client; | 361 | goto found_client; |
278 | if (new) | 362 | if (new) |
@@ -280,7 +364,7 @@ static struct nfs_client *nfs_get_client(const char *hostname, | |||
280 | 364 | ||
281 | spin_unlock(&nfs_client_lock); | 365 | spin_unlock(&nfs_client_lock); |
282 | 366 | ||
283 | new = nfs_alloc_client(hostname, addr, nfsversion); | 367 | new = nfs_alloc_client(cl_init); |
284 | } while (new); | 368 | } while (new); |
285 | 369 | ||
286 | return ERR_PTR(-ENOMEM); | 370 | return ERR_PTR(-ENOMEM); |
@@ -302,7 +386,7 @@ found_client: | |||
302 | if (new) | 386 | if (new) |
303 | nfs_free_client(new); | 387 | nfs_free_client(new); |
304 | 388 | ||
305 | error = wait_event_interruptible(nfs_client_active_wq, | 389 | error = wait_event_killable(nfs_client_active_wq, |
306 | clp->cl_cons_state != NFS_CS_INITING); | 390 | clp->cl_cons_state != NFS_CS_INITING); |
307 | if (error < 0) { | 391 | if (error < 0) { |
308 | nfs_put_client(clp); | 392 | nfs_put_client(clp); |
@@ -344,12 +428,16 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
344 | switch (proto) { | 428 | switch (proto) { |
345 | case XPRT_TRANSPORT_TCP: | 429 | case XPRT_TRANSPORT_TCP: |
346 | case XPRT_TRANSPORT_RDMA: | 430 | case XPRT_TRANSPORT_RDMA: |
347 | if (!to->to_initval) | 431 | if (to->to_initval == 0) |
348 | to->to_initval = 60 * HZ; | 432 | to->to_initval = 60 * HZ; |
349 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | 433 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) |
350 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | 434 | to->to_initval = NFS_MAX_TCP_TIMEOUT; |
351 | to->to_increment = to->to_initval; | 435 | to->to_increment = to->to_initval; |
352 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | 436 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); |
437 | if (to->to_maxval > NFS_MAX_TCP_TIMEOUT) | ||
438 | to->to_maxval = NFS_MAX_TCP_TIMEOUT; | ||
439 | if (to->to_maxval < to->to_initval) | ||
440 | to->to_maxval = to->to_initval; | ||
353 | to->to_exponential = 0; | 441 | to->to_exponential = 0; |
354 | break; | 442 | break; |
355 | case XPRT_TRANSPORT_UDP: | 443 | case XPRT_TRANSPORT_UDP: |
@@ -367,19 +455,17 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
367 | /* | 455 | /* |
368 | * Create an RPC client handle | 456 | * Create an RPC client handle |
369 | */ | 457 | */ |
370 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | 458 | static int nfs_create_rpc_client(struct nfs_client *clp, |
371 | unsigned int timeo, | 459 | const struct rpc_timeout *timeparms, |
372 | unsigned int retrans, | 460 | rpc_authflavor_t flavor, |
373 | rpc_authflavor_t flavor, | 461 | int flags) |
374 | int flags) | ||
375 | { | 462 | { |
376 | struct rpc_timeout timeparms; | ||
377 | struct rpc_clnt *clnt = NULL; | 463 | struct rpc_clnt *clnt = NULL; |
378 | struct rpc_create_args args = { | 464 | struct rpc_create_args args = { |
379 | .protocol = proto, | 465 | .protocol = clp->cl_proto, |
380 | .address = (struct sockaddr *)&clp->cl_addr, | 466 | .address = (struct sockaddr *)&clp->cl_addr, |
381 | .addrsize = sizeof(clp->cl_addr), | 467 | .addrsize = clp->cl_addrlen, |
382 | .timeout = &timeparms, | 468 | .timeout = timeparms, |
383 | .servername = clp->cl_hostname, | 469 | .servername = clp->cl_hostname, |
384 | .program = &nfs_program, | 470 | .program = &nfs_program, |
385 | .version = clp->rpc_ops->version, | 471 | .version = clp->rpc_ops->version, |
@@ -390,10 +476,6 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
390 | if (!IS_ERR(clp->cl_rpcclient)) | 476 | if (!IS_ERR(clp->cl_rpcclient)) |
391 | return 0; | 477 | return 0; |
392 | 478 | ||
393 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
394 | clp->retrans_timeo = timeparms.to_initval; | ||
395 | clp->retrans_count = timeparms.to_retries; | ||
396 | |||
397 | clnt = rpc_create(&args); | 479 | clnt = rpc_create(&args); |
398 | if (IS_ERR(clnt)) { | 480 | if (IS_ERR(clnt)) { |
399 | dprintk("%s: cannot create RPC client. Error = %ld\n", | 481 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
@@ -410,11 +492,8 @@ static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | |||
410 | */ | 492 | */ |
411 | static void nfs_destroy_server(struct nfs_server *server) | 493 | static void nfs_destroy_server(struct nfs_server *server) |
412 | { | 494 | { |
413 | if (!IS_ERR(server->client_acl)) | ||
414 | rpc_shutdown_client(server->client_acl); | ||
415 | |||
416 | if (!(server->flags & NFS_MOUNT_NONLM)) | 495 | if (!(server->flags & NFS_MOUNT_NONLM)) |
417 | lockd_down(); /* release rpc.lockd */ | 496 | nlmclnt_done(server->nlm_host); |
418 | } | 497 | } |
419 | 498 | ||
420 | /* | 499 | /* |
@@ -422,20 +501,29 @@ static void nfs_destroy_server(struct nfs_server *server) | |||
422 | */ | 501 | */ |
423 | static int nfs_start_lockd(struct nfs_server *server) | 502 | static int nfs_start_lockd(struct nfs_server *server) |
424 | { | 503 | { |
425 | int error = 0; | 504 | struct nlm_host *host; |
505 | struct nfs_client *clp = server->nfs_client; | ||
506 | struct nlmclnt_initdata nlm_init = { | ||
507 | .hostname = clp->cl_hostname, | ||
508 | .address = (struct sockaddr *)&clp->cl_addr, | ||
509 | .addrlen = clp->cl_addrlen, | ||
510 | .protocol = server->flags & NFS_MOUNT_TCP ? | ||
511 | IPPROTO_TCP : IPPROTO_UDP, | ||
512 | .nfs_version = clp->rpc_ops->version, | ||
513 | }; | ||
426 | 514 | ||
427 | if (server->nfs_client->cl_nfsversion > 3) | 515 | if (nlm_init.nfs_version > 3) |
428 | goto out; | 516 | return 0; |
429 | if (server->flags & NFS_MOUNT_NONLM) | 517 | if (server->flags & NFS_MOUNT_NONLM) |
430 | goto out; | 518 | return 0; |
431 | error = lockd_up((server->flags & NFS_MOUNT_TCP) ? | 519 | |
432 | IPPROTO_TCP : IPPROTO_UDP); | 520 | host = nlmclnt_init(&nlm_init); |
433 | if (error < 0) | 521 | if (IS_ERR(host)) |
434 | server->flags |= NFS_MOUNT_NONLM; | 522 | return PTR_ERR(host); |
435 | else | 523 | |
436 | server->destroy = nfs_destroy_server; | 524 | server->nlm_host = host; |
437 | out: | 525 | server->destroy = nfs_destroy_server; |
438 | return error; | 526 | return 0; |
439 | } | 527 | } |
440 | 528 | ||
441 | /* | 529 | /* |
@@ -444,7 +532,7 @@ out: | |||
444 | #ifdef CONFIG_NFS_V3_ACL | 532 | #ifdef CONFIG_NFS_V3_ACL |
445 | static void nfs_init_server_aclclient(struct nfs_server *server) | 533 | static void nfs_init_server_aclclient(struct nfs_server *server) |
446 | { | 534 | { |
447 | if (server->nfs_client->cl_nfsversion != 3) | 535 | if (server->nfs_client->rpc_ops->version != 3) |
448 | goto out_noacl; | 536 | goto out_noacl; |
449 | if (server->flags & NFS_MOUNT_NOACL) | 537 | if (server->flags & NFS_MOUNT_NOACL) |
450 | goto out_noacl; | 538 | goto out_noacl; |
@@ -471,7 +559,9 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server) | |||
471 | /* | 559 | /* |
472 | * Create a general RPC client | 560 | * Create a general RPC client |
473 | */ | 561 | */ |
474 | static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour) | 562 | static int nfs_init_server_rpcclient(struct nfs_server *server, |
563 | const struct rpc_timeout *timeo, | ||
564 | rpc_authflavor_t pseudoflavour) | ||
475 | { | 565 | { |
476 | struct nfs_client *clp = server->nfs_client; | 566 | struct nfs_client *clp = server->nfs_client; |
477 | 567 | ||
@@ -481,6 +571,11 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
481 | return PTR_ERR(server->client); | 571 | return PTR_ERR(server->client); |
482 | } | 572 | } |
483 | 573 | ||
574 | memcpy(&server->client->cl_timeout_default, | ||
575 | timeo, | ||
576 | sizeof(server->client->cl_timeout_default)); | ||
577 | server->client->cl_timeout = &server->client->cl_timeout_default; | ||
578 | |||
484 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { | 579 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { |
485 | struct rpc_auth *auth; | 580 | struct rpc_auth *auth; |
486 | 581 | ||
@@ -494,10 +589,6 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
494 | if (server->flags & NFS_MOUNT_SOFT) | 589 | if (server->flags & NFS_MOUNT_SOFT) |
495 | server->client->cl_softrtry = 1; | 590 | server->client->cl_softrtry = 1; |
496 | 591 | ||
497 | server->client->cl_intr = 0; | ||
498 | if (server->flags & NFS4_MOUNT_INTR) | ||
499 | server->client->cl_intr = 1; | ||
500 | |||
501 | return 0; | 592 | return 0; |
502 | } | 593 | } |
503 | 594 | ||
@@ -505,6 +596,7 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t | |||
505 | * Initialise an NFS2 or NFS3 client | 596 | * Initialise an NFS2 or NFS3 client |
506 | */ | 597 | */ |
507 | static int nfs_init_client(struct nfs_client *clp, | 598 | static int nfs_init_client(struct nfs_client *clp, |
599 | const struct rpc_timeout *timeparms, | ||
508 | const struct nfs_parsed_mount_data *data) | 600 | const struct nfs_parsed_mount_data *data) |
509 | { | 601 | { |
510 | int error; | 602 | int error; |
@@ -515,18 +607,11 @@ static int nfs_init_client(struct nfs_client *clp, | |||
515 | return 0; | 607 | return 0; |
516 | } | 608 | } |
517 | 609 | ||
518 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
519 | clp->rpc_ops = &nfs_v2_clientops; | ||
520 | #ifdef CONFIG_NFS_V3 | ||
521 | if (clp->cl_nfsversion == 3) | ||
522 | clp->rpc_ops = &nfs_v3_clientops; | ||
523 | #endif | ||
524 | /* | 610 | /* |
525 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 611 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
526 | * - RFC 2623, sec 2.3.2 | 612 | * - RFC 2623, sec 2.3.2 |
527 | */ | 613 | */ |
528 | error = nfs_create_rpc_client(clp, data->nfs_server.protocol, | 614 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0); |
529 | data->timeo, data->retrans, RPC_AUTH_UNIX, 0); | ||
530 | if (error < 0) | 615 | if (error < 0) |
531 | goto error; | 616 | goto error; |
532 | nfs_mark_client_ready(clp, NFS_CS_READY); | 617 | nfs_mark_client_ready(clp, NFS_CS_READY); |
@@ -544,25 +629,34 @@ error: | |||
544 | static int nfs_init_server(struct nfs_server *server, | 629 | static int nfs_init_server(struct nfs_server *server, |
545 | const struct nfs_parsed_mount_data *data) | 630 | const struct nfs_parsed_mount_data *data) |
546 | { | 631 | { |
632 | struct nfs_client_initdata cl_init = { | ||
633 | .hostname = data->nfs_server.hostname, | ||
634 | .addr = (const struct sockaddr *)&data->nfs_server.address, | ||
635 | .addrlen = data->nfs_server.addrlen, | ||
636 | .rpc_ops = &nfs_v2_clientops, | ||
637 | .proto = data->nfs_server.protocol, | ||
638 | }; | ||
639 | struct rpc_timeout timeparms; | ||
547 | struct nfs_client *clp; | 640 | struct nfs_client *clp; |
548 | int error, nfsvers = 2; | 641 | int error; |
549 | 642 | ||
550 | dprintk("--> nfs_init_server()\n"); | 643 | dprintk("--> nfs_init_server()\n"); |
551 | 644 | ||
552 | #ifdef CONFIG_NFS_V3 | 645 | #ifdef CONFIG_NFS_V3 |
553 | if (data->flags & NFS_MOUNT_VER3) | 646 | if (data->flags & NFS_MOUNT_VER3) |
554 | nfsvers = 3; | 647 | cl_init.rpc_ops = &nfs_v3_clientops; |
555 | #endif | 648 | #endif |
556 | 649 | ||
557 | /* Allocate or find a client reference we can use */ | 650 | /* Allocate or find a client reference we can use */ |
558 | clp = nfs_get_client(data->nfs_server.hostname, | 651 | clp = nfs_get_client(&cl_init); |
559 | &data->nfs_server.address, nfsvers); | ||
560 | if (IS_ERR(clp)) { | 652 | if (IS_ERR(clp)) { |
561 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | 653 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); |
562 | return PTR_ERR(clp); | 654 | return PTR_ERR(clp); |
563 | } | 655 | } |
564 | 656 | ||
565 | error = nfs_init_client(clp, data); | 657 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
658 | data->timeo, data->retrans); | ||
659 | error = nfs_init_client(clp, &timeparms, data); | ||
566 | if (error < 0) | 660 | if (error < 0) |
567 | goto error; | 661 | goto error; |
568 | 662 | ||
@@ -586,7 +680,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
586 | if (error < 0) | 680 | if (error < 0) |
587 | goto error; | 681 | goto error; |
588 | 682 | ||
589 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 683 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
590 | if (error < 0) | 684 | if (error < 0) |
591 | goto error; | 685 | goto error; |
592 | 686 | ||
@@ -732,6 +826,9 @@ static struct nfs_server *nfs_alloc_server(void) | |||
732 | INIT_LIST_HEAD(&server->client_link); | 826 | INIT_LIST_HEAD(&server->client_link); |
733 | INIT_LIST_HEAD(&server->master_link); | 827 | INIT_LIST_HEAD(&server->master_link); |
734 | 828 | ||
829 | init_waitqueue_head(&server->active_wq); | ||
830 | atomic_set(&server->active, 0); | ||
831 | |||
735 | server->io_stats = nfs_alloc_iostats(); | 832 | server->io_stats = nfs_alloc_iostats(); |
736 | if (!server->io_stats) { | 833 | if (!server->io_stats) { |
737 | kfree(server); | 834 | kfree(server); |
@@ -755,6 +852,9 @@ void nfs_free_server(struct nfs_server *server) | |||
755 | 852 | ||
756 | if (server->destroy != NULL) | 853 | if (server->destroy != NULL) |
757 | server->destroy(server); | 854 | server->destroy(server); |
855 | |||
856 | if (!IS_ERR(server->client_acl)) | ||
857 | rpc_shutdown_client(server->client_acl); | ||
758 | if (!IS_ERR(server->client)) | 858 | if (!IS_ERR(server->client)) |
759 | rpc_shutdown_client(server->client); | 859 | rpc_shutdown_client(server->client); |
760 | 860 | ||
@@ -840,7 +940,7 @@ error: | |||
840 | * Initialise an NFS4 client record | 940 | * Initialise an NFS4 client record |
841 | */ | 941 | */ |
842 | static int nfs4_init_client(struct nfs_client *clp, | 942 | static int nfs4_init_client(struct nfs_client *clp, |
843 | int proto, int timeo, int retrans, | 943 | const struct rpc_timeout *timeparms, |
844 | const char *ip_addr, | 944 | const char *ip_addr, |
845 | rpc_authflavor_t authflavour) | 945 | rpc_authflavor_t authflavour) |
846 | { | 946 | { |
@@ -855,7 +955,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
855 | /* Check NFS protocol revision and initialize RPC op vector */ | 955 | /* Check NFS protocol revision and initialize RPC op vector */ |
856 | clp->rpc_ops = &nfs_v4_clientops; | 956 | clp->rpc_ops = &nfs_v4_clientops; |
857 | 957 | ||
858 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour, | 958 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
859 | RPC_CLNT_CREATE_DISCRTRY); | 959 | RPC_CLNT_CREATE_DISCRTRY); |
860 | if (error < 0) | 960 | if (error < 0) |
861 | goto error; | 961 | goto error; |
@@ -882,23 +982,32 @@ error: | |||
882 | * Set up an NFS4 client | 982 | * Set up an NFS4 client |
883 | */ | 983 | */ |
884 | static int nfs4_set_client(struct nfs_server *server, | 984 | static int nfs4_set_client(struct nfs_server *server, |
885 | const char *hostname, const struct sockaddr_in *addr, | 985 | const char *hostname, |
986 | const struct sockaddr *addr, | ||
987 | const size_t addrlen, | ||
886 | const char *ip_addr, | 988 | const char *ip_addr, |
887 | rpc_authflavor_t authflavour, | 989 | rpc_authflavor_t authflavour, |
888 | int proto, int timeo, int retrans) | 990 | int proto, const struct rpc_timeout *timeparms) |
889 | { | 991 | { |
992 | struct nfs_client_initdata cl_init = { | ||
993 | .hostname = hostname, | ||
994 | .addr = addr, | ||
995 | .addrlen = addrlen, | ||
996 | .rpc_ops = &nfs_v4_clientops, | ||
997 | .proto = proto, | ||
998 | }; | ||
890 | struct nfs_client *clp; | 999 | struct nfs_client *clp; |
891 | int error; | 1000 | int error; |
892 | 1001 | ||
893 | dprintk("--> nfs4_set_client()\n"); | 1002 | dprintk("--> nfs4_set_client()\n"); |
894 | 1003 | ||
895 | /* Allocate or find a client reference we can use */ | 1004 | /* Allocate or find a client reference we can use */ |
896 | clp = nfs_get_client(hostname, addr, 4); | 1005 | clp = nfs_get_client(&cl_init); |
897 | if (IS_ERR(clp)) { | 1006 | if (IS_ERR(clp)) { |
898 | error = PTR_ERR(clp); | 1007 | error = PTR_ERR(clp); |
899 | goto error; | 1008 | goto error; |
900 | } | 1009 | } |
901 | error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour); | 1010 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour); |
902 | if (error < 0) | 1011 | if (error < 0) |
903 | goto error_put; | 1012 | goto error_put; |
904 | 1013 | ||
@@ -919,10 +1028,26 @@ error: | |||
919 | static int nfs4_init_server(struct nfs_server *server, | 1028 | static int nfs4_init_server(struct nfs_server *server, |
920 | const struct nfs_parsed_mount_data *data) | 1029 | const struct nfs_parsed_mount_data *data) |
921 | { | 1030 | { |
1031 | struct rpc_timeout timeparms; | ||
922 | int error; | 1032 | int error; |
923 | 1033 | ||
924 | dprintk("--> nfs4_init_server()\n"); | 1034 | dprintk("--> nfs4_init_server()\n"); |
925 | 1035 | ||
1036 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | ||
1037 | data->timeo, data->retrans); | ||
1038 | |||
1039 | /* Get a client record */ | ||
1040 | error = nfs4_set_client(server, | ||
1041 | data->nfs_server.hostname, | ||
1042 | (const struct sockaddr *)&data->nfs_server.address, | ||
1043 | data->nfs_server.addrlen, | ||
1044 | data->client_address, | ||
1045 | data->auth_flavors[0], | ||
1046 | data->nfs_server.protocol, | ||
1047 | &timeparms); | ||
1048 | if (error < 0) | ||
1049 | goto error; | ||
1050 | |||
926 | /* Initialise the client representation from the mount data */ | 1051 | /* Initialise the client representation from the mount data */ |
927 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | 1052 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; |
928 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1053 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
@@ -937,8 +1062,9 @@ static int nfs4_init_server(struct nfs_server *server, | |||
937 | server->acdirmin = data->acdirmin * HZ; | 1062 | server->acdirmin = data->acdirmin * HZ; |
938 | server->acdirmax = data->acdirmax * HZ; | 1063 | server->acdirmax = data->acdirmax * HZ; |
939 | 1064 | ||
940 | error = nfs_init_server_rpcclient(server, data->auth_flavors[0]); | 1065 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
941 | 1066 | ||
1067 | error: | ||
942 | /* Done */ | 1068 | /* Done */ |
943 | dprintk("<-- nfs4_init_server() = %d\n", error); | 1069 | dprintk("<-- nfs4_init_server() = %d\n", error); |
944 | return error; | 1070 | return error; |
@@ -961,17 +1087,6 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
961 | if (!server) | 1087 | if (!server) |
962 | return ERR_PTR(-ENOMEM); | 1088 | return ERR_PTR(-ENOMEM); |
963 | 1089 | ||
964 | /* Get a client record */ | ||
965 | error = nfs4_set_client(server, | ||
966 | data->nfs_server.hostname, | ||
967 | &data->nfs_server.address, | ||
968 | data->client_address, | ||
969 | data->auth_flavors[0], | ||
970 | data->nfs_server.protocol, | ||
971 | data->timeo, data->retrans); | ||
972 | if (error < 0) | ||
973 | goto error; | ||
974 | |||
975 | /* set up the general RPC client */ | 1090 | /* set up the general RPC client */ |
976 | error = nfs4_init_server(server, data); | 1091 | error = nfs4_init_server(server, data); |
977 | if (error < 0) | 1092 | if (error < 0) |
@@ -1039,12 +1154,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1039 | 1154 | ||
1040 | /* Get a client representation. | 1155 | /* Get a client representation. |
1041 | * Note: NFSv4 always uses TCP, */ | 1156 | * Note: NFSv4 always uses TCP, */ |
1042 | error = nfs4_set_client(server, data->hostname, data->addr, | 1157 | error = nfs4_set_client(server, data->hostname, |
1043 | parent_client->cl_ipaddr, | 1158 | data->addr, |
1044 | data->authflavor, | 1159 | data->addrlen, |
1045 | parent_server->client->cl_xprt->prot, | 1160 | parent_client->cl_ipaddr, |
1046 | parent_client->retrans_timeo, | 1161 | data->authflavor, |
1047 | parent_client->retrans_count); | 1162 | parent_server->client->cl_xprt->prot, |
1163 | parent_server->client->cl_timeout); | ||
1048 | if (error < 0) | 1164 | if (error < 0) |
1049 | goto error; | 1165 | goto error; |
1050 | 1166 | ||
@@ -1052,7 +1168,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1052 | nfs_server_copy_userdata(server, parent_server); | 1168 | nfs_server_copy_userdata(server, parent_server); |
1053 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1169 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
1054 | 1170 | ||
1055 | error = nfs_init_server_rpcclient(server, data->authflavor); | 1171 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
1056 | if (error < 0) | 1172 | if (error < 0) |
1057 | goto error; | 1173 | goto error; |
1058 | 1174 | ||
@@ -1121,7 +1237,9 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1121 | 1237 | ||
1122 | server->fsid = fattr->fsid; | 1238 | server->fsid = fattr->fsid; |
1123 | 1239 | ||
1124 | error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor); | 1240 | error = nfs_init_server_rpcclient(server, |
1241 | source->client->cl_timeout, | ||
1242 | source->client->cl_auth->au_flavor); | ||
1125 | if (error < 0) | 1243 | if (error < 0) |
1126 | goto out_free_server; | 1244 | goto out_free_server; |
1127 | if (!IS_ERR(source->client_acl)) | 1245 | if (!IS_ERR(source->client_acl)) |
@@ -1263,10 +1381,10 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
1263 | /* display one transport per line on subsequent lines */ | 1381 | /* display one transport per line on subsequent lines */ |
1264 | clp = list_entry(v, struct nfs_client, cl_share_link); | 1382 | clp = list_entry(v, struct nfs_client, cl_share_link); |
1265 | 1383 | ||
1266 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | 1384 | seq_printf(m, "v%u %s %s %3d %s\n", |
1267 | clp->cl_nfsversion, | 1385 | clp->rpc_ops->version, |
1268 | NIPQUAD(clp->cl_addr.sin_addr), | 1386 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1269 | ntohs(clp->cl_addr.sin_port), | 1387 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1270 | atomic_read(&clp->cl_count), | 1388 | atomic_read(&clp->cl_count), |
1271 | clp->cl_hostname); | 1389 | clp->cl_hostname); |
1272 | 1390 | ||
@@ -1342,10 +1460,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1342 | (unsigned long long) server->fsid.major, | 1460 | (unsigned long long) server->fsid.major, |
1343 | (unsigned long long) server->fsid.minor); | 1461 | (unsigned long long) server->fsid.minor); |
1344 | 1462 | ||
1345 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | 1463 | seq_printf(m, "v%u %s %s %-7s %-17s\n", |
1346 | clp->cl_nfsversion, | 1464 | clp->rpc_ops->version, |
1347 | NIPQUAD(clp->cl_addr.sin_addr), | 1465 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1348 | ntohs(clp->cl_addr.sin_port), | 1466 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1349 | dev, | 1467 | dev, |
1350 | fsid); | 1468 | fsid); |
1351 | 1469 | ||