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 */