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/nfs4namespace.c | |
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/nfs4namespace.c')
-rw-r--r-- | fs/nfs/nfs4namespace.c | 101 |
1 files changed, 101 insertions, 0 deletions
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 | } | ||