From d9adbeafd8f8b1c2417a208874b621fe3a8fdb26 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 9 Aug 2009 23:17:32 -0700 Subject: [PATCH] NFS - Cleanly unmount NFS on halt/shutdown/reboot * Abort any in-transit RPCs, disallow new RPCs, and disconnect the socket (aka if TCP) when doing a forced NFS unmount. This fixes left over TCP sockets when doing a normal halt/shutdown/reboot. * Related user processes will also unblock, but the unmount code will still block trying to look up the path and this commit does not quite solve that problem. --- sys/kern/vfs_mount.c | 11 ++++++++--- sys/vfs/nfs/nfs.h | 2 +- sys/vfs/nfs/nfs_socket.c | 10 ++++++++++ sys/vfs/nfs/nfs_vfsops.c | 25 +++++++++++++++++++------ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 4e069a1657..e228de68d6 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1103,9 +1103,14 @@ vflush(struct mount *mp, int rootrefs, int flags) * Get the filesystem root vnode. We can vput() it * immediately, since with rootrefs > 0, it won't go away. */ - if ((error = VFS_ROOT(mp, &rootvp)) != 0) - return (error); - vput(rootvp); + if ((error = VFS_ROOT(mp, &rootvp)) != 0) { + if ((flags & FORCECLOSE) == 0) + return (error); + rootrefs = 0; + /* continue anyway */ + } + if (rootrefs) + vput(rootvp); } vflush_info.busy = 0; diff --git a/sys/vfs/nfs/nfs.h b/sys/vfs/nfs/nfs.h index a2284033c9..40c1795b4c 100644 --- a/sys/vfs/nfs/nfs.h +++ b/sys/vfs/nfs/nfs.h @@ -161,7 +161,7 @@ struct nfs_args { #define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ #define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ #define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ -#define NFSMNT_UNUSED0100 0x00000100 +#define NFSMNT_FORCE 0x00000100 /* Forced unmount */ #define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ #define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ #define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ diff --git a/sys/vfs/nfs/nfs_socket.c b/sys/vfs/nfs/nfs_socket.c index f7460d7c3c..9a9048de7f 100644 --- a/sys/vfs/nfs/nfs_socket.c +++ b/sys/vfs/nfs/nfs_socket.c @@ -196,6 +196,8 @@ nfs_connect(struct nfsmount *nmp, struct nfsreq *rep) struct thread *td = &thread0; /* only used for socreate and sobind */ nmp->nm_so = NULL; + if (nmp->nm_flag & NFSMNT_FORCE) + return (EINVAL); saddr = nmp->nm_nam; error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, nmp->nm_soproto, td); @@ -354,6 +356,8 @@ nfs_reconnect(struct nfsmount *nmp, struct nfsreq *rep) while ((error = nfs_connect(nmp, rep)) != 0) { if (error == EINTR || error == ERESTART) return (EINTR); + if (error == EINVAL) + return (error); (void) tsleep((caddr_t)&lbolt, 0, "nfscon", 0); } @@ -1244,6 +1248,12 @@ nfs_request_try(struct nfsreq *rep) */ nfsstats.rpcrequests++; + if (nmp->nm_flag & NFSMNT_FORCE) { + rep->r_flags |= R_SOFTTERM; + rep->r_flags &= ~R_LOCKED; + return (0); + } + /* * Chain request into list of outstanding requests. Be sure * to put it LAST so timer finds oldest requests first. Note diff --git a/sys/vfs/nfs/nfs_vfsops.c b/sys/vfs/nfs/nfs_vfsops.c index f2eb747e15..51e9f06f27 100644 --- a/sys/vfs/nfs/nfs_vfsops.c +++ b/sys/vfs/nfs/nfs_vfsops.c @@ -1047,9 +1047,12 @@ nfs_unmount(struct mount *mp, int mntflags) struct nfsmount *nmp; int error, flags = 0; - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; nmp = VFSTONFS(mp); + if (mntflags & MNT_FORCE) { + flags |= FORCECLOSE; + nmp->nm_flag |= NFSMNT_FORCE; + } + /* * Goes something like this.. * - Call vflush() to clear out vnodes for this file system @@ -1059,19 +1062,29 @@ nfs_unmount(struct mount *mp, int mntflags) /* In the forced case, cancel any outstanding requests. */ if (flags & FORCECLOSE) { error = nfs_nmcancelreqs(nmp); - if (error) - return (error); + if (error) { + kprintf("NFS: %s: Unable to cancel all requests\n", + mp->mnt_stat.f_mntfromname); + /* continue anyway */ + } } + /* * Must handshake with nfs_clientd() if it is active. XXX */ nmp->nm_state |= NFSSTA_DISMINPROG; - /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ + /* + * We hold 1 extra ref on the root vnode; see comment in mountnfs(). + * + * If this doesn't work and we are doing a forced unmount we continue + * anyway. + */ error = vflush(mp, 1, flags); if (error) { nmp->nm_state &= ~NFSSTA_DISMINPROG; - return (error); + if ((flags & FORCECLOSE) == 0) + return (error); } /* -- 2.41.0