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