1/* 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/*- 29 * Copyright 1997,1998 Julian Elischer. All rights reserved. 30 * julian@freebsd.org 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions are 34 * met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright notice, 38 * this list of conditions and the following disclaimer in the documentation 39 * and/or other materials provided with the distribution. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS 42 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 43 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR 45 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 47 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 48 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * devfs_vfsops.c 54 * 55 */ 56/* 57 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 58 * support for mandatory and extensible security protections. This notice 59 * is included in support of clause 2.2 (b) of the Apple Public License, 60 * Version 2.0. 61 */ 62/* 63 * HISTORY 64 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999 65 * - modified devfs_statfs() to use devfs_stats to calculate the 66 * amount of memory used by devfs 67 */ 68 69 70#include <sys/param.h> 71#include <sys/systm.h> 72#include <sys/kernel.h> 73#include <sys/vnode_internal.h> 74#include <sys/proc.h> 75#include <sys/kauth.h> 76#include <sys/mount_internal.h> 77#include <sys/malloc.h> 78 79#include <libkern/OSAtomic.h> 80 81#if CONFIG_MACF 82#include <security/mac_framework.h> 83#endif 84 85#include "devfs.h" 86#include "devfsdefs.h" 87 88static int devfs_statfs( struct mount *mp, struct vfsstatfs *sbp, vfs_context_t ctx); 89static int devfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx); 90 91static struct vfstable * devfs_vfsp = 0; 92extern int setup_kmem; 93__private_extern__ void devfs_setup_kmem(void); 94 95 96/*- 97 * Called from the generic VFS startups. 98 * This is the second stage of DEVFS initialisation. 99 * The probed devices have already been loaded and the 100 * basic structure of the DEVFS created. 101 * We take the oportunity to mount the hidden DEVFS layer, so that 102 * devices from devfs get sync'd. 103 */ 104static int 105devfs_init(struct vfsconf *vfsp) 106{ 107 devfs_vfsp = (struct vfstable *)vfsp; /* remember this for devfs_kernel_mount below */ 108 109 if (devfs_sinit()) 110 return (ENOTSUP); 111 devfs_make_node(makedev(0, 0), DEVFS_CHAR, 112 UID_ROOT, GID_WHEEL, 0622, "console"); 113 devfs_make_node(makedev(2, 0), DEVFS_CHAR, 114 UID_ROOT, GID_WHEEL, 0666, "tty"); 115 if (setup_kmem) { 116 devfs_setup_kmem(); 117 } 118 devfs_make_node(makedev(3, 2), DEVFS_CHAR, 119 UID_ROOT, GID_WHEEL, 0666, "null"); 120 devfs_make_node(makedev(3, 3), DEVFS_CHAR, 121 UID_ROOT, GID_WHEEL, 0666, "zero"); 122 devfs_make_node(makedev(6, 0), DEVFS_CHAR, 123 UID_ROOT, GID_WHEEL, 0600, "klog"); 124 return 0; 125} 126 127__private_extern__ void 128devfs_setup_kmem(void) 129{ 130 devfs_make_node(makedev(3, 0), DEVFS_CHAR, 131 UID_ROOT, GID_KMEM, 0640, "mem"); 132 devfs_make_node(makedev(3, 1), DEVFS_CHAR, 133 UID_ROOT, GID_KMEM, 0640, "kmem"); 134} 135 136 137/*- 138 * mp - pointer to 'mount' structure 139 * path - addr in user space of mount point (ie /usr or whatever) 140 * data - addr in user space of mount params including the 141 * name of the block special file to treat as a filesystem. 142 * (NOT USED) 143 * ndp - namei data pointer (NOT USED) 144 * p - proc pointer 145 * devfs is special in that it doesn't require any device to be mounted.. 146 * It makes up its data as it goes along. 147 * it must be mounted during single user.. until it is, only std{in/out/err} 148 * and the root filesystem are available. 149 */ 150/*proto*/ 151int 152devfs_mount(struct mount *mp, __unused vnode_t devvp, __unused user_addr_t data, vfs_context_t ctx) 153{ 154 struct devfsmount *devfs_mp_p; /* devfs specific mount info */ 155 int error; 156 157 /*- 158 * If they just want to update, we don't need to do anything. 159 */ 160 if (mp->mnt_flag & MNT_UPDATE) 161 { 162 return 0; 163 } 164 165 /* Advisory locking should be handled at the VFS layer */ 166 vfs_setlocklocal(mp); 167 168 /*- 169 * Well, it's not an update, it's a real mount request. 170 * Time to get dirty. 171 * HERE we should check to see if we are already mounted here. 172 */ 173 174 MALLOC(devfs_mp_p, struct devfsmount *, sizeof(struct devfsmount), 175 M_DEVFSMNT, M_WAITOK); 176 if (devfs_mp_p == NULL) 177 return (ENOMEM); 178 bzero(devfs_mp_p,sizeof(*devfs_mp_p)); 179 devfs_mp_p->mount = mp; 180 181 /*- 182 * Fill out some fields 183 */ 184 mp->mnt_data = (qaddr_t)devfs_mp_p; 185 mp->mnt_vfsstat.f_fsid.val[0] = (int32_t)(void *)devfs_mp_p; 186 mp->mnt_vfsstat.f_fsid.val[1] = vfs_typenum(mp); 187 mp->mnt_flag |= MNT_LOCAL; 188 189 DEVFS_LOCK(); 190 error = dev_dup_plane(devfs_mp_p); 191 DEVFS_UNLOCK(); 192 193 if (error) { 194 mp->mnt_data = (qaddr_t)0; 195 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT); 196 return (error); 197 } else 198 DEVFS_INCR_MOUNTS(); 199 200 /*- 201 * Copy in the name of the directory the filesystem 202 * is to be mounted on. 203 * And we clear the remainder of the character strings 204 * to be tidy. 205 */ 206 207 bzero(mp->mnt_vfsstat.f_mntfromname, MAXPATHLEN); 208 bcopy("devfs",mp->mnt_vfsstat.f_mntfromname, 5); 209 (void)devfs_statfs(mp, &mp->mnt_vfsstat, ctx); 210 211 return 0; 212} 213 214 215static int 216devfs_start(__unused struct mount *mp, __unused int flags, __unused vfs_context_t ctx) 217{ 218 return 0; 219} 220 221/*- 222 * Unmount the filesystem described by mp. 223 */ 224static int 225devfs_unmount( struct mount *mp, int mntflags, __unused vfs_context_t ctx) 226{ 227 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; 228 int flags = 0; 229 int force = 0; 230 int error; 231 232 if (mntflags & MNT_FORCE) { 233 flags |= FORCECLOSE; 234 force = 1; 235 } 236 error = vflush(mp, NULLVP, flags); 237 if (error && !force) 238 return error; 239 240 DEVFS_LOCK(); 241 devfs_free_plane(devfs_mp_p); 242 DEVFS_UNLOCK(); 243 244 DEVFS_DECR_MOUNTS(); 245 246 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT); 247 mp->mnt_data = (qaddr_t)0; 248 mp->mnt_flag &= ~MNT_LOCAL; 249 250 return 0; 251} 252 253/* return the address of the root vnode in *vpp */ 254static int 255devfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t ctx) 256{ 257 struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data); 258 int error; 259 260 DEVFS_LOCK(); 261 /* last parameter to devfs_dntovn() is ignored */ 262 error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp, vpp, NULL); 263 DEVFS_UNLOCK(); 264 265 return error; 266} 267 268static int 269devfs_statfs( struct mount *mp, struct vfsstatfs *sbp, __unused vfs_context_t ctx) 270{ 271 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; 272 273 /*- 274 * Fill in the stat block. 275 */ 276 //sbp->f_type = mp->mnt_vfsstat.f_type; 277 sbp->f_flags = 0; /* XXX */ 278 sbp->f_bsize = 512; 279 sbp->f_iosize = 512; 280 sbp->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount) 281 + devfs_stats.nodes * sizeof(devnode_t) 282 + devfs_stats.entries * sizeof(devdirent_t) 283 + devfs_stats.stringspace 284 ) / sbp->f_bsize; 285 sbp->f_bfree = 0; 286 sbp->f_bavail = 0; 287 sbp->f_files = devfs_stats.nodes; 288 sbp->f_ffree = 0; 289 sbp->f_fsid.val[0] = (int32_t)(void *)devfs_mp_p; 290 sbp->f_fsid.val[1] = vfs_typenum(mp); 291 292 return 0; 293} 294 295static int 296devfs_vfs_getattr(__unused mount_t mp, struct vfs_attr *fsap, __unused vfs_context_t ctx) 297{ 298 VFSATTR_RETURN(fsap, f_objcount, devfs_stats.nodes); 299 VFSATTR_RETURN(fsap, f_maxobjcount, devfs_stats.nodes); 300 VFSATTR_RETURN(fsap, f_bsize, 512); 301 VFSATTR_RETURN(fsap, f_iosize, 512); 302 if (VFSATTR_IS_ACTIVE(fsap, f_blocks) || VFSATTR_IS_ACTIVE(fsap, f_bused)) { 303 fsap->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount) 304 + devfs_stats.nodes * sizeof(devnode_t) 305 + devfs_stats.entries * sizeof(devdirent_t) 306 + devfs_stats.stringspace 307 ) / fsap->f_bsize; 308 fsap->f_bused = fsap->f_blocks; 309 VFSATTR_SET_SUPPORTED(fsap, f_blocks); 310 VFSATTR_SET_SUPPORTED(fsap, f_bused); 311 } 312 VFSATTR_RETURN(fsap, f_bfree, 0); 313 VFSATTR_RETURN(fsap, f_bavail, 0); 314 VFSATTR_RETURN(fsap, f_files, devfs_stats.nodes); 315 VFSATTR_RETURN(fsap, f_ffree, 0); 316 VFSATTR_RETURN(fsap, f_fssubtype, 0); 317 318 return 0; 319} 320 321static int 322devfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx) 323{ 324 return (0); 325} 326 327 328static int 329devfs_vget(__unused struct mount *mp, __unused ino64_t ino, __unused struct vnode **vpp, __unused vfs_context_t ctx) 330{ 331 return ENOTSUP; 332} 333 334/************************************************************* 335 * The concept of exporting a kernel generated devfs is stupid 336 * So don't handle filehandles 337 */ 338 339static int 340devfs_fhtovp (__unused struct mount *mp, __unused int fhlen, __unused unsigned char *fhp, __unused struct vnode **vpp, __unused vfs_context_t ctx) 341{ 342 return (EINVAL); 343} 344 345 346static int 347devfs_vptofh (__unused struct vnode *vp, __unused int *fhlenp, __unused unsigned char *fhp, __unused vfs_context_t ctx) 348{ 349 return (EINVAL); 350} 351 352static int 353devfs_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp, 354 __unused size_t *oldlenp, __unused user_addr_t newp, 355 __unused size_t newlen, __unused vfs_context_t ctx) 356{ 357 return (ENOTSUP); 358} 359 360#include <sys/namei.h> 361 362/* 363 * Function: devfs_kernel_mount 364 * Purpose: 365 * Mount devfs at the given mount point from within the kernel. 366 */ 367int 368devfs_kernel_mount(char * mntname) 369{ 370 struct mount *mp; 371 int error; 372 struct nameidata nd; 373 struct vnode * vp; 374 vfs_context_t ctx = vfs_context_kernel(); 375 376 if (devfs_vfsp == NULL) { 377 printf("devfs_kernel_mount: devfs_vfsp is NULL\n"); 378 return (EINVAL); 379 } 380 381 /* 382 * Get vnode to be covered 383 */ 384 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE32, 385 CAST_USER_ADDR_T(mntname), ctx); 386 if ((error = namei(&nd))) { 387 printf("devfs_kernel_mount: failed to find directory '%s', %d", 388 mntname, error); 389 return (error); 390 } 391 nameidone(&nd); 392 vp = nd.ni_vp; 393 394 if ((error = VNOP_FSYNC(vp, MNT_WAIT, ctx))) { 395 printf("devfs_kernel_mount: vnop_fsync failed: %d\n", error); 396 vnode_put(vp); 397 return (error); 398 } 399 if ((error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0))) { 400 printf("devfs_kernel_mount: buf_invalidateblks failed: %d\n", error); 401 vnode_put(vp); 402 return (error); 403 } 404 if (vnode_isdir(vp) == 0) { 405 printf("devfs_kernel_mount: '%s' is not a directory\n", mntname); 406 vnode_put(vp); 407 return (ENOTDIR); 408 } 409 if ((vnode_mountedhere(vp))) { 410 vnode_put(vp); 411 return (EBUSY); 412 } 413 414 /* 415 * Allocate and initialize the filesystem. 416 */ 417 MALLOC_ZONE(mp, struct mount *, (u_long)sizeof(struct mount), 418 M_MOUNT, M_WAITOK); 419 bzero((char *)mp, (u_long)sizeof(struct mount)); 420 421 /* Initialize the default IO constraints */ 422 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS; 423 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32; 424 mp->mnt_ioflags = 0; 425 mp->mnt_realrootvp = NULLVP; 426 mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL; 427 428 mount_lock_init(mp); 429 TAILQ_INIT(&mp->mnt_vnodelist); 430 TAILQ_INIT(&mp->mnt_workerqueue); 431 TAILQ_INIT(&mp->mnt_newvnodes); 432 433 (void)vfs_busy(mp, LK_NOWAIT); 434 mp->mnt_op = devfs_vfsp->vfc_vfsops; 435 mp->mnt_vtable = devfs_vfsp; 436 devfs_vfsp->vfc_refcount++; 437 devfs_vfsp->vfc_threadsafe = TRUE; 438 devfs_vfsp->vfc_64bitready = TRUE; 439 mp->mnt_flag = 0; 440 mp->mnt_flag |= devfs_vfsp->vfc_flags & MNT_VISFLAGMASK; 441 strlcpy(mp->mnt_vfsstat.f_fstypename, devfs_vfsp->vfc_name, MFSTYPENAMELEN); 442 vp->v_mountedhere = mp; 443 mp->mnt_vnodecovered = vp; 444 mp->mnt_vfsstat.f_owner = kauth_cred_getuid(kauth_cred_get()); 445 (void) copystr(mntname, mp->mnt_vfsstat.f_mntonname, MAXPATHLEN - 1, 0); 446#if CONFIG_MACF 447 mac_mount_label_init(mp); 448 mac_mount_label_associate(ctx, mp); 449#endif 450 451 error = devfs_mount(mp, NULL, USER_ADDR_NULL, ctx); 452 453 if (error) { 454 printf("devfs_kernel_mount: mount %s failed: %d", mntname, error); 455 mp->mnt_vtable->vfc_refcount--; 456 457 vfs_unbusy(mp); 458 459 mount_lock_destroy(mp); 460#if CONFIG_MACF 461 mac_mount_label_destroy(mp); 462#endif 463 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT); 464 vnode_put(vp); 465 return (error); 466 } 467 vnode_ref(vp); 468 vnode_put(vp); 469 vfs_unbusy(mp); 470 mount_list_add(mp); 471 return (0); 472} 473 474struct vfsops devfs_vfsops = { 475 devfs_mount, 476 devfs_start, 477 devfs_unmount, 478 devfs_root, 479 NULL, /* quotactl */ 480 devfs_vfs_getattr, 481 devfs_sync, 482 devfs_vget, 483 devfs_fhtovp, 484 devfs_vptofh, 485 devfs_init, 486 devfs_sysctl, 487 NULL, 488 {NULL} 489}; 490