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

Reply via email to