diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2013-10-17 14:12:28 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-10-28 15:22:29 -0400 |
commit | 32e62b7c3ef095eccbb6a8c96fddf05dacc749df (patch) | |
tree | 53b2abd3c507a3194fc76dd638e77202bacbb04d | |
parent | 40b00b6b17c412ff9ff28631250d32ee29ff0006 (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.c | 3 | ||||
-rw-r--r-- | fs/nfs/internal.h | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 108 |
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 | } |
946 | EXPORT_SYMBOL_GPL(nfs_server_insert_lists); | 946 | EXPORT_SYMBOL_GPL(nfs_server_insert_lists); |
947 | 947 | ||
948 | static void nfs_server_remove_lists(struct nfs_server *server) | 948 | void 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 | } |
965 | EXPORT_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); |
155 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); | 155 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); |
156 | void nfs_server_insert_lists(struct nfs_server *); | 156 | void nfs_server_insert_lists(struct nfs_server *); |
157 | void nfs_server_remove_lists(struct nfs_server *); | ||
157 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); | 158 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); |
158 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, | 159 | int 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 *); |
175 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | 176 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, |
176 | struct nfs_fh *); | 177 | struct nfs_fh *); |
178 | extern int nfs4_update_server(struct nfs_server *server, const char *hostname, | ||
179 | struct sockaddr *sap, size_t salen); | ||
177 | extern void nfs_free_server(struct nfs_server *server); | 180 | extern void nfs_free_server(struct nfs_server *server); |
178 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 181 | extern 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 | */ | ||
1102 | static 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 | */ | ||
1134 | int 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 | |||
1200 | out: | ||
1201 | return error; | ||
1202 | } | ||