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>
This commit is contained in:
Родитель
32e62b7c3e
Коммит
800c06a5bf
|
@ -217,6 +217,8 @@ rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
|
|||
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
|
||||
struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
|
||||
struct nfs_fh *, struct nfs_fattr *);
|
||||
int nfs4_replace_transport(struct nfs_server *server,
|
||||
const struct nfs4_fs_locations *locations);
|
||||
|
||||
/* nfs4proc.c */
|
||||
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *);
|
||||
|
|
|
@ -400,3 +400,104 @@ out:
|
|||
rpc_shutdown_client(client);
|
||||
return mnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try one location from the fs_locations array.
|
||||
*
|
||||
* Returns zero on success, or a negative errno value.
|
||||
*/
|
||||
static int nfs4_try_replacing_one_location(struct nfs_server *server,
|
||||
char *page, char *page2,
|
||||
const struct nfs4_fs_location *location)
|
||||
{
|
||||
const size_t addr_bufsize = sizeof(struct sockaddr_storage);
|
||||
struct sockaddr *sap;
|
||||
unsigned int s;
|
||||
size_t salen;
|
||||
int error;
|
||||
|
||||
sap = kmalloc(addr_bufsize, GFP_KERNEL);
|
||||
if (sap == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
error = -ENOENT;
|
||||
for (s = 0; s < location->nservers; s++) {
|
||||
const struct nfs4_string *buf = &location->servers[s];
|
||||
char *hostname;
|
||||
|
||||
if (buf->len <= 0 || buf->len > PAGE_SIZE)
|
||||
continue;
|
||||
|
||||
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL)
|
||||
continue;
|
||||
|
||||
salen = nfs_parse_server_name(buf->data, buf->len,
|
||||
sap, addr_bufsize, server);
|
||||
if (salen == 0)
|
||||
continue;
|
||||
rpc_set_port(sap, NFS_PORT);
|
||||
|
||||
error = -ENOMEM;
|
||||
hostname = kstrndup(buf->data, buf->len, GFP_KERNEL);
|
||||
if (hostname == NULL)
|
||||
break;
|
||||
|
||||
error = nfs4_update_server(server, hostname, sap, salen);
|
||||
kfree(hostname);
|
||||
if (error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(sap);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs4_replace_transport - set up transport to destination server
|
||||
*
|
||||
* @server: export being migrated
|
||||
* @locations: fs_locations array
|
||||
*
|
||||
* Returns zero on success, or a negative errno value.
|
||||
*
|
||||
* The client tries all the entries in the "locations" array, in the
|
||||
* order returned by the server, until one works or the end of the
|
||||
* array is reached.
|
||||
*/
|
||||
int nfs4_replace_transport(struct nfs_server *server,
|
||||
const struct nfs4_fs_locations *locations)
|
||||
{
|
||||
char *page = NULL, *page2 = NULL;
|
||||
int loc, error;
|
||||
|
||||
error = -ENOENT;
|
||||
if (locations == NULL || locations->nlocations <= 0)
|
||||
goto out;
|
||||
|
||||
error = -ENOMEM;
|
||||
page = (char *) __get_free_page(GFP_USER);
|
||||
if (!page)
|
||||
goto out;
|
||||
page2 = (char *) __get_free_page(GFP_USER);
|
||||
if (!page2)
|
||||
goto out;
|
||||
|
||||
for (loc = 0; loc < locations->nlocations; loc++) {
|
||||
const struct nfs4_fs_location *location =
|
||||
&locations->locations[loc];
|
||||
|
||||
if (location == NULL || location->nservers <= 0 ||
|
||||
location->rootpath.ncomponents == 0)
|
||||
continue;
|
||||
|
||||
error = nfs4_try_replacing_one_location(server, page,
|
||||
page2, location);
|
||||
if (error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
free_page((unsigned long)page);
|
||||
free_page((unsigned long)page2);
|
||||
return error;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче