diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2013-10-17 14:12:34 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-10-28 15:23:07 -0400 |
commit | 800c06a5bf497e0587ba8382a761f31a7825e2cd (patch) | |
tree | b76eeaf2ae9a6fb7669a4e15693fefb7e7f75899 /fs/nfs | |
parent | 32e62b7c3ef095eccbb6a8c96fddf05dacc749df (diff) |
NFS: Add functions to swap transports during migration recovery
Introduce functions that can walk through an array of returned
fs_locations information and connect a transport to one of the
destination servers listed therein.
Note that NFS minor version 1 introduces "fs_locations_info" which
extends the locations array sorting criteria available to clients.
This is not supported yet.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 101 |
2 files changed, 103 insertions, 0 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 28842abafab4..fcae7289d557 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -217,6 +217,8 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); | |||
217 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); | 217 | struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); |
218 | struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, | 218 | struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, |
219 | struct nfs_fh *, struct nfs_fattr *); | 219 | struct nfs_fh *, struct nfs_fattr *); |
220 | int nfs4_replace_transport(struct nfs_server *server, | ||
221 | const struct nfs4_fs_locations *locations); | ||
220 | 222 | ||
221 | /* nfs4proc.c */ | 223 | /* nfs4proc.c */ |
222 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); | 224 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 2288cd3c9278..ebd8b064843b 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -400,3 +400,104 @@ out: | |||
400 | rpc_shutdown_client(client); | 400 | rpc_shutdown_client(client); |
401 | return mnt; | 401 | return mnt; |
402 | } | 402 | } |
403 | |||
404 | /* | ||
405 | * Try one location from the fs_locations array. | ||
406 | * | ||
407 | * Returns zero on success, or a negative errno value. | ||
408 | */ | ||
409 | static int nfs4_try_replacing_one_location(struct nfs_server *server, | ||
410 | char *page, char *page2, | ||
411 | const struct nfs4_fs_location *location) | ||
412 | { | ||
413 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | ||
414 | struct sockaddr *sap; | ||
415 | unsigned int s; | ||
416 | size_t salen; | ||
417 | int error; | ||
418 | |||
419 | sap = kmalloc(addr_bufsize, GFP_KERNEL); | ||
420 | if (sap == NULL) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | error = -ENOENT; | ||
424 | for (s = 0; s < location->nservers; s++) { | ||
425 | const struct nfs4_string *buf = &location->servers[s]; | ||
426 | char *hostname; | ||
427 | |||
428 | if (buf->len <= 0 || buf->len > PAGE_SIZE) | ||
429 | continue; | ||
430 | |||
431 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL) | ||
432 | continue; | ||
433 | |||
434 | salen = nfs_parse_server_name(buf->data, buf->len, | ||
435 | sap, addr_bufsize, server); | ||
436 | if (salen == 0) | ||
437 | continue; | ||
438 | rpc_set_port(sap, NFS_PORT); | ||
439 | |||
440 | error = -ENOMEM; | ||
441 | hostname = kstrndup(buf->data, buf->len, GFP_KERNEL); | ||
442 | if (hostname == NULL) | ||
443 | break; | ||
444 | |||
445 | error = nfs4_update_server(server, hostname, sap, salen); | ||
446 | kfree(hostname); | ||
447 | if (error == 0) | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | kfree(sap); | ||
452 | return error; | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * nfs4_replace_transport - set up transport to destination server | ||
457 | * | ||
458 | * @server: export being migrated | ||
459 | * @locations: fs_locations array | ||
460 | * | ||
461 | * Returns zero on success, or a negative errno value. | ||
462 | * | ||
463 | * The client tries all the entries in the "locations" array, in the | ||
464 | * order returned by the server, until one works or the end of the | ||
465 | * array is reached. | ||
466 | */ | ||
467 | int nfs4_replace_transport(struct nfs_server *server, | ||
468 | const struct nfs4_fs_locations *locations) | ||
469 | { | ||
470 | char *page = NULL, *page2 = NULL; | ||
471 | int loc, error; | ||
472 | |||
473 | error = -ENOENT; | ||
474 | if (locations == NULL || locations->nlocations <= 0) | ||
475 | goto out; | ||
476 | |||
477 | error = -ENOMEM; | ||
478 | page = (char *) __get_free_page(GFP_USER); | ||
479 | if (!page) | ||
480 | goto out; | ||
481 | page2 = (char *) __get_free_page(GFP_USER); | ||
482 | if (!page2) | ||
483 | goto out; | ||
484 | |||
485 | for (loc = 0; loc < locations->nlocations; loc++) { | ||
486 | const struct nfs4_fs_location *location = | ||
487 | &locations->locations[loc]; | ||
488 | |||
489 | if (location == NULL || location->nservers <= 0 || | ||
490 | location->rootpath.ncomponents == 0) | ||
491 | continue; | ||
492 | |||
493 | error = nfs4_try_replacing_one_location(server, page, | ||
494 | page2, location); | ||
495 | if (error == 0) | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | out: | ||
500 | free_page((unsigned long)page); | ||
501 | free_page((unsigned long)page2); | ||
502 | return error; | ||
503 | } | ||