[PATCH 10/13] NFS: Add replace transport infrastructure for replication

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Adds nfs4_replace_transport() that goes through next replicated server
from the stored replication locations. It replaces the transport.

Signed-off-by: Malahal Naineni <malahal@xxxxxxxxxx>
---
 fs/nfs/nfs4_fs.h          |    1 +
 fs/nfs/nfs4namespace.c    |  125 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nfs_fs_sb.h |    1 +
 3 files changed, 127 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 7ff0177..b2a973b 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -331,6 +331,7 @@ extern void nfs4_close_state(struct nfs4_state *, fmode_t);
 extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
+int nfs4_replace_transport(struct nfs_server *server);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
 extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index bb80c49..ee75e27 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -263,3 +263,128 @@ out:
 	dprintk("%s: done\n", __func__);
 	return mnt;
 }
+
+/*
+ * Returns zero on success, or a negative errno value.
+ */
+static int nfs4_update_server(struct nfs_server *server, const char *hostname,
+			      struct sockaddr *sap, size_t salen)
+{
+	struct nfs_client *clp = server->nfs_client;
+	struct rpc_clnt *clnt = server->client;
+	struct xprt_create xargs = {
+		.ident		= clp->cl_proto,
+		.net		= &init_net,
+		.dstaddr	= sap,
+		.addrlen	= salen,
+		.servername	= hostname,
+	};
+	char buf[INET6_ADDRSTRLEN + 1];
+	struct sockaddr_storage address;
+	struct sockaddr *localaddr = (struct sockaddr *)&address;
+	int error;
+
+	dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
+			(unsigned long long)server->fsid.major,
+			(unsigned long long)server->fsid.minor,
+			hostname);
+
+	/*
+	 * rpc_lock_client() deadlocks here.  This is because the tasks
+	 * that received NFS4ERR_MOVED are waiting for us to wake them
+	 * when we are done recovering.  But they have bumped
+	 * cl_active_tasks for this clnt, so rpc_lock_client() can't make
+	 * any progress.
+	 */
+#ifdef USE_RPC_LOCK_CLIENT
+	error = rpc_lock_client(clnt, clnt->cl_timeout->to_maxval);
+	if (error != 0) {
+		dprintk("<-- %s(): rpc_lock_client returned %d\n",
+			__func__, error);
+		goto out;
+	}
+#endif	/* USE_RPC_LOCK_CLIENT */
+
+	error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
+	if (error != 0) {
+		dprintk("<-- %s(): rpc_switch_client_transport returned %d\n",
+			__func__, error);
+		goto out;
+	}
+
+	/*
+	 * If we were able to contact the server at @sap, set up a new
+	 * nfs_client and move @server to it.
+	 */
+	error = rpc_localaddr(clnt, localaddr, sizeof(address));
+	if (error != 0) {
+		dprintk("<-- %s(): rpc_localaddr returned %d\n",
+			__func__, error);
+		goto out;
+	}
+	error = -EAFNOSUPPORT;
+	if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
+		dprintk("<-- %s(): rpc_ntop returned %d\n",
+			__func__, error);
+		goto out;
+	}
+	error = nfs4_clone_client(clp, sap, salen, buf, server);
+	if (error != 0) {
+		dprintk("<-- %s(): nfs4_clone_client returned %d\n",
+			__func__, error);
+		goto out;
+	}
+	if (server->nfs_client->cl_hostname == NULL)
+		server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
+
+	dprintk("<-- %s() succeeded\n", __func__);
+
+out:
+#ifdef USE_RPC_LOCK_CLIENT
+	rpc_unlock_client(clnt);
+#endif	/* USE_RPC_LOCK_CLIENT */
+	return error;
+}
+
+int nfs4_replace_transport(struct nfs_server *server)
+{
+	const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+	struct sockaddr *sap;
+	size_t salen;
+	char *hostname;
+	size_t hostnamelen;
+	unsigned int i;
+	int error;
+
+	sap = kmalloc(addr_bufsize, GFP_KERNEL);
+	if (sap == NULL) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	error = -ENOENT;
+	/* Start after the current entry and search until the current entry */
+	for (i = (server->repli_current + 1) % NFS_MAX_REPLI_SERVERS;
+			i != server->repli_current;
+			i = (i + 1) % NFS_MAX_REPLI_SERVERS) {
+		if (server->repli_servers[i] == NULL)
+			continue;
+		hostname = server->repli_servers[i];
+		hostnamelen = strlen(hostname);
+		salen = nfs_parse_server_name(hostname, hostnamelen, sap,
+					      addr_bufsize);
+		if (salen == 0)
+			continue;
+		rpc_set_port(sap, NFS_PORT);
+		error = nfs4_update_server(server, hostname, sap, salen);
+		if (error == 0) {
+			dprintk("%s(): updated with server: %s\n",
+				__func__, hostname);
+			server->repli_current = i;
+			break;
+		}
+	}
+
+out:
+	return error;
+}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 4970c58..f5fd4bb 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -160,6 +160,7 @@ struct nfs_server {
 	struct nfs_fh		*rootfh;
 #define NFS_MAX_REPLI_SERVERS 2
 	char *repli_servers[NFS_MAX_REPLI_SERVERS];
+	int repli_current; /* Current serving replica index */
 
 	atomic_t active; /* Keep trace of any activity to this server */
 
-- 
1.7.8.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux