Hi,

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.

# mount /dev/vnd0a /mnt
# mkdir /mnt/mnt
# mount /dev/vnd1a /mnt/mnt
# mount
/dev/sd0a on / type ffs (local)
/dev/vnd0a on /mnt type ffs (local)
/dev/vnd1a on /mnt/mnt type ffs (local)
# umount /mnt
umount: /mnt: Device busy
# umount -f /mnt
# mount
/dev/sd0a on / type ffs (local)
/dev/vnd1a on /mnt/mnt type ffs (local)
# umount /mnt/mnt
umount: /mnt/mnt: No such file or directory
# mkdir /mnt/mnt
# umount /mnt/mnt
umount: /mnt/mnt: Invalid argument
# vnconfig -u vnd1
vnconfig: VNDIOCCLR: Device busy

The fix could be to unmount recursively.

ok?

bluhm

Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.267
diff -u -p -r1.267 vfs_syscalls.c
--- kern/vfs_syscalls.c 10 Jan 2017 20:13:17 -0000      1.267
+++ kern/vfs_syscalls.c 10 Jan 2017 20:36:05 -0000
@@ -88,6 +88,7 @@ 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 unmount_vnode(struct vnode *, void *);
 
 /*
  * Virtual File System System Calls
@@ -368,15 +369,56 @@ sys_unmount(struct proc *p, void *v, reg
        return (dounmount(mp, SCARG(uap, flags) & MNT_FORCE, p));
 }
 
+struct unmount_args {
+       struct proc     *ua_proc;
+       int              ua_flags;
+       int              ua_error;
+};
+
+int
+unmount_vnode(struct vnode *vp, void *args)
+{
+       struct unmount_args *ua = args;
+       struct mount *mp;
+       int error;
+
+       if (vp->v_type != VDIR)
+               return (0);
+       if ((mp = vp->v_mountedhere) == NULL)
+               return (0);
+       if (!(ua->ua_flags & MNT_FORCE)) {
+               ua->ua_error = EBUSY;
+               return (EBUSY);
+       }
+       if (vfs_busy(mp, VB_WRITE|VB_WAIT)) {
+               ua->ua_error = EBUSY;
+               return (0);
+       }
+       error = dounmount(mp, ua->ua_flags, ua->ua_proc);
+       if (error)
+               ua->ua_error = error;
+       return (0);
+}
+
 /*
  * Do the actual file system unmount.
  */
 int
 dounmount(struct mount *mp, int flags, struct proc *p)
 {
+       struct unmount_args ua;
        struct vnode *coveredvp;
        int error;
        int hadsyncer = 0;
+
+       ua.ua_proc = p;
+       ua.ua_flags = flags;
+       ua.ua_error = 0;
+       vfs_mount_foreach_vnode(mp, unmount_vnode, &ua);
+       if (ua.ua_error && !(flags & MNT_DOOMED)) {
+               vfs_unbusy(mp);
+               return (ua.ua_error);
+       }
 
        mp->mnt_flag &=~ MNT_ASYNC;
        cache_purgevfs(mp);     /* remove cache entries for this file sys */

Reply via email to