aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-10-17 14:12:28 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-10-28 15:22:29 -0400
commit32e62b7c3ef095eccbb6a8c96fddf05dacc749df (patch)
tree53b2abd3c507a3194fc76dd638e77202bacbb04d
parent40b00b6b17c412ff9ff28631250d32ee29ff0006 (diff)
NFS: Add nfs4_update_server
New function nfs4_update_server() moves an nfs_server to a different nfs_client. This is done as part of migration recovery. Though it may be appealing to think of them as the same thing, migration recovery is not the same as following a referral. For a referral, the client has not descended into the file system yet: it has no nfs_server, no super block, no inodes or open state. It is enough to simply instantiate the nfs_server and super block, and perform a referral mount. For a migration, however, we have all of those things already, and they have to be moved to a different nfs_client. No local namespace changes are needed here. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/client.c3
-rw-r--r--fs/nfs/internal.h3
-rw-r--r--fs/nfs/nfs4client.c108
3 files changed, 113 insertions, 1 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index af0325864df6..692fd0e9362f 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -945,7 +945,7 @@ void nfs_server_insert_lists(struct nfs_server *server)
945} 945}
946EXPORT_SYMBOL_GPL(nfs_server_insert_lists); 946EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
947 947
948static void nfs_server_remove_lists(struct nfs_server *server) 948void nfs_server_remove_lists(struct nfs_server *server)
949{ 949{
950 struct nfs_client *clp = server->nfs_client; 950 struct nfs_client *clp = server->nfs_client;
951 struct nfs_net *nn; 951 struct nfs_net *nn;
@@ -962,6 +962,7 @@ static void nfs_server_remove_lists(struct nfs_server *server)
962 962
963 synchronize_rcu(); 963 synchronize_rcu();
964} 964}
965EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
965 966
966/* 967/*
967 * Allocate and initialise a server record 968 * Allocate and initialise a server record
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 38da8c2b81ac..e5a6bd12562a 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -154,6 +154,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *,
154 rpc_authflavor_t); 154 rpc_authflavor_t);
155int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); 155int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *);
156void nfs_server_insert_lists(struct nfs_server *); 156void nfs_server_insert_lists(struct nfs_server *);
157void nfs_server_remove_lists(struct nfs_server *);
157void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); 158void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int);
158int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, 159int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t,
159 rpc_authflavor_t); 160 rpc_authflavor_t);
@@ -174,6 +175,8 @@ extern struct nfs_server *nfs4_create_server(
174 struct nfs_subversion *); 175 struct nfs_subversion *);
175extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, 176extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
176 struct nfs_fh *); 177 struct nfs_fh *);
178extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
179 struct sockaddr *sap, size_t salen);
177extern void nfs_free_server(struct nfs_server *server); 180extern void nfs_free_server(struct nfs_server *server);
178extern struct nfs_server *nfs_clone_server(struct nfs_server *, 181extern struct nfs_server *nfs_clone_server(struct nfs_server *,
179 struct nfs_fh *, 182 struct nfs_fh *,
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 511cdce6ecf2..c6eee812337f 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1092,3 +1092,111 @@ error:
1092 dprintk("<-- nfs4_create_referral_server() = error %d\n", error); 1092 dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
1093 return ERR_PTR(error); 1093 return ERR_PTR(error);
1094} 1094}
1095
1096/*
1097 * Grab the destination's particulars, including lease expiry time.
1098 *
1099 * Returns zero if probe succeeded and retrieved FSID matches the FSID
1100 * we have cached.
1101 */
1102static int nfs_probe_destination(struct nfs_server *server)
1103{
1104 struct inode *inode = server->super->s_root->d_inode;
1105 struct nfs_fattr *fattr;
1106 int error;
1107
1108 fattr = nfs_alloc_fattr();
1109 if (fattr == NULL)
1110 return -ENOMEM;
1111
1112 /* Sanity: the probe won't work if the destination server
1113 * does not recognize the migrated FH. */
1114 error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr);
1115
1116 nfs_free_fattr(fattr);
1117 return error;
1118}
1119
1120/**
1121 * nfs4_update_server - Move an nfs_server to a different nfs_client
1122 *
1123 * @server: represents FSID to be moved
1124 * @hostname: new end-point's hostname
1125 * @sap: new end-point's socket address
1126 * @salen: size of "sap"
1127 *
1128 * The nfs_server must be quiescent before this function is invoked.
1129 * Either its session is drained (NFSv4.1+), or its transport is
1130 * plugged and drained (NFSv4.0).
1131 *
1132 * Returns zero on success, or a negative errno value.
1133 */
1134int nfs4_update_server(struct nfs_server *server, const char *hostname,
1135 struct sockaddr *sap, size_t salen)
1136{
1137 struct nfs_client *clp = server->nfs_client;
1138 struct rpc_clnt *clnt = server->client;
1139 struct xprt_create xargs = {
1140 .ident = clp->cl_proto,
1141 .net = &init_net,
1142 .dstaddr = sap,
1143 .addrlen = salen,
1144 .servername = hostname,
1145 };
1146 char buf[INET6_ADDRSTRLEN + 1];
1147 struct sockaddr_storage address;
1148 struct sockaddr *localaddr = (struct sockaddr *)&address;
1149 int error;
1150
1151 dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
1152 (unsigned long long)server->fsid.major,
1153 (unsigned long long)server->fsid.minor,
1154 hostname);
1155
1156 error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
1157 if (error != 0) {
1158 dprintk("<-- %s(): rpc_switch_client_transport returned %d\n",
1159 __func__, error);
1160 goto out;
1161 }
1162
1163 error = rpc_localaddr(clnt, localaddr, sizeof(address));
1164 if (error != 0) {
1165 dprintk("<-- %s(): rpc_localaddr returned %d\n",
1166 __func__, error);
1167 goto out;
1168 }
1169
1170 error = -EAFNOSUPPORT;
1171 if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
1172 dprintk("<-- %s(): rpc_ntop returned %d\n",
1173 __func__, error);
1174 goto out;
1175 }
1176
1177 nfs_server_remove_lists(server);
1178 error = nfs4_set_client(server, hostname, sap, salen, buf,
1179 clp->cl_rpcclient->cl_auth->au_flavor,
1180 clp->cl_proto, clnt->cl_timeout,
1181 clp->cl_minorversion, clp->cl_net);
1182 nfs_put_client(clp);
1183 if (error != 0) {
1184 nfs_server_insert_lists(server);
1185 dprintk("<-- %s(): nfs4_set_client returned %d\n",
1186 __func__, error);
1187 goto out;
1188 }
1189
1190 if (server->nfs_client->cl_hostname == NULL)
1191 server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
1192 nfs_server_insert_lists(server);
1193
1194 error = nfs_probe_destination(server);
1195 if (error < 0)
1196 goto out;
1197
1198 dprintk("<-- %s() succeeded\n", __func__);
1199
1200out:
1201 return error;
1202}