1139776Simp/*- 264880Sphk * Copyright (c) 1992, 1993, 1995 364880Sphk * The Regents of the University of California. All rights reserved. 464880Sphk * Copyright (c) 2000 564880Sphk * Poul-Henning Kamp. All rights reserved. 664880Sphk * 764880Sphk * This code is derived from software donated to Berkeley by 864880Sphk * Jan-Simon Pendry. 964880Sphk * 1064880Sphk * Redistribution and use in source and binary forms, with or without 1164880Sphk * modification, are permitted provided that the following conditions 1264880Sphk * are met: 1364880Sphk * 1. Redistributions of source code must retain the above copyright 1464880Sphk * notice, this list of conditions and the following disclaimer. 1564880Sphk * 2. Neither the name of the University nor the names of its contributors 1664880Sphk * may be used to endorse or promote products derived from this software 1764880Sphk * without specific prior written permission. 1864880Sphk * 1964880Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2064880Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2164880Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2264880Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2364880Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2464880Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2564880Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2664880Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2764880Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2864880Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2964880Sphk * SUCH DAMAGE. 3064880Sphk * 3164880Sphk * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 3264880Sphk * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 3364880Sphk * 3464880Sphk * $FreeBSD$ 3564880Sphk */ 3664880Sphk 3764880Sphk#include <sys/param.h> 3864880Sphk#include <sys/systm.h> 3964880Sphk#include <sys/kernel.h> 4076166Smarkm#include <sys/lock.h> 4176166Smarkm#include <sys/malloc.h> 4276166Smarkm#include <sys/mount.h> 4376166Smarkm#include <sys/proc.h> 44150342Sphk#include <sys/sx.h> 4564880Sphk#include <sys/vnode.h> 46150342Sphk#include <sys/limits.h> 47232728Smm#include <sys/jail.h> 4864880Sphk 4964880Sphk#include <fs/devfs/devfs.h> 5064880Sphk 51150342Sphkstatic struct unrhdr *devfs_unr; 52150342Sphk 5364880SphkMALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data"); 5464880Sphk 55132902Sphkstatic vfs_mount_t devfs_mount; 56101777Sphkstatic vfs_unmount_t devfs_unmount; 57101777Sphkstatic vfs_root_t devfs_root; 58101777Sphkstatic vfs_statfs_t devfs_statfs; 5964880Sphk 60232728Smmstatic const char *devfs_opts[] = { 61232728Smm "from", "export", "ruleset", NULL 62232728Smm}; 63232728Smm 6464880Sphk/* 6564880Sphk * Mount the filesystem 6664880Sphk */ 6764880Sphkstatic int 68191990Sattiliodevfs_mount(struct mount *mp) 6964880Sphk{ 7065132Sphk int error; 7164880Sphk struct devfs_mount *fmp; 7264880Sphk struct vnode *rvp; 73232728Smm struct thread *td = curthread; 74232728Smm int injail, rsnum; 7564880Sphk 76150342Sphk if (devfs_unr == NULL) 77150342Sphk devfs_unr = new_unrhdr(0, INT_MAX, NULL); 78150342Sphk 7965132Sphk error = 0; 80137006Sphk 81232728Smm if (mp->mnt_flag & MNT_ROOTFS) 8264880Sphk return (EOPNOTSUPP); 8364880Sphk 84232728Smm if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_DEVFS)) 85232728Smm return (EPERM); 86232728Smm 87232728Smm rsnum = 0; 88232728Smm injail = jailed(td->td_ucred); 89232728Smm 90232728Smm if (mp->mnt_optnew != NULL) { 91232728Smm if (vfs_filteropt(mp->mnt_optnew, devfs_opts)) 92232728Smm return (EINVAL); 93232728Smm 94232728Smm if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 95232728Smm return (EOPNOTSUPP); 96232728Smm 97232728Smm if (vfs_getopt(mp->mnt_optnew, "ruleset", NULL, NULL) == 0 && 98232728Smm (vfs_scanopt(mp->mnt_optnew, "ruleset", "%d", 99232728Smm &rsnum) != 1 || rsnum < 0 || rsnum > 65535)) { 100232728Smm vfs_mount_error(mp, "%s", 101232728Smm "invalid ruleset specification"); 102232728Smm return (EINVAL); 103232728Smm } 104232728Smm 105232728Smm if (injail && rsnum != 0 && 106232728Smm rsnum != td->td_ucred->cr_prison->pr_devfs_rsnum) 107232728Smm return (EPERM); 108232728Smm } 109232728Smm 110232728Smm /* jails enforce their ruleset */ 111232728Smm if (injail) 112232728Smm rsnum = td->td_ucred->cr_prison->pr_devfs_rsnum; 113232728Smm 114232728Smm if (mp->mnt_flag & MNT_UPDATE) { 115232728Smm if (rsnum != 0) { 116232728Smm fmp = mp->mnt_data; 117232728Smm if (fmp != NULL) { 118232728Smm sx_xlock(&fmp->dm_lock); 119232728Smm devfs_ruleset_set((devfs_rsnum)rsnum, fmp); 120232728Smm devfs_ruleset_apply(fmp); 121232728Smm sx_xunlock(&fmp->dm_lock); 122232728Smm } 123232728Smm } 124232728Smm return (0); 125232728Smm } 126232728Smm 127150342Sphk fmp = malloc(sizeof *fmp, M_DEVFS, M_WAITOK | M_ZERO); 128150342Sphk fmp->dm_idx = alloc_unr(devfs_unr); 129150342Sphk sx_init(&fmp->dm_lock, "devfsmount"); 130162398Skib fmp->dm_holdcnt = 1; 13164880Sphk 132162647Stegge MNT_ILOCK(mp); 13364880Sphk mp->mnt_flag |= MNT_LOCAL; 134210925Skib mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | 135210925Skib MNTK_EXTENDED_SHARED; 136101069Srwatson#ifdef MAC 137101069Srwatson mp->mnt_flag |= MNT_MULTILABEL; 138101069Srwatson#endif 139162647Stegge MNT_IUNLOCK(mp); 140107698Srwatson fmp->dm_mount = mp; 141150342Sphk mp->mnt_data = (void *) fmp; 14264880Sphk vfs_getnewfsid(mp); 14364880Sphk 144150342Sphk fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO); 14564880Sphk 146191990Sattilio error = devfs_root(mp, LK_EXCLUSIVE, &rvp); 14765132Sphk if (error) { 148150342Sphk sx_destroy(&fmp->dm_lock); 149150342Sphk free_unr(devfs_unr, fmp->dm_idx); 150150342Sphk free(fmp, M_DEVFS); 15165132Sphk return (error); 15265132Sphk } 153138481Sphk 154232728Smm if (rsnum != 0) { 155232728Smm sx_xlock(&fmp->dm_lock); 156232728Smm devfs_ruleset_set((devfs_rsnum)rsnum, fmp); 157232728Smm sx_xunlock(&fmp->dm_lock); 158232728Smm } 159232728Smm 160175294Sattilio VOP_UNLOCK(rvp, 0); 16165132Sphk 162138481Sphk vfs_mountedfrom(mp, "devfs"); 16364880Sphk 16464880Sphk return (0); 16564880Sphk} 16664880Sphk 167162398Skibvoid 168162398Skibdevfs_unmount_final(struct devfs_mount *fmp) 169162398Skib{ 170162398Skib sx_destroy(&fmp->dm_lock); 171162398Skib free(fmp, M_DEVFS); 172162398Skib} 173162398Skib 17464880Sphkstatic int 175191990Sattiliodevfs_unmount(struct mount *mp, int mntflags) 17664880Sphk{ 17764880Sphk int error; 17864880Sphk int flags = 0; 17964880Sphk struct devfs_mount *fmp; 180162398Skib int hold; 181162398Skib u_int idx; 18264880Sphk 18365132Sphk fmp = VFSTODEVFS(mp); 184162398Skib KASSERT(fmp->dm_mount != NULL, 185162398Skib ("devfs_unmount unmounted devfs_mount")); 18676688Siedowse /* There is 1 extra root vnode reference from devfs_mount(). */ 187191990Sattilio error = vflush(mp, 1, flags, curthread); 18864880Sphk if (error) 18964880Sphk return (error); 190150342Sphk sx_xlock(&fmp->dm_lock); 191150342Sphk devfs_cleanup(fmp); 192150501Sphk devfs_rules_cleanup(fmp); 193162398Skib fmp->dm_mount = NULL; 194162398Skib hold = --fmp->dm_holdcnt; 195162398Skib mp->mnt_data = NULL; 196162398Skib idx = fmp->dm_idx; 197150342Sphk sx_xunlock(&fmp->dm_lock); 198162398Skib free_unr(devfs_unr, idx); 199162398Skib if (hold == 0) 200162398Skib devfs_unmount_final(fmp); 20164880Sphk return 0; 20264880Sphk} 20364880Sphk 20465132Sphk/* Return locked reference to root. */ 20565132Sphk 20664880Sphkstatic int 207191990Sattiliodevfs_root(struct mount *mp, int flags, struct vnode **vpp) 20864880Sphk{ 20965132Sphk int error; 21064880Sphk struct vnode *vp; 21165132Sphk struct devfs_mount *dmp; 21264880Sphk 21365132Sphk dmp = VFSTODEVFS(mp); 214162398Skib sx_xlock(&dmp->dm_lock); 215210921Skib error = devfs_allocv(dmp->dm_rootdir, mp, LK_EXCLUSIVE, &vp); 21665132Sphk if (error) 21765132Sphk return (error); 218101308Sjeff vp->v_vflag |= VV_ROOT; 21964880Sphk *vpp = vp; 22064880Sphk return (0); 22164880Sphk} 22264880Sphk 22364880Sphkstatic int 224191990Sattiliodevfs_statfs(struct mount *mp, struct statfs *sbp) 22564880Sphk{ 22664880Sphk 22764880Sphk sbp->f_flags = 0; 22864880Sphk sbp->f_bsize = DEV_BSIZE; 22964880Sphk sbp->f_iosize = DEV_BSIZE; 23064880Sphk sbp->f_blocks = 2; /* 1K to keep df happy */ 23164880Sphk sbp->f_bfree = 0; 23264880Sphk sbp->f_bavail = 0; 23364880Sphk sbp->f_files = 0; 23464880Sphk sbp->f_ffree = 0; 23564880Sphk return (0); 23664880Sphk} 23764880Sphk 23864880Sphkstatic struct vfsops devfs_vfsops = { 239132902Sphk .vfs_mount = devfs_mount, 240116271Sphk .vfs_root = devfs_root, 241116271Sphk .vfs_statfs = devfs_statfs, 242116271Sphk .vfs_unmount = devfs_unmount, 24364880Sphk}; 24464880Sphk 245232728SmmVFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC | VFCF_JAIL); 246