diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2009-08-09 15:09:30 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-09 15:09:30 -0400 |
commit | 0b524123c93893391ec9e6c9b04998a45235f9c8 (patch) | |
tree | 6e65a65ecf9968803e712ccc7063cca4385757e0 /fs/nfs | |
parent | f3f4f4ed26b116f621596f74d42d2b736171e968 (diff) |
NFS: Add ability to send MOUNTPROC_UMNT to the kernel's mountd client
After certain failure modes of an NFS mount, an NFS client should send
a MOUNTPROC_UMNT request to remove the just-added mount entry from the
server's mount table. While no-one should rely on the accuracy of the
server's mount table, sending a UMNT is simply being a good internet
neighbor.
Since NFS mount processing is handled in the kernel now, we will need
a function in the kernel's mountd client that can post a MOUNTRPC_UMNT
request, in order to handle these failure modes.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/internal.h | 1 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 79 |
2 files changed, 80 insertions, 0 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7dd90a6769d..8d2b71d57d2 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -102,6 +102,7 @@ struct nfs_mount_request { | |||
102 | }; | 102 | }; |
103 | 103 | ||
104 | extern int nfs_mount(struct nfs_mount_request *info); | 104 | extern int nfs_mount(struct nfs_mount_request *info); |
105 | extern void nfs_umount(const struct nfs_mount_request *info); | ||
105 | 106 | ||
106 | /* client.c */ | 107 | /* client.c */ |
107 | extern struct rpc_program nfs_program; | 108 | extern struct rpc_program nfs_program; |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 38ef9eaec40..72dd8b6ccaf 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -209,6 +209,71 @@ out_mnt_err: | |||
209 | goto out; | 209 | goto out; |
210 | } | 210 | } |
211 | 211 | ||
212 | /** | ||
213 | * nfs_umount - Notify a server that we have unmounted this export | ||
214 | * @info: pointer to umount request arguments | ||
215 | * | ||
216 | * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always | ||
217 | * use UDP. | ||
218 | */ | ||
219 | void nfs_umount(const struct nfs_mount_request *info) | ||
220 | { | ||
221 | static const struct rpc_timeout nfs_umnt_timeout = { | ||
222 | .to_initval = 1 * HZ, | ||
223 | .to_maxval = 3 * HZ, | ||
224 | .to_retries = 2, | ||
225 | }; | ||
226 | struct rpc_create_args args = { | ||
227 | .protocol = IPPROTO_UDP, | ||
228 | .address = info->sap, | ||
229 | .addrsize = info->salen, | ||
230 | .timeout = &nfs_umnt_timeout, | ||
231 | .servername = info->hostname, | ||
232 | .program = &mnt_program, | ||
233 | .version = info->version, | ||
234 | .authflavor = RPC_AUTH_UNIX, | ||
235 | .flags = RPC_CLNT_CREATE_NOPING, | ||
236 | }; | ||
237 | struct mountres result; | ||
238 | struct rpc_message msg = { | ||
239 | .rpc_argp = info->dirpath, | ||
240 | .rpc_resp = &result, | ||
241 | }; | ||
242 | struct rpc_clnt *clnt; | ||
243 | int status; | ||
244 | |||
245 | if (info->noresvport) | ||
246 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
247 | |||
248 | clnt = rpc_create(&args); | ||
249 | if (unlikely(IS_ERR(clnt))) | ||
250 | goto out_clnt_err; | ||
251 | |||
252 | dprintk("NFS: sending UMNT request for %s:%s\n", | ||
253 | (info->hostname ? info->hostname : "server"), info->dirpath); | ||
254 | |||
255 | if (info->version == NFS_MNT3_VERSION) | ||
256 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT]; | ||
257 | else | ||
258 | msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT]; | ||
259 | |||
260 | status = rpc_call_sync(clnt, &msg, 0); | ||
261 | rpc_shutdown_client(clnt); | ||
262 | |||
263 | if (unlikely(status < 0)) | ||
264 | goto out_call_err; | ||
265 | |||
266 | return; | ||
267 | |||
268 | out_clnt_err: | ||
269 | dprintk("NFS: failed to create UMNT RPC client, status=%ld\n", | ||
270 | PTR_ERR(clnt)); | ||
271 | return; | ||
272 | |||
273 | out_call_err: | ||
274 | dprintk("NFS: UMNT request failed, status=%d\n", status); | ||
275 | } | ||
276 | |||
212 | /* | 277 | /* |
213 | * XDR encode/decode functions for MOUNT | 278 | * XDR encode/decode functions for MOUNT |
214 | */ | 279 | */ |
@@ -407,6 +472,13 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
407 | .p_statidx = MOUNTPROC_MNT, | 472 | .p_statidx = MOUNTPROC_MNT, |
408 | .p_name = "MOUNT", | 473 | .p_name = "MOUNT", |
409 | }, | 474 | }, |
475 | [MOUNTPROC_UMNT] = { | ||
476 | .p_proc = MOUNTPROC_UMNT, | ||
477 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
478 | .p_arglen = MNT_enc_dirpath_sz, | ||
479 | .p_statidx = MOUNTPROC_UMNT, | ||
480 | .p_name = "UMOUNT", | ||
481 | }, | ||
410 | }; | 482 | }; |
411 | 483 | ||
412 | static struct rpc_procinfo mnt3_procedures[] = { | 484 | static struct rpc_procinfo mnt3_procedures[] = { |
@@ -419,6 +491,13 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
419 | .p_statidx = MOUNTPROC3_MNT, | 491 | .p_statidx = MOUNTPROC3_MNT, |
420 | .p_name = "MOUNT", | 492 | .p_name = "MOUNT", |
421 | }, | 493 | }, |
494 | [MOUNTPROC3_UMNT] = { | ||
495 | .p_proc = MOUNTPROC3_UMNT, | ||
496 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, | ||
497 | .p_arglen = MNT_enc_dirpath_sz, | ||
498 | .p_statidx = MOUNTPROC3_UMNT, | ||
499 | .p_name = "UMOUNT", | ||
500 | }, | ||
422 | }; | 501 | }; |
423 | 502 | ||
424 | 503 | ||