On Tue, Jan 10, 2017 at 09:46:30PM +0100, Alexander Bluhm wrote: > When I force to unmount a filesystem where another mountpoint is > located, an unlinked mountpoint will remain. I have not found a > way to restore the kernel to a sane state. > > ok?
anyone? bluhm Index: kern/vfs_syscalls.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.268 diff -u -p -r1.268 vfs_syscalls.c --- kern/vfs_syscalls.c 15 Jan 2017 23:18:05 -0000 1.268 +++ kern/vfs_syscalls.c 16 Jan 2017 00:01:54 -0000 @@ -88,6 +88,8 @@ int domkdirat(struct proc *, int, const int doutimensat(struct proc *, int, const char *, struct timespec [2], int); int dovutimens(struct proc *, struct vnode *, struct timespec [2]); int dofutimens(struct proc *, int, struct timespec [2]); +int dounmount_leaf(struct mount *, int, struct proc *); +int unmount_vnode(struct vnode *, void *); /* * Virtual File System System Calls @@ -368,11 +370,67 @@ sys_unmount(struct proc *p, void *v, reg return (dounmount(mp, SCARG(uap, flags) & MNT_FORCE, p)); } +struct unmount_args { + TAILQ_HEAD(ua_mphead, mount) ua_mplist; + int ua_flags; +}; + +int +unmount_vnode(struct vnode *vp, void *args) +{ + struct unmount_args *ua = args; + struct mount *mp; + + if (vp->v_type != VDIR) + return (0); + if ((mp = vp->v_mountedhere) == NULL) + return (0); + if (!(ua->ua_flags & MNT_FORCE)) + return (EBUSY); + if (vfs_busy(mp, VB_WRITE|VB_WAIT)) + return ((ua->ua_flags & MNT_DOOMED) ? 0 : EBUSY); + + TAILQ_INSERT_HEAD(&ua->ua_mplist, mp, mnt_dounmount); + + return (0); +} + /* * Do the actual file system unmount. */ int dounmount(struct mount *mp, int flags, struct proc *p) +{ + struct unmount_args ua; + int error; + + TAILQ_INIT(&ua.ua_mplist); + TAILQ_INSERT_HEAD(&ua.ua_mplist, mp, mnt_dounmount); + ua.ua_flags = flags; + TAILQ_FOREACH_REVERSE(mp, &ua.ua_mplist, ua_mphead, mnt_dounmount) { + error = vfs_mount_foreach_vnode(mp, unmount_vnode, &ua); + if (error) + goto err; + } + + while ((mp = TAILQ_FIRST(&ua.ua_mplist))) { + TAILQ_REMOVE(&ua.ua_mplist, mp, mnt_dounmount); + error = dounmount_leaf(mp, flags, p); + if (error) + goto err; + } + return (0); + + err: + while ((mp = TAILQ_FIRST(&ua.ua_mplist))) { + TAILQ_REMOVE(&ua.ua_mplist, mp, mnt_dounmount); + vfs_unbusy(mp); + } + return (error); +} + +int +dounmount_leaf(struct mount *mp, int flags, struct proc *p) { struct vnode *coveredvp; int error; Index: sys/mount.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/mount.h,v retrieving revision 1.128 diff -u -p -r1.128 mount.h --- sys/mount.h 10 Jan 2017 19:48:32 -0000 1.128 +++ sys/mount.h 16 Jan 2017 00:01:54 -0000 @@ -347,6 +347,7 @@ LIST_HEAD(vnodelst, vnode); struct mount { TAILQ_ENTRY(mount) mnt_list; /* mount list */ + TAILQ_ENTRY(mount) mnt_dounmount; /* unmount work queue */ const struct vfsops *mnt_op; /* operations on fs */ struct vfsconf *mnt_vfc; /* configuration info */ struct vnode *mnt_vnodecovered; /* vnode we mounted on */