aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-10-17 14:12:34 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-10-28 15:23:07 -0400
commit800c06a5bf497e0587ba8382a761f31a7825e2cd (patch)
treeb76eeaf2ae9a6fb7669a4e15693fefb7e7f75899 /fs/nfs
parent32e62b7c3ef095eccbb6a8c96fddf05dacc749df (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.h2
-rw-r--r--fs/nfs/nfs4namespace.c101
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 *);
217struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *); 217struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
218struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, 218struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
219 struct nfs_fh *, struct nfs_fattr *); 219 struct nfs_fh *, struct nfs_fattr *);
220int nfs4_replace_transport(struct nfs_server *server,
221 const struct nfs4_fs_locations *locations);
220 222
221/* nfs4proc.c */ 223/* nfs4proc.c */
222extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); 224extern 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 */
409static 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 */
467int 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
499out:
500 free_page((unsigned long)page);
501 free_page((unsigned long)page2);
502 return error;
503}