59f69ba49f
After disscussing things I have decided to take the easy and consistent 90% solution instead of aiming for the very involved 99% solution. If we allow forceful unmounts of DEVFS we need to decide how to handle the devices which are in use through this filesystem at the time. We cannot just readopt the open devices in the main /dev instance since that would open us to security issues. For the majority of the devices, this is relatively straightforward as we can just pretend they got revoke(2)'ed. Some devices get tricky: /dev/console and /dev/tty for instance does a sort of recursive open of the real console device. Other devices may be mmap'ed (kill the processes ?). And then there are disk devices which are mounted. The correct thing here would be to recursively unmount the filesystems mounte from devices from our DEVFS instance (forcefully) and if this succeeds, complete the forcefully unmount of DEVFS. But if one of the forceful unmounts fail we cannot complete the forceful unmount of DEVFS, but we are likely to already have severed a lot of stuff in the process of trying. Event attempting this would be a lot of code for a very far out corner-case which most people would never see or get in touch with. It's just not worth it.
185 lines
4.5 KiB
C
185 lines
4.5 KiB
C
/*
|
|
* Copyright (c) 1992, 1993, 1995
|
|
* The Regents of the University of California. All rights reserved.
|
|
* Copyright (c) 2000
|
|
* Poul-Henning Kamp. All rights reserved.
|
|
*
|
|
* This code is derived from software donated to Berkeley by
|
|
* Jan-Simon Pendry.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95
|
|
* From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "opt_devfs.h"
|
|
#include "opt_mac.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/mac.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/vnode.h>
|
|
|
|
#include <fs/devfs/devfs.h>
|
|
|
|
MALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data");
|
|
|
|
static vfs_mount_t devfs_mount;
|
|
static vfs_unmount_t devfs_unmount;
|
|
static vfs_root_t devfs_root;
|
|
static vfs_statfs_t devfs_statfs;
|
|
|
|
/*
|
|
* Mount the filesystem
|
|
*/
|
|
static int
|
|
devfs_mount(struct mount *mp, struct thread *td)
|
|
{
|
|
int error;
|
|
struct devfs_mount *fmp;
|
|
struct vnode *rvp;
|
|
|
|
error = 0;
|
|
|
|
if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))
|
|
return (EOPNOTSUPP);
|
|
|
|
MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount),
|
|
M_DEVFS, M_WAITOK | M_ZERO);
|
|
MALLOC(fmp->dm_dirent, struct devfs_dirent **,
|
|
sizeof(struct devfs_dirent *) * NDEVFSINO,
|
|
M_DEVFS, M_WAITOK | M_ZERO);
|
|
lockinit(&fmp->dm_lock, PVFS, "devfs", 0, LK_NOPAUSE);
|
|
|
|
mp->mnt_flag |= MNT_LOCAL;
|
|
#ifdef MAC
|
|
mp->mnt_flag |= MNT_MULTILABEL;
|
|
#endif
|
|
fmp->dm_mount = mp;
|
|
mp->mnt_data = (qaddr_t) fmp;
|
|
vfs_getnewfsid(mp);
|
|
|
|
fmp->dm_inode = DEVFSINOMOUNT;
|
|
|
|
fmp->dm_rootdir = devfs_vmkdir("(root)", 6, NULL);
|
|
fmp->dm_rootdir->de_inode = 2;
|
|
#ifdef MAC
|
|
mac_create_devfs_directory(mp, "", 0, fmp->dm_rootdir);
|
|
#endif
|
|
fmp->dm_basedir = fmp->dm_rootdir;
|
|
devfs_rules_newmount(fmp, td);
|
|
|
|
error = devfs_root(mp, &rvp, td);
|
|
if (error) {
|
|
lockdestroy(&fmp->dm_lock);
|
|
FREE(fmp, M_DEVFS);
|
|
return (error);
|
|
}
|
|
|
|
VOP_UNLOCK(rvp, 0, td);
|
|
|
|
vfs_mountedfrom(mp, "devfs");
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
devfs_unmount(mp, mntflags, td)
|
|
struct mount *mp;
|
|
int mntflags;
|
|
struct thread *td;
|
|
{
|
|
int error;
|
|
int flags = 0;
|
|
struct devfs_mount *fmp;
|
|
|
|
fmp = VFSTODEVFS(mp);
|
|
if (mntflags & MNT_FORCE)
|
|
return (EOPNOTSUPP);
|
|
/* There is 1 extra root vnode reference from devfs_mount(). */
|
|
error = vflush(mp, 1, flags, td);
|
|
if (error)
|
|
return (error);
|
|
devfs_purge(fmp->dm_rootdir);
|
|
mp->mnt_data = 0;
|
|
lockdestroy(&fmp->dm_lock);
|
|
free(fmp->dm_dirent, M_DEVFS);
|
|
free(fmp, M_DEVFS);
|
|
return 0;
|
|
}
|
|
|
|
/* Return locked reference to root. */
|
|
|
|
static int
|
|
devfs_root(mp, vpp, td)
|
|
struct mount *mp;
|
|
struct vnode **vpp;
|
|
struct thread *td;
|
|
{
|
|
int error;
|
|
struct vnode *vp;
|
|
struct devfs_mount *dmp;
|
|
|
|
dmp = VFSTODEVFS(mp);
|
|
error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td);
|
|
if (error)
|
|
return (error);
|
|
vp->v_vflag |= VV_ROOT;
|
|
*vpp = vp;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
devfs_statfs(mp, sbp, td)
|
|
struct mount *mp;
|
|
struct statfs *sbp;
|
|
struct thread *td;
|
|
{
|
|
|
|
sbp->f_flags = 0;
|
|
sbp->f_bsize = DEV_BSIZE;
|
|
sbp->f_iosize = DEV_BSIZE;
|
|
sbp->f_blocks = 2; /* 1K to keep df happy */
|
|
sbp->f_bfree = 0;
|
|
sbp->f_bavail = 0;
|
|
sbp->f_files = 0;
|
|
sbp->f_ffree = 0;
|
|
return (0);
|
|
}
|
|
|
|
static struct vfsops devfs_vfsops = {
|
|
.vfs_mount = devfs_mount,
|
|
.vfs_root = devfs_root,
|
|
.vfs_statfs = devfs_statfs,
|
|
.vfs_unmount = devfs_unmount,
|
|
};
|
|
|
|
VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC);
|