|
@@ -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;
|
|
|
+}
|