1 /* 2 * Copyright (c) 1992, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2000 5 * Poul-Henning Kamp. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 32 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 33 * 34 * $FreeBSD$ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/proc.h> 41 #include <sys/vnode.h> 42 #include <sys/mount.h> 43 #include <sys/malloc.h> 44 #include <sys/eventhandler.h> 45 46 #define DEVFS_INTERN 47 #include <fs/devfs/devfs.h> 48 49 MALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data"); 50 51 static int devfs_mount __P((struct mount *mp, char *path, caddr_t data, 52 struct nameidata *ndp, struct proc *p)); 53 static int devfs_unmount __P((struct mount *mp, int mntflags, 54 struct proc *p)); 55 static int devfs_root __P((struct mount *mp, struct vnode **vpp)); 56 static int devfs_statfs __P((struct mount *mp, struct statfs *sbp, 57 struct proc *p)); 58 59 /* 60 * Mount the filesystem 61 */ 62 static int 63 devfs_mount(mp, path, data, ndp, p) 64 struct mount *mp; 65 char *path; 66 caddr_t data; 67 struct nameidata *ndp; 68 struct proc *p; 69 { 70 int error = 0; 71 u_int size; 72 struct devfs_mount *fmp; 73 struct vnode *rvp; 74 75 /* 76 * Update is a no-op 77 */ 78 if (mp->mnt_flag & MNT_UPDATE) 79 return (EOPNOTSUPP); 80 81 MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), M_DEVFS, M_WAITOK); 82 83 bzero(fmp, sizeof(*fmp)); 84 85 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &rvp); 86 if (error) { 87 FREE(fmp, M_DEVFS); 88 return (error); 89 } 90 91 vhold(rvp); 92 rvp->v_type = VDIR; 93 rvp->v_flag |= VROOT; 94 mp->mnt_flag |= MNT_LOCAL; 95 mp->mnt_data = (qaddr_t) fmp; 96 vfs_getnewfsid(mp); 97 98 fmp->dm_inode = NDEVINO; 99 fmp->dm_root = rvp; 100 fmp->dm_rootdir = devfs_vmkdir(); 101 rvp->v_data = fmp->dm_rootdir; 102 TAILQ_FIRST(&fmp->dm_rootdir->dd_list)->de_vnode = rvp; 103 TAILQ_FIRST(&fmp->dm_rootdir->dd_list)->de_inode = 2; 104 105 #ifdef DEVFS_DEVBASE 106 { 107 struct devfs_dirent *de; 108 109 fmp->dm_basedir = devfs_vmkdir(); 110 de = devfs_newdirent("dev", 3); 111 de->de_inode = fmp->dm_inode++; 112 de->de_dir = fmp->dm_basedir; 113 TAILQ_FIRST(&de->de_dir->dd_list)->de_inode = de->de_inode; 114 de->de_uid = 0; 115 de->de_gid = 0; 116 de->de_mode = 0755; 117 de->de_dirent->d_type = DT_DIR; 118 TAILQ_INSERT_TAIL(&fmp->dm_rootdir->dd_list, de, de_list); 119 } 120 #else 121 fmp->dm_basedir = fmp->dm_rootdir; 122 #endif 123 124 if (path != NULL) { 125 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 126 } else { 127 strcpy(mp->mnt_stat.f_mntonname, "/"); 128 size = 1; 129 } 130 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 131 bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); 132 bcopy("devfs", mp->mnt_stat.f_mntfromname, sizeof("devfs")); 133 (void)devfs_statfs(mp, &mp->mnt_stat, p); 134 devfs_populate(fmp); 135 136 return (0); 137 } 138 139 static int 140 devfs_unmount(mp, mntflags, p) 141 struct mount *mp; 142 int mntflags; 143 struct proc *p; 144 { 145 int error; 146 int flags = 0; 147 struct vnode *rootvp = VFSTODEVFS(mp)->dm_root; 148 struct devfs_mount *fmp; 149 150 fmp = (struct devfs_mount*) mp->mnt_data; 151 if (mntflags & MNT_FORCE) 152 flags |= FORCECLOSE; 153 154 /* 155 * Clear out buffer cache. I don't think we 156 * ever get anything cached at this level at the 157 * moment, but who knows... 158 */ 159 if (rootvp->v_usecount > 2) 160 return (EBUSY); 161 devfs_purge(fmp->dm_rootdir); 162 error = vflush(mp, rootvp, flags); 163 if (error) 164 return (error); 165 166 /* 167 * Release reference on underlying root vnode 168 */ 169 vrele(rootvp); 170 /* 171 * And blow it away for future re-use 172 */ 173 vgone(rootvp); 174 /* 175 * Finally, throw away the devfs_mount structure 176 */ 177 free(mp->mnt_data, M_DEVFS); 178 mp->mnt_data = 0; 179 return 0; 180 } 181 182 static int 183 devfs_root(mp, vpp) 184 struct mount *mp; 185 struct vnode **vpp; 186 { 187 struct proc *p = curproc; /* XXX */ 188 struct vnode *vp; 189 190 /* 191 * Return locked reference to root. 192 */ 193 vp = VFSTODEVFS(mp)->dm_root; 194 VREF(vp); 195 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 196 *vpp = vp; 197 return (0); 198 } 199 200 static int 201 devfs_statfs(mp, sbp, p) 202 struct mount *mp; 203 struct statfs *sbp; 204 struct proc *p; 205 { 206 207 sbp->f_flags = 0; 208 sbp->f_bsize = DEV_BSIZE; 209 sbp->f_iosize = DEV_BSIZE; 210 sbp->f_blocks = 2; /* 1K to keep df happy */ 211 sbp->f_bfree = 0; 212 sbp->f_bavail = 0; 213 sbp->f_files = 0; 214 sbp->f_ffree = 0; 215 if (sbp != &mp->mnt_stat) { 216 sbp->f_type = mp->mnt_vfc->vfc_typenum; 217 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 218 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 219 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 220 } 221 return (0); 222 } 223 224 static struct vfsops devfs_vfsops = { 225 devfs_mount, 226 vfs_stdstart, 227 devfs_unmount, 228 devfs_root, 229 vfs_stdquotactl, 230 devfs_statfs, 231 vfs_stdsync, 232 vfs_stdvget, 233 vfs_stdfhtovp, 234 vfs_stdcheckexp, 235 vfs_stdvptofh, 236 vfs_stdinit, 237 vfs_stduninit, 238 vfs_stdextattrctl, 239 }; 240 241 VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC); 242