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/* 30 * Copyright 1997,1998 Julian Elischer. All rights reserved. 31 * julian@freebsd.org 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions are 35 * met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright notice, 39 * this list of conditions and the following disclaimer in the documentation 40 * and/or other materials provided with the distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS 43 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 44 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 45 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR 46 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 48 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 49 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * 54 * devfs_tree.c 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/* 64 * HISTORY 65 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999 66 * - removed mounting of "hidden" mountpoint 67 * - fixed problem in which devnode->dn_vn pointer was not 68 * updated with the vnode returned from checkalias() 69 * - replaced devfs_vntodn() with a macro VTODN() 70 * - rewrote dev_finddir() to not use recursion 71 * - added locking to avoid data structure corruption (DEVFS_(UN)LOCK()) 72 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999 73 * - fixed problem with devfs_dntovn() checking the v_id against the 74 * value cached in the device node; a union mount on top of us causes 75 * the v_id to get incremented thus, we would end up returning a new 76 * vnode instead of the existing one that has the mounted_here 77 * field filled in; the net effect was that the filesystem mounted 78 * on top of us would never show up 79 * - added devfs_stats to store how many data structures are actually 80 * allocated 81 */ 82 83/* SPLIT_DEVS means each devfs uses a different devnode for the same device */ 84/* Otherwise the same device always ends up at the same vnode even if */ 85/* reached througgh a different devfs instance. The practical difference */ 86/* is that with the same vnode, chmods and chowns show up on all instances of */ 87/* a device. (etc) */ 88 89#define SPLIT_DEVS 1 /* maybe make this an option */ 90/*#define SPLIT_DEVS 1*/ 91 92#include <sys/param.h> 93#include <sys/systm.h> 94#include <sys/kernel.h> 95#include <sys/conf.h> 96#include <sys/malloc.h> 97#include <sys/mount_internal.h> 98#include <sys/proc.h> 99#include <sys/vnode_internal.h> 100#include <stdarg.h> 101#include <libkern/OSAtomic.h> 102#define BSD_KERNEL_PRIVATE 1 /* devfs_make_link() prototype */ 103#include "devfs.h" 104#include "devfsdefs.h" 105 106#if CONFIG_MACF 107#include <security/mac_framework.h> 108#endif 109 110#if FDESC 111#include "fdesc.h" 112#endif 113 114typedef struct devfs_vnode_event { 115 vnode_t dve_vp; 116 uint32_t dve_vid; 117 uint32_t dve_events; 118} *devfs_vnode_event_t; 119 120/* 121 * Size of stack buffer (fast path) for notifications. If 122 * the number of mounts is small, no need to malloc a buffer. 123 */ 124#define NUM_STACK_ENTRIES 5 125 126typedef struct devfs_event_log { 127 size_t del_max; 128 size_t del_used; 129 devfs_vnode_event_t del_entries; 130} *devfs_event_log_t; 131 132 133static void dev_free_hier(devdirent_t *); 134static int devfs_propogate(devdirent_t *, devdirent_t *, devfs_event_log_t); 135static int dev_finddir(const char *, devnode_t *, int, devnode_t **, devfs_event_log_t); 136static int dev_dup_entry(devnode_t *, devdirent_t *, devdirent_t **, struct devfsmount *); 137void devfs_ref_node(devnode_t *); 138void devfs_rele_node(devnode_t *); 139static void devfs_record_event(devfs_event_log_t, devnode_t*, uint32_t); 140static int devfs_init_event_log(devfs_event_log_t, uint32_t, devfs_vnode_event_t); 141static void devfs_release_event_log(devfs_event_log_t, int); 142static void devfs_bulk_notify(devfs_event_log_t); 143static devdirent_t *devfs_make_node_internal(dev_t, devfstype_t type, uid_t, gid_t, int, 144 int (*clone)(dev_t dev, int action), const char *fmt, va_list ap); 145 146 147lck_grp_t * devfs_lck_grp; 148lck_grp_attr_t * devfs_lck_grp_attr; 149lck_attr_t * devfs_lck_attr; 150lck_mtx_t devfs_mutex; 151lck_mtx_t devfs_attr_mutex; 152 153devdirent_t * dev_root = NULL; /* root of backing tree */ 154struct devfs_stats devfs_stats; /* hold stats */ 155 156static ino_t devfs_unique_fileno = 0; 157 158#ifdef HIDDEN_MOUNTPOINT 159static struct mount *devfs_hidden_mount; 160#endif /* HIDDEN_MOINTPOINT */ 161 162static int devfs_ready = 0; 163static uint32_t devfs_nmountplanes = 0; /* The first plane is not used for a mount */ 164 165#define DEVFS_NOCREATE FALSE 166#define DEVFS_CREATE TRUE 167 168/* 169 * Set up the root directory node in the backing plane 170 * This is happenning before the vfs system has been 171 * set up yet, so be careful about what we reference.. 172 * Notice that the ops are by indirection.. as they haven't 173 * been set up yet! 174 * DEVFS has a hidden mountpoint that is used as the anchor point 175 * for the internal 'blueprint' version of the dev filesystem tree. 176 */ 177/*proto*/ 178int 179devfs_sinit(void) 180{ 181 int error; 182 183 devfs_lck_grp_attr = lck_grp_attr_alloc_init(); 184 devfs_lck_grp = lck_grp_alloc_init("devfs_lock", devfs_lck_grp_attr); 185 186 devfs_lck_attr = lck_attr_alloc_init(); 187 188 lck_mtx_init(&devfs_mutex, devfs_lck_grp, devfs_lck_attr); 189 lck_mtx_init(&devfs_attr_mutex, devfs_lck_grp, devfs_lck_attr); 190 191 DEVFS_LOCK(); 192 error = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root); 193 DEVFS_UNLOCK(); 194 195 if (error) { 196 printf("devfs_sinit: dev_add_entry failed "); 197 return (ENOTSUP); 198 } 199#ifdef HIDDEN_MOUNTPOINT 200 MALLOC(devfs_hidden_mount, struct mount *, sizeof(struct mount), 201 M_MOUNT, M_WAITOK); 202 bzero(devfs_hidden_mount,sizeof(struct mount)); 203 mount_lock_init(devfs_hidden_mount); 204 TAILQ_INIT(&devfs_hidden_mount->mnt_vnodelist); 205 TAILQ_INIT(&devfs_hidden_mount->mnt_workerqueue); 206 TAILQ_INIT(&devfs_hidden_mount->mnt_newvnodes); 207#if CONFIG_MACF 208 mac_mount_label_init(devfs_hidden_mount); 209 mac_mount_label_associate(vfs_context_kernel(), devfs_hidden_mount); 210#endif 211 212 /* Initialize the default IO constraints */ 213 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS; 214 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32; 215 mp->mnt_ioflags = 0; 216 mp->mnt_realrootvp = NULLVP; 217 mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL; 218 219 devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL); 220 dev_root->de_dnp->dn_dvm 221 = (struct devfsmount *)devfs_hidden_mount->mnt_data; 222#endif /* HIDDEN_MOUNTPOINT */ 223#if CONFIG_MACF 224 mac_devfs_label_associate_directory("/", strlen("/"), 225 dev_root->de_dnp, "/"); 226#endif 227 devfs_ready = 1; 228 return (0); 229} 230 231/***********************************************************************\ 232************************************************************************* 233* Routines used to find our way to a point in the tree * 234************************************************************************* 235\***********************************************************************/ 236 237 238 239/*************************************************************** 240 * Search down the linked list off a dir to find "name" 241 * return the devnode_t * for that node. 242 * 243 * called with DEVFS_LOCK held 244 ***************************************************************/ 245devdirent_t * 246dev_findname(devnode_t * dir, const char *name) 247{ 248 devdirent_t * newfp; 249 if (dir->dn_type != DEV_DIR) return 0;/*XXX*/ /* printf?*/ 250 251 if (name[0] == '.') 252 { 253 if(name[1] == 0) 254 { 255 return dir->dn_typeinfo.Dir.myname; 256 } 257 if((name[1] == '.') && (name[2] == 0)) 258 { 259 /* for root, .. == . */ 260 return dir->dn_typeinfo.Dir.parent->dn_typeinfo.Dir.myname; 261 } 262 } 263 newfp = dir->dn_typeinfo.Dir.dirlist; 264 265 while(newfp) 266 { 267 if(!(strncmp(name, newfp->de_name, sizeof(newfp->de_name)))) 268 return newfp; 269 newfp = newfp->de_next; 270 } 271 return NULL; 272} 273 274/*********************************************************************** 275 * Given a starting node (0 for root) and a pathname, return the node 276 * for the end item on the path. It MUST BE A DIRECTORY. If the 'DEVFS_CREATE' 277 * option is true, then create any missing nodes in the path and create 278 * and return the final node as well. 279 * This is used to set up a directory, before making nodes in it.. 280 * 281 * called with DEVFS_LOCK held 282 ***********************************************************************/ 283static int 284dev_finddir(const char * path, 285 devnode_t * dirnode, 286 int create, 287 devnode_t * * dn_pp, 288 devfs_event_log_t delp) 289{ 290 devnode_t * dnp = NULL; 291 int error = 0; 292 const char * scan; 293#if CONFIG_MACF 294 char fullpath[DEVMAXPATHSIZE]; 295#endif 296 297 298 if (!dirnode) /* dirnode == NULL means start at root */ 299 dirnode = dev_root->de_dnp; 300 301 if (dirnode->dn_type != DEV_DIR) 302 return ENOTDIR; 303 304 if (strlen(path) > (DEVMAXPATHSIZE - 1)) 305 return ENAMETOOLONG; 306 307#if CONFIG_MACF 308 strlcpy (fullpath, path, DEVMAXPATHSIZE); 309#endif 310 scan = path; 311 312 while (*scan == '/') 313 scan++; 314 315 *dn_pp = NULL; 316 317 while (1) { 318 char component[DEVMAXPATHSIZE]; 319 devdirent_t * dirent_p; 320 const char * start; 321 322 if (*scan == 0) { 323 /* we hit the end of the string, we're done */ 324 *dn_pp = dirnode; 325 break; 326 } 327 start = scan; 328 while (*scan != '/' && *scan) 329 scan++; 330 331 strlcpy(component, start, scan - start); 332 if (*scan == '/') 333 scan++; 334 335 dirent_p = dev_findname(dirnode, component); 336 if (dirent_p) { 337 dnp = dirent_p->de_dnp; 338 if (dnp->dn_type != DEV_DIR) { 339 error = ENOTDIR; 340 break; 341 } 342 } 343 else { 344 if (!create) { 345 error = ENOENT; 346 break; 347 } 348 error = dev_add_entry(component, dirnode, 349 DEV_DIR, NULL, NULL, NULL, &dirent_p); 350 if (error) 351 break; 352 dnp = dirent_p->de_dnp; 353#if CONFIG_MACF 354 mac_devfs_label_associate_directory( 355 dirnode->dn_typeinfo.Dir.myname->de_name, 356 strlen(dirnode->dn_typeinfo.Dir.myname->de_name), 357 dnp, fullpath); 358#endif 359 devfs_propogate(dirnode->dn_typeinfo.Dir.myname, dirent_p, delp); 360 } 361 dirnode = dnp; /* continue relative to this directory */ 362 } 363 return (error); 364} 365 366 367/*********************************************************************** 368 * Add a new NAME element to the devfs 369 * If we're creating a root node, then dirname is NULL 370 * Basically this creates a new namespace entry for the device node 371 * 372 * Creates a name node, and links it to the supplied node 373 * 374 * called with DEVFS_LOCK held 375 ***********************************************************************/ 376int 377dev_add_name(const char * name, devnode_t * dirnode, __unused devdirent_t * back, 378 devnode_t * dnp, devdirent_t * *dirent_pp) 379{ 380 devdirent_t * dirent_p = NULL; 381 382 if(dirnode != NULL ) { 383 if(dirnode->dn_type != DEV_DIR) return(ENOTDIR); 384 385 if( dev_findname(dirnode,name)) 386 return(EEXIST); 387 } 388 /* 389 * make sure the name is legal 390 * slightly misleading in the case of NULL 391 */ 392 if (!name || (strlen(name) > (DEVMAXNAMESIZE - 1))) 393 return (ENAMETOOLONG); 394 395 /* 396 * Allocate and fill out a new directory entry 397 */ 398 MALLOC(dirent_p, devdirent_t *, sizeof(devdirent_t), 399 M_DEVFSNAME, M_WAITOK); 400 if (!dirent_p) { 401 return ENOMEM; 402 } 403 bzero(dirent_p,sizeof(devdirent_t)); 404 405 /* inherrit our parent's mount info */ /*XXX*/ 406 /* a kludge but.... */ 407 if(dirnode && ( dnp->dn_dvm == NULL)) { 408 dnp->dn_dvm = dirnode->dn_dvm; 409 /* if(!dnp->dn_dvm) printf("parent had null dvm "); */ 410 } 411 412 /* 413 * Link the two together 414 * include the implicit link in the count of links to the devnode.. 415 * this stops it from being accidentally freed later. 416 */ 417 dirent_p->de_dnp = dnp; 418 dnp->dn_links++ ; /* implicit from our own name-node */ 419 420 /* 421 * Make sure that we can find all the links that reference a node 422 * so that we can get them all if we need to zap the node. 423 */ 424 if(dnp->dn_linklist) { 425 dirent_p->de_nextlink = dnp->dn_linklist; 426 dirent_p->de_prevlinkp = dirent_p->de_nextlink->de_prevlinkp; 427 dirent_p->de_nextlink->de_prevlinkp = &(dirent_p->de_nextlink); 428 *dirent_p->de_prevlinkp = dirent_p; 429 } else { 430 dirent_p->de_nextlink = dirent_p; 431 dirent_p->de_prevlinkp = &(dirent_p->de_nextlink); 432 } 433 dnp->dn_linklist = dirent_p; 434 435 /* 436 * If the node is a directory, then we need to handle the 437 * creation of the .. link. 438 * A NULL dirnode indicates a root node, so point to ourself. 439 */ 440 if(dnp->dn_type == DEV_DIR) { 441 dnp->dn_typeinfo.Dir.myname = dirent_p; 442 /* 443 * If we are unlinking from an old dir, decrement its links 444 * as we point our '..' elsewhere 445 * Note: it's up to the calling code to remove the 446 * us from the original directory's list 447 */ 448 if(dnp->dn_typeinfo.Dir.parent) { 449 dnp->dn_typeinfo.Dir.parent->dn_links--; 450 } 451 if(dirnode) { 452 dnp->dn_typeinfo.Dir.parent = dirnode; 453 } else { 454 dnp->dn_typeinfo.Dir.parent = dnp; 455 } 456 dnp->dn_typeinfo.Dir.parent->dn_links++; /* account for the new '..' */ 457 } 458 459 /* 460 * put the name into the directory entry. 461 */ 462 strlcpy(dirent_p->de_name, name, DEVMAXNAMESIZE); 463 464 465 /* 466 * Check if we are not making a root node.. 467 * (i.e. have parent) 468 */ 469 if(dirnode) { 470 /* 471 * Put it on the END of the linked list of directory entries 472 */ 473 dirent_p->de_parent = dirnode; /* null for root */ 474 dirent_p->de_prevp = dirnode->dn_typeinfo.Dir.dirlast; 475 dirent_p->de_next = *(dirent_p->de_prevp); /* should be NULL */ 476 /*right?*/ 477 *(dirent_p->de_prevp) = dirent_p; 478 dirnode->dn_typeinfo.Dir.dirlast = &(dirent_p->de_next); 479 dirnode->dn_typeinfo.Dir.entrycount++; 480 dirnode->dn_len += strlen(name) + 8;/*ok, ok?*/ 481 } 482 483 *dirent_pp = dirent_p; 484 DEVFS_INCR_ENTRIES(); 485 return 0 ; 486} 487 488 489/*********************************************************************** 490 * Add a new element to the devfs plane. 491 * 492 * Creates a new dev_node to go with it if the prototype should not be 493 * reused. (Is a DIR, or we select SPLIT_DEVS at compile time) 494 * typeinfo gives us info to make our node if we don't have a prototype. 495 * If typeinfo is null and proto exists, then the typeinfo field of 496 * the proto is used intead in the DEVFS_CREATE case. 497 * note the 'links' count is 0 (except if a dir) 498 * but it is only cleared on a transition 499 * so this is ok till we link it to something 500 * Even in SPLIT_DEVS mode, 501 * if the node already exists on the wanted plane, just return it 502 * 503 * called with DEVFS_LOCK held 504***********************************************************************/ 505int 506dev_add_node(int entrytype, devnode_type_t * typeinfo, devnode_t * proto, 507 devnode_t * *dn_pp, struct devfsmount *dvm) 508{ 509 devnode_t * dnp = NULL; 510 511#if defined SPLIT_DEVS 512 /* 513 * If we have a prototype, then check if there is already a sibling 514 * on the mount plane we are looking at, if so, just return it. 515 */ 516 if (proto) { 517 dnp = proto->dn_nextsibling; 518 while( dnp != proto) { 519 if (dnp->dn_dvm == dvm) { 520 *dn_pp = dnp; 521 return (0); 522 } 523 dnp = dnp->dn_nextsibling; 524 } 525 if (typeinfo == NULL) 526 typeinfo = &(proto->dn_typeinfo); 527 } 528#else /* SPLIT_DEVS */ 529 if ( proto ) { 530 switch (proto->type) { 531 case DEV_BDEV: 532 case DEV_CDEV: 533 *dn_pp = proto; 534 return 0; 535 } 536 } 537#endif /* SPLIT_DEVS */ 538 MALLOC(dnp, devnode_t *, sizeof(devnode_t), M_DEVFSNODE, M_WAITOK); 539 if (!dnp) { 540 return ENOMEM; 541 } 542 543 /* 544 * If we have a proto, that means that we are duplicating some 545 * other device, which can only happen if we are not at the back plane 546 */ 547 if (proto) { 548 bcopy(proto, dnp, sizeof(devnode_t)); 549 dnp->dn_links = 0; 550 dnp->dn_linklist = NULL; 551 dnp->dn_vn = NULL; 552 dnp->dn_len = 0; 553 /* add to END of siblings list */ 554 dnp->dn_prevsiblingp = proto->dn_prevsiblingp; 555 *(dnp->dn_prevsiblingp) = dnp; 556 dnp->dn_nextsibling = proto; 557 proto->dn_prevsiblingp = &(dnp->dn_nextsibling); 558#if CONFIG_MACF 559 mac_devfs_label_init(dnp); 560 mac_devfs_label_copy(proto->dn_label, dnp->dn_label); 561#endif 562 } else { 563 struct timeval tv; 564 565 /* 566 * We have no prototype, so start off with a clean slate 567 */ 568 microtime(&tv); 569 bzero(dnp, sizeof(devnode_t)); 570 dnp->dn_type = entrytype; 571 dnp->dn_nextsibling = dnp; 572 dnp->dn_prevsiblingp = &(dnp->dn_nextsibling); 573 dnp->dn_atime.tv_sec = tv.tv_sec; 574 dnp->dn_mtime.tv_sec = tv.tv_sec; 575 dnp->dn_ctime.tv_sec = tv.tv_sec; 576#if CONFIG_MACF 577 mac_devfs_label_init(dnp); 578#endif 579 } 580 dnp->dn_dvm = dvm; 581 dnp->dn_refcount = 0; 582 dnp->dn_ino = devfs_unique_fileno; 583 devfs_unique_fileno++; 584 585 /* 586 * fill out the dev node according to type 587 */ 588 switch(entrytype) { 589 case DEV_DIR: 590 /* 591 * As it's a directory, make sure 592 * it has a null entries list 593 */ 594 dnp->dn_typeinfo.Dir.dirlast = &(dnp->dn_typeinfo.Dir.dirlist); 595 dnp->dn_typeinfo.Dir.dirlist = (devdirent_t *)0; 596 dnp->dn_typeinfo.Dir.entrycount = 0; 597 /* until we know better, it has a null parent pointer*/ 598 dnp->dn_typeinfo.Dir.parent = NULL; 599 dnp->dn_links++; /* for .*/ 600 dnp->dn_typeinfo.Dir.myname = NULL; 601 /* 602 * make sure that the ops associated with it are the ops 603 * that we use (by default) for directories 604 */ 605 dnp->dn_ops = &devfs_vnodeop_p; 606 dnp->dn_mode |= 0555; /* default perms */ 607 break; 608 case DEV_SLNK: 609 /* 610 * As it's a symlink allocate and store the link info 611 * Symlinks should only ever be created by the user, 612 * so they are not on the back plane and should not be 613 * propogated forward.. a bit like directories in that way.. 614 * A symlink only exists on one plane and has its own 615 * node.. therefore we might be on any random plane. 616 */ 617 MALLOC(dnp->dn_typeinfo.Slnk.name, char *, 618 typeinfo->Slnk.namelen+1, 619 M_DEVFSNODE, M_WAITOK); 620 if (!dnp->dn_typeinfo.Slnk.name) { 621 FREE(dnp,M_DEVFSNODE); 622 return ENOMEM; 623 } 624 strlcpy(dnp->dn_typeinfo.Slnk.name, typeinfo->Slnk.name, 625 typeinfo->Slnk.namelen + 1); 626 dnp->dn_typeinfo.Slnk.namelen = typeinfo->Slnk.namelen; 627 DEVFS_INCR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1); 628 dnp->dn_ops = &devfs_vnodeop_p; 629 dnp->dn_mode |= 0555; /* default perms */ 630 break; 631 case DEV_CDEV: 632 case DEV_BDEV: 633 /* 634 * Make sure it has DEVICE type ops 635 * and device specific fields are correct 636 */ 637 dnp->dn_ops = &devfs_spec_vnodeop_p; 638 dnp->dn_typeinfo.dev = typeinfo->dev; 639 break; 640 641 #if FDESC 642 /* /dev/fd is special */ 643 case DEV_DEVFD: 644 dnp->dn_ops = &devfs_devfd_vnodeop_p; 645 dnp->dn_mode |= 0555; /* default perms */ 646 break; 647 648 #endif /* FDESC */ 649 default: 650 return EINVAL; 651 } 652 653 *dn_pp = dnp; 654 DEVFS_INCR_NODES(); 655 return 0 ; 656} 657 658 659/*********************************************************************** 660 * called with DEVFS_LOCK held 661 **********************************************************************/ 662void 663devnode_free(devnode_t * dnp) 664{ 665#if CONFIG_MACF 666 mac_devfs_label_destroy(dnp); 667#endif 668 if (dnp->dn_type == DEV_SLNK) { 669 DEVFS_DECR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1); 670 FREE(dnp->dn_typeinfo.Slnk.name, M_DEVFSNODE); 671 } 672 DEVFS_DECR_NODES(); 673 FREE(dnp, M_DEVFSNODE); 674} 675 676 677/*********************************************************************** 678 * called with DEVFS_LOCK held 679 **********************************************************************/ 680static void 681devfs_dn_free(devnode_t * dnp) 682{ 683 if(--dnp->dn_links <= 0 ) /* can be -1 for initial free, on error */ 684 { 685 /*probably need to do other cleanups XXX */ 686 if (dnp->dn_nextsibling != dnp) { 687 devnode_t * * prevp = dnp->dn_prevsiblingp; 688 *prevp = dnp->dn_nextsibling; 689 dnp->dn_nextsibling->dn_prevsiblingp = prevp; 690 691 } 692 693 /* Can only free if there are no references; otherwise, wait for last vnode to be reclaimed */ 694 if (dnp->dn_refcount == 0) { 695 devnode_free(dnp); 696 } 697 else { 698 dnp->dn_lflags |= DN_DELETE; 699 } 700 } 701} 702 703/***********************************************************************\ 704* Front Node Operations * 705* Add or delete a chain of front nodes * 706\***********************************************************************/ 707 708 709/*********************************************************************** 710 * Given a directory backing node, and a child backing node, add the 711 * appropriate front nodes to the front nodes of the directory to 712 * represent the child node to the user 713 * 714 * on failure, front nodes will either be correct or not exist for each 715 * front dir, however dirs completed will not be stripped of completed 716 * frontnodes on failure of a later frontnode 717 * 718 * This allows a new node to be propogated through all mounted planes 719 * 720 * called with DEVFS_LOCK held 721 ***********************************************************************/ 722static int 723devfs_propogate(devdirent_t * parent,devdirent_t * child, devfs_event_log_t delp) 724{ 725 int error; 726 devdirent_t * newnmp; 727 devnode_t * dnp = child->de_dnp; 728 devnode_t * pdnp = parent->de_dnp; 729 devnode_t * adnp = parent->de_dnp; 730 int type = child->de_dnp->dn_type; 731 uint32_t events; 732 733 events = (dnp->dn_type == DEV_DIR ? VNODE_EVENT_DIR_CREATED : VNODE_EVENT_FILE_CREATED); 734 if (delp != NULL) { 735 devfs_record_event(delp, pdnp, events); 736 } 737 738 /*********************************************** 739 * Find the other instances of the parent node 740 ***********************************************/ 741 for (adnp = pdnp->dn_nextsibling; 742 adnp != pdnp; 743 adnp = adnp->dn_nextsibling) 744 { 745 /* 746 * Make the node, using the original as a prototype) 747 * if the node already exists on that plane it won't be 748 * re-made.. 749 */ 750 if ((error = dev_add_entry(child->de_name, adnp, type, 751 NULL, dnp, adnp->dn_dvm, 752 &newnmp)) != 0) { 753 printf("duplicating %s failed\n",child->de_name); 754 } else { 755 if (delp != NULL) { 756 devfs_record_event(delp, adnp, events); 757 758 /* 759 * Slightly subtle. We're guaranteed that there will 760 * only be a vnode hooked into this devnode if we're creating 761 * a new link to an existing node; otherwise, the devnode is new 762 * and no one can have looked it up yet. If we're making a link, 763 * then the buffer is large enough for two nodes in each 764 * plane; otherwise, there's no vnode and this call will 765 * do nothing. 766 */ 767 devfs_record_event(delp, newnmp->de_dnp, VNODE_EVENT_LINK); 768 } 769 } 770 } 771 return 0; /* for now always succeed */ 772} 773 774static uint32_t 775remove_notify_count(devnode_t *dnp) 776{ 777 uint32_t notify_count = 0; 778 devnode_t *dnp2; 779 780 /* 781 * Could need to notify for one removed node on each mount and 782 * one parent for each such node. 783 */ 784 notify_count = devfs_nmountplanes; 785 notify_count += dnp->dn_links; 786 for (dnp2 = dnp->dn_nextsibling; dnp2 != dnp; dnp2 = dnp2->dn_nextsibling) { 787 notify_count += dnp2->dn_links; 788 } 789 790 return notify_count; 791 792} 793 794/*********************************************************************** 795 * remove all instances of this devicename [for backing nodes..] 796 * note.. if there is another link to the node (non dir nodes only) 797 * then the devfs_node will still exist as the ref count will be non-0 798 * removing a directory node will remove all sup-nodes on all planes (ZAP) 799 * 800 * Used by device drivers to remove nodes that are no longer relevant 801 * The argument is the 'cookie' they were given when they created the node 802 * this function is exported.. see devfs.h 803 ***********************************************************************/ 804void 805devfs_remove(void *dirent_p) 806{ 807 devnode_t * dnp = ((devdirent_t *)dirent_p)->de_dnp; 808 devnode_t * dnp2; 809 boolean_t lastlink; 810 struct devfs_event_log event_log; 811 uint32_t log_count = 0; 812 int do_notify = 0; 813 int need_free = 0; 814 struct devfs_vnode_event stackbuf[NUM_STACK_ENTRIES]; 815 816 DEVFS_LOCK(); 817 818 if (!devfs_ready) { 819 printf("devfs_remove: not ready for devices!\n"); 820 goto out; 821 } 822 823 log_count = remove_notify_count(dnp); 824 825 if (log_count > NUM_STACK_ENTRIES) { 826 uint32_t new_count; 827wrongsize: 828 DEVFS_UNLOCK(); 829 if (devfs_init_event_log(&event_log, log_count, NULL) == 0) { 830 do_notify = 1; 831 need_free = 1; 832 } 833 DEVFS_LOCK(); 834 835 new_count = remove_notify_count(dnp); 836 if (need_free && (new_count > log_count)) { 837 devfs_release_event_log(&event_log, 1); 838 need_free = 0; 839 do_notify = 0; 840 log_count = log_count * 2; 841 goto wrongsize; 842 } 843 } else { 844 if (devfs_init_event_log(&event_log, NUM_STACK_ENTRIES, &stackbuf[0]) == 0) { 845 do_notify = 1; 846 } 847 } 848 849 /* This file has been deleted */ 850 if (do_notify != 0) { 851 devfs_record_event(&event_log, dnp, VNODE_EVENT_DELETE); 852 } 853 854 /* keep removing the next sibling till only we exist. */ 855 while ((dnp2 = dnp->dn_nextsibling) != dnp) { 856 857 /* 858 * Keep removing the next front node till no more exist 859 */ 860 dnp->dn_nextsibling = dnp2->dn_nextsibling; 861 dnp->dn_nextsibling->dn_prevsiblingp = &(dnp->dn_nextsibling); 862 dnp2->dn_nextsibling = dnp2; 863 dnp2->dn_prevsiblingp = &(dnp2->dn_nextsibling); 864 865 /* This file has been deleted in this plane */ 866 if (do_notify != 0) { 867 devfs_record_event(&event_log, dnp2, VNODE_EVENT_DELETE); 868 } 869 870 if (dnp2->dn_linklist) { 871 do { 872 lastlink = (1 == dnp2->dn_links); 873 /* Each parent of a link to this file has lost a child in this plane */ 874 if (do_notify != 0) { 875 devfs_record_event(&event_log, dnp2->dn_linklist->de_parent, VNODE_EVENT_FILE_REMOVED); 876 } 877 dev_free_name(dnp2->dn_linklist); 878 } while (!lastlink); 879 } 880 } 881 882 /* 883 * then free the main node 884 * If we are not running in SPLIT_DEVS mode, then 885 * THIS is what gets rid of the propogated nodes. 886 */ 887 if (dnp->dn_linklist) { 888 do { 889 lastlink = (1 == dnp->dn_links); 890 /* Each parent of a link to this file has lost a child */ 891 if (do_notify != 0) { 892 devfs_record_event(&event_log, dnp->dn_linklist->de_parent, VNODE_EVENT_FILE_REMOVED); 893 } 894 dev_free_name(dnp->dn_linklist); 895 } while (!lastlink); 896 } 897out: 898 DEVFS_UNLOCK(); 899 if (do_notify != 0) { 900 devfs_bulk_notify(&event_log); 901 devfs_release_event_log(&event_log, need_free); 902 } 903 904 return ; 905} 906 907 908 909/*************************************************************** 910 * duplicate the backing tree into a tree of nodes hung off the 911 * mount point given as the argument. Do this by 912 * calling dev_dup_entry which recurses all the way 913 * up the tree.. 914 * 915 * called with DEVFS_LOCK held 916 **************************************************************/ 917int 918dev_dup_plane(struct devfsmount *devfs_mp_p) 919{ 920 devdirent_t * new; 921 int error = 0; 922 923 if ((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p))) 924 return error; 925 devfs_mp_p->plane_root = new; 926 devfs_nmountplanes++; 927 return error; 928} 929 930 931 932/*************************************************************** 933 * Free a whole plane 934 * 935 * called with DEVFS_LOCK held 936 ***************************************************************/ 937void 938devfs_free_plane(struct devfsmount *devfs_mp_p) 939{ 940 devdirent_t * dirent_p; 941 942 dirent_p = devfs_mp_p->plane_root; 943 if (dirent_p) { 944 dev_free_hier(dirent_p); 945 dev_free_name(dirent_p); 946 } 947 devfs_mp_p->plane_root = NULL; 948 devfs_nmountplanes--; 949 950 if (devfs_nmountplanes > (devfs_nmountplanes+1)) { 951 panic("plane count wrapped around.\n"); 952 } 953} 954 955 956/*************************************************************** 957 * Create and link in a new front element.. 958 * Parent can be 0 for a root node 959 * Not presently usable to make a symlink XXX 960 * (Ok, symlinks don't propogate) 961 * recursively will create subnodes corresponding to equivalent 962 * child nodes in the base level 963 * 964 * called with DEVFS_LOCK held 965 ***************************************************************/ 966static int 967dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp, 968 struct devfsmount *dvm) 969{ 970 devdirent_t * entry_p; 971 devdirent_t * newback; 972 devdirent_t * newfront; 973 int error; 974 devnode_t * dnp = back->de_dnp; 975 int type = dnp->dn_type; 976 977 /* 978 * go get the node made (if we need to) 979 * use the back one as a prototype 980 */ 981 if ((error = dev_add_entry(back->de_name, parent, type, 982 NULL, dnp, 983 parent?parent->dn_dvm:dvm, &entry_p)) != 0) { 984 printf("duplicating %s failed\n",back->de_name); 985 } 986 987 /* 988 * If we have just made the root, then insert the pointer to the 989 * mount information 990 */ 991 if(dvm) { 992 entry_p->de_dnp->dn_dvm = dvm; 993 } 994 995 /* 996 * If it is a directory, then recurse down all the other 997 * subnodes in it.... 998 * note that this time we don't pass on the mount info.. 999 */ 1000 if (type == DEV_DIR) 1001 { 1002 for(newback = back->de_dnp->dn_typeinfo.Dir.dirlist; 1003 newback; newback = newback->de_next) 1004 { 1005 if((error = dev_dup_entry(entry_p->de_dnp, 1006 newback, &newfront, NULL)) != 0) 1007 { 1008 break; /* back out with an error */ 1009 } 1010 } 1011 } 1012 *dnm_pp = entry_p; 1013 return error; 1014} 1015 1016 1017/*************************************************************** 1018 * Free a name node 1019 * remember that if there are other names pointing to the 1020 * dev_node then it may not get freed yet 1021 * can handle if there is no dnp 1022 * 1023 * called with DEVFS_LOCK held 1024 ***************************************************************/ 1025 1026int 1027dev_free_name(devdirent_t * dirent_p) 1028{ 1029 devnode_t * parent = dirent_p->de_parent; 1030 devnode_t * dnp = dirent_p->de_dnp; 1031 1032 if(dnp) { 1033 if(dnp->dn_type == DEV_DIR) 1034 { 1035 devnode_t * p; 1036 1037 if(dnp->dn_typeinfo.Dir.dirlist) 1038 return (ENOTEMPTY); 1039 p = dnp->dn_typeinfo.Dir.parent; 1040 devfs_dn_free(dnp); /* account for '.' */ 1041 devfs_dn_free(p); /* '..' */ 1042 } 1043 /* 1044 * unlink us from the list of links for this node 1045 * If we are the only link, it's easy! 1046 * if we are a DIR of course there should not be any 1047 * other links. 1048 */ 1049 if(dirent_p->de_nextlink == dirent_p) { 1050 dnp->dn_linklist = NULL; 1051 } else { 1052 if(dnp->dn_linklist == dirent_p) { 1053 dnp->dn_linklist = dirent_p->de_nextlink; 1054 } 1055 } 1056 devfs_dn_free(dnp); 1057 } 1058 1059 dirent_p->de_nextlink->de_prevlinkp = dirent_p->de_prevlinkp; 1060 *(dirent_p->de_prevlinkp) = dirent_p->de_nextlink; 1061 1062 /* 1063 * unlink ourselves from the directory on this plane 1064 */ 1065 if(parent) /* if not fs root */ 1066 { 1067 if( (*dirent_p->de_prevp = dirent_p->de_next) )/* yes, assign */ 1068 { 1069 dirent_p->de_next->de_prevp = dirent_p->de_prevp; 1070 } 1071 else 1072 { 1073 parent->dn_typeinfo.Dir.dirlast 1074 = dirent_p->de_prevp; 1075 } 1076 parent->dn_typeinfo.Dir.entrycount--; 1077 parent->dn_len -= strlen(dirent_p->de_name) + 8; 1078 } 1079 1080 DEVFS_DECR_ENTRIES(); 1081 FREE(dirent_p, M_DEVFSNAME); 1082 return 0; 1083} 1084 1085 1086/*************************************************************** 1087 * Free a hierarchy starting at a directory node name 1088 * remember that if there are other names pointing to the 1089 * dev_node then it may not get freed yet 1090 * can handle if there is no dnp 1091 * leave the node itself allocated. 1092 * 1093 * called with DEVFS_LOCK held 1094 ***************************************************************/ 1095 1096static void 1097dev_free_hier(devdirent_t * dirent_p) 1098{ 1099 devnode_t * dnp = dirent_p->de_dnp; 1100 1101 if(dnp) { 1102 if(dnp->dn_type == DEV_DIR) 1103 { 1104 while(dnp->dn_typeinfo.Dir.dirlist) 1105 { 1106 dev_free_hier(dnp->dn_typeinfo.Dir.dirlist); 1107 dev_free_name(dnp->dn_typeinfo.Dir.dirlist); 1108 } 1109 } 1110 } 1111} 1112 1113 1114/*************************************************************** 1115 * given a dev_node, find the appropriate vnode if one is already 1116 * associated, or get a new one and associate it with the dev_node 1117 * 1118 * called with DEVFS_LOCK held 1119 * 1120 * If an error is returned, then the dnp may have been freed (we 1121 * raced with a delete and lost). A devnode should not be accessed 1122 * after devfs_dntovn() fails. 1123 ****************************************************************/ 1124int 1125devfs_dntovn(devnode_t * dnp, struct vnode **vn_pp, __unused struct proc * p) 1126{ 1127 struct vnode *vn_p; 1128 int error = 0; 1129 struct vnode_fsparam vfsp; 1130 enum vtype vtype = 0; 1131 int markroot = 0; 1132 int n_minor = DEVFS_CLONE_ALLOC; /* new minor number for clone device */ 1133 1134 /* 1135 * We should never come in and find that our devnode has been marked for delete. 1136 * The lookup should have held the lock from entry until now; it should not have 1137 * been able to find a removed entry. Any other pathway would have just created 1138 * the devnode and come here without dropping the devfs lock, so no one would 1139 * have a chance to delete. 1140 */ 1141 if (dnp->dn_lflags & DN_DELETE) { 1142 panic("devfs_dntovn: DN_DELETE set on a devnode upon entry."); 1143 } 1144 1145 devfs_ref_node(dnp); 1146 1147retry: 1148 *vn_pp = NULL; 1149 vn_p = dnp->dn_vn; 1150 1151 if (vn_p) { /* already has a vnode */ 1152 uint32_t vid; 1153 1154 vid = vnode_vid(vn_p); 1155 1156 DEVFS_UNLOCK(); 1157 1158 error = vnode_getwithvid(vn_p, vid); 1159 1160 DEVFS_LOCK(); 1161 1162 if (dnp->dn_lflags & DN_DELETE) { 1163 /* 1164 * our BUSY node got marked for 1165 * deletion while the DEVFS lock 1166 * was dropped... 1167 */ 1168 if (error == 0) { 1169 /* 1170 * vnode_getwithvid returned a valid ref 1171 * which we need to drop 1172 */ 1173 vnode_put(vn_p); 1174 } 1175 1176 /* 1177 * This entry is no longer in the namespace. This is only 1178 * possible for lookup: no other path would not find an existing 1179 * vnode. Therefore, ENOENT is a valid result. 1180 */ 1181 error = ENOENT; 1182 } 1183 if ( !error) 1184 *vn_pp = vn_p; 1185 1186 goto out; 1187 } 1188 1189 /* 1190 * If we get here, then we've beaten any deletes; 1191 * if someone sets DN_DELETE during a subsequent drop 1192 * of the devfs lock, we'll still vend a vnode. 1193 */ 1194 1195 if (dnp->dn_lflags & DN_CREATE) { 1196 dnp->dn_lflags |= DN_CREATEWAIT; 1197 msleep(&dnp->dn_lflags, &devfs_mutex, PRIBIO, 0 , 0); 1198 goto retry; 1199 } 1200 1201 dnp->dn_lflags |= DN_CREATE; 1202 1203 switch (dnp->dn_type) { 1204 case DEV_SLNK: 1205 vtype = VLNK; 1206 break; 1207 case DEV_DIR: 1208 if (dnp->dn_typeinfo.Dir.parent == dnp) { 1209 markroot = 1; 1210 } 1211 vtype = VDIR; 1212 break; 1213 case DEV_BDEV: 1214 case DEV_CDEV: 1215 vtype = (dnp->dn_type == DEV_BDEV) ? VBLK : VCHR; 1216 break; 1217#if FDESC 1218 case DEV_DEVFD: 1219 vtype = VDIR; 1220 break; 1221#endif /* FDESC */ 1222 } 1223 vfsp.vnfs_mp = dnp->dn_dvm->mount; 1224 vfsp.vnfs_vtype = vtype; 1225 vfsp.vnfs_str = "devfs"; 1226 vfsp.vnfs_dvp = 0; 1227 vfsp.vnfs_fsnode = dnp; 1228 vfsp.vnfs_cnp = 0; 1229 vfsp.vnfs_vops = *(dnp->dn_ops); 1230 1231 if (vtype == VBLK || vtype == VCHR) { 1232 /* 1233 * Ask the clone minor number function for a new minor number 1234 * to use for the next device instance. If an administative 1235 * limit has been reached, this function will return -1. 1236 */ 1237 if (dnp->dn_clone != NULL) { 1238 int n_major = major(dnp->dn_typeinfo.dev); 1239 1240 n_minor = (*dnp->dn_clone)(dnp->dn_typeinfo.dev, DEVFS_CLONE_ALLOC); 1241 if (n_minor == -1) { 1242 error = ENOMEM; 1243 goto out; 1244 } 1245 1246 vfsp.vnfs_rdev = makedev(n_major, n_minor);; 1247 } else { 1248 vfsp.vnfs_rdev = dnp->dn_typeinfo.dev; 1249 } 1250 } else { 1251 vfsp.vnfs_rdev = 0; 1252 } 1253 vfsp.vnfs_filesize = 0; 1254 vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE; 1255 /* Tag system files */ 1256 vfsp.vnfs_marksystem = 0; 1257 vfsp.vnfs_markroot = markroot; 1258 1259 DEVFS_UNLOCK(); 1260 1261 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &vn_p); 1262 1263 /* Do this before grabbing the lock */ 1264 if (error == 0) { 1265 vnode_setneedinactive(vn_p); 1266 } 1267 1268 DEVFS_LOCK(); 1269 1270 if (error == 0) { 1271 vnode_settag(vn_p, VT_DEVFS); 1272 1273 if ((dnp->dn_clone != NULL) && (dnp->dn_vn != NULLVP) ) 1274 panic("devfs_dntovn: cloning device with a vnode?\n"); 1275 1276 *vn_pp = vn_p; 1277 1278 /* 1279 * Another vnode that has this devnode as its v_data. 1280 * This reference, unlike the one taken at the start 1281 * of the function, persists until a VNOP_RECLAIM 1282 * comes through for this vnode. 1283 */ 1284 devfs_ref_node(dnp); 1285 1286 /* 1287 * A cloned vnode is not hooked into the devnode; every lookup 1288 * gets a new vnode. 1289 */ 1290 if (dnp->dn_clone == NULL) { 1291 dnp->dn_vn = vn_p; 1292 } 1293 } else if (n_minor != DEVFS_CLONE_ALLOC) { 1294 /* 1295 * If we failed the create, we need to release the cloned minor 1296 * back to the free list. In general, this is only useful if 1297 * the clone function results in a state change in the cloned 1298 * device for which the minor number was obtained. If we get 1299 * past this point withouth falling into this case, it's 1300 * assumed that any state to be released will be released when 1301 * the vnode is dropped, instead. 1302 */ 1303 (void)(*dnp->dn_clone)(dnp->dn_typeinfo.dev, DEVFS_CLONE_FREE); 1304 } 1305 1306 dnp->dn_lflags &= ~DN_CREATE; 1307 if (dnp->dn_lflags & DN_CREATEWAIT) { 1308 dnp->dn_lflags &= ~DN_CREATEWAIT; 1309 wakeup(&dnp->dn_lflags); 1310 } 1311 1312out: 1313 /* 1314 * Release the reference we took to prevent deletion while we weren't holding the lock. 1315 * If not returning success, then dropping this reference could delete the devnode; 1316 * no one should access a devnode after a call to devfs_dntovn fails. 1317 */ 1318 devfs_rele_node(dnp); 1319 1320 return error; 1321} 1322 1323/* 1324 * Increment refcount on a devnode; prevents free of the node 1325 * while the devfs lock is not held. 1326 */ 1327void 1328devfs_ref_node(devnode_t *dnp) 1329{ 1330 dnp->dn_refcount++; 1331} 1332 1333/* 1334 * Release a reference on a devnode. If the devnode is marked for 1335 * free and the refcount is dropped to zero, do the free. 1336 */ 1337void 1338devfs_rele_node(devnode_t *dnp) 1339{ 1340 dnp->dn_refcount--; 1341 if (dnp->dn_refcount < 0) { 1342 panic("devfs_rele_node: devnode with a negative refcount!\n"); 1343 } else if ((dnp->dn_refcount == 0) && (dnp->dn_lflags & DN_DELETE)) { 1344 devnode_free(dnp); 1345 } 1346 1347} 1348 1349/*********************************************************************** 1350 * add a whole device, with no prototype.. make name element and node 1351 * Used for adding the original device entries 1352 * 1353 * called with DEVFS_LOCK held 1354 ***********************************************************************/ 1355int 1356dev_add_entry(const char *name, devnode_t * parent, int type, devnode_type_t * typeinfo, 1357 devnode_t * proto, struct devfsmount *dvm, devdirent_t * *nm_pp) 1358{ 1359 devnode_t * dnp; 1360 int error = 0; 1361 1362 if ((error = dev_add_node(type, typeinfo, proto, &dnp, 1363 (parent?parent->dn_dvm:dvm))) != 0) 1364 { 1365 printf("devfs: %s: base node allocation failed (Errno=%d)\n", 1366 name,error); 1367 return error; 1368 } 1369 if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0) 1370 { 1371 devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */ 1372 printf("devfs: %s: name slot allocation failed (Errno=%d)\n", 1373 name,error); 1374 1375 } 1376 return error; 1377} 1378 1379static void 1380devfs_bulk_notify(devfs_event_log_t delp) 1381{ 1382 uint32_t i; 1383 for (i = 0; i < delp->del_used; i++) { 1384 devfs_vnode_event_t dvep = &delp->del_entries[i]; 1385 if (vnode_getwithvid(dvep->dve_vp, dvep->dve_vid) == 0) { 1386 vnode_notify(dvep->dve_vp, dvep->dve_events, NULL); 1387 vnode_put(dvep->dve_vp); 1388 } 1389 } 1390} 1391 1392static void 1393devfs_record_event(devfs_event_log_t delp, devnode_t *dnp, uint32_t events) 1394{ 1395 if (delp->del_used >= delp->del_max) { 1396 panic("devfs event log overflowed.\n"); 1397 } 1398 1399 /* Can only notify for nodes that have an associated vnode */ 1400 if (dnp->dn_vn != NULLVP && vnode_ismonitored(dnp->dn_vn)) { 1401 devfs_vnode_event_t dvep = &delp->del_entries[delp->del_used]; 1402 dvep->dve_vp = dnp->dn_vn; 1403 dvep->dve_vid = vnode_vid(dnp->dn_vn); 1404 dvep->dve_events = events; 1405 delp->del_used++; 1406 } 1407} 1408 1409static int 1410devfs_init_event_log(devfs_event_log_t delp, uint32_t count, devfs_vnode_event_t buf) 1411{ 1412 devfs_vnode_event_t dvearr; 1413 1414 if (buf == NULL) { 1415 MALLOC(dvearr, devfs_vnode_event_t, count * sizeof(struct devfs_vnode_event), M_TEMP, M_WAITOK | M_ZERO); 1416 if (dvearr == NULL) { 1417 return ENOMEM; 1418 } 1419 } else { 1420 dvearr = buf; 1421 } 1422 1423 delp->del_max = count; 1424 delp->del_used = 0; 1425 delp->del_entries = dvearr; 1426 return 0; 1427} 1428 1429static void 1430devfs_release_event_log(devfs_event_log_t delp, int need_free) 1431{ 1432 if (delp->del_entries == NULL) { 1433 panic("Free of devfs notify info that has not been intialized.\n"); 1434 } 1435 1436 if (need_free) { 1437 FREE(delp->del_entries, M_TEMP); 1438 } 1439 1440 delp->del_entries = NULL; 1441} 1442 1443/* 1444 * Function: devfs_make_node 1445 * 1446 * Purpose 1447 * Create a device node with the given pathname in the devfs namespace. 1448 * 1449 * Parameters: 1450 * dev - the dev_t value to associate 1451 * chrblk - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 1452 * uid, gid - ownership 1453 * perms - permissions 1454 * clone - minor number cloning function 1455 * fmt, ... - path format string with printf args to format the path name 1456 * Returns: 1457 * A handle to a device node if successful, NULL otherwise. 1458 */ 1459void * 1460devfs_make_node_clone(dev_t dev, int chrblk, uid_t uid, 1461 gid_t gid, int perms, int (*clone)(dev_t dev, int action), 1462 const char *fmt, ...) 1463{ 1464 devdirent_t * new_dev = NULL; 1465 devfstype_t type; 1466 va_list ap; 1467 1468 switch (chrblk) { 1469 case DEVFS_CHAR: 1470 type = DEV_CDEV; 1471 break; 1472 case DEVFS_BLOCK: 1473 type = DEV_BDEV; 1474 break; 1475 default: 1476 goto out; 1477 } 1478 1479 va_start(ap, fmt); 1480 new_dev = devfs_make_node_internal(dev, type, uid, gid, perms, clone, fmt, ap); 1481 va_end(ap); 1482out: 1483 return new_dev; 1484} 1485 1486 1487/* 1488 * Function: devfs_make_node 1489 * 1490 * Purpose 1491 * Create a device node with the given pathname in the devfs namespace. 1492 * 1493 * Parameters: 1494 * dev - the dev_t value to associate 1495 * chrblk - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 1496 * uid, gid - ownership 1497 * perms - permissions 1498 * fmt, ... - path format string with printf args to format the path name 1499 * Returns: 1500 * A handle to a device node if successful, NULL otherwise. 1501 */ 1502void * 1503devfs_make_node(dev_t dev, int chrblk, uid_t uid, 1504 gid_t gid, int perms, const char *fmt, ...) 1505{ 1506 devdirent_t * new_dev = NULL; 1507 devfstype_t type; 1508 va_list ap; 1509 1510 if (chrblk != DEVFS_CHAR && chrblk != DEVFS_BLOCK) 1511 goto out; 1512 1513 type = (chrblk == DEVFS_BLOCK ? DEV_BDEV : DEV_CDEV); 1514 1515 va_start(ap, fmt); 1516 new_dev = devfs_make_node_internal(dev, type, uid, gid, perms, NULL, fmt, ap); 1517 va_end(ap); 1518 1519out: 1520 return new_dev; 1521} 1522 1523static devdirent_t * 1524devfs_make_node_internal(dev_t dev, devfstype_t type, uid_t uid, 1525 gid_t gid, int perms, int (*clone)(dev_t dev, int action), const char *fmt, va_list ap) 1526{ 1527 devdirent_t * new_dev = NULL; 1528 devnode_t * dnp; 1529 devnode_type_t typeinfo; 1530 1531 char *name, buf[256]; /* XXX */ 1532 const char *path; 1533#if CONFIG_MACF 1534 char buff[sizeof(buf)]; 1535#endif 1536 int i; 1537 uint32_t log_count; 1538 struct devfs_event_log event_log; 1539 struct devfs_vnode_event stackbuf[NUM_STACK_ENTRIES]; 1540 int need_free = 0; 1541 1542 vsnprintf(buf, sizeof(buf), fmt, ap); 1543 1544#if CONFIG_MACF 1545 bcopy(buf, buff, sizeof(buff)); 1546 buff[sizeof(buff)-1] = 0; 1547#endif 1548 name = NULL; 1549 1550 for(i=strlen(buf); i>0; i--) 1551 if(buf[i] == '/') { 1552 name=&buf[i]; 1553 buf[i]=0; 1554 break; 1555 } 1556 1557 if (name) { 1558 *name++ = '\0'; 1559 path = buf; 1560 } else { 1561 name = buf; 1562 path = "/"; 1563 } 1564 1565 log_count = devfs_nmountplanes; 1566 if (log_count > NUM_STACK_ENTRIES) { 1567wrongsize: 1568 need_free = 1; 1569 if (devfs_init_event_log(&event_log, log_count, NULL) != 0) { 1570 return NULL; 1571 } 1572 } else { 1573 need_free = 0; 1574 log_count = NUM_STACK_ENTRIES; 1575 if (devfs_init_event_log(&event_log, log_count, &stackbuf[0]) != 0) { 1576 return NULL; 1577 } 1578 } 1579 1580 DEVFS_LOCK(); 1581 if (log_count < devfs_nmountplanes) { 1582 DEVFS_UNLOCK(); 1583 devfs_release_event_log(&event_log, need_free); 1584 log_count = log_count * 2; 1585 goto wrongsize; 1586 } 1587 1588 if (!devfs_ready) { 1589 printf("devfs_make_node: not ready for devices!\n"); 1590 goto out; 1591 } 1592 1593 /* find/create directory path ie. mkdir -p */ 1594 if (dev_finddir(path, NULL, DEVFS_CREATE, &dnp, &event_log) == 0) { 1595 typeinfo.dev = dev; 1596 if (dev_add_entry(name, dnp, type, &typeinfo, NULL, NULL, &new_dev) == 0) { 1597 new_dev->de_dnp->dn_gid = gid; 1598 new_dev->de_dnp->dn_uid = uid; 1599 new_dev->de_dnp->dn_mode |= perms; 1600 new_dev->de_dnp->dn_clone = clone; 1601#if CONFIG_MACF 1602 mac_devfs_label_associate_device(dev, new_dev->de_dnp, buff); 1603#endif 1604 devfs_propogate(dnp->dn_typeinfo.Dir.myname, new_dev, &event_log); 1605 } 1606 } 1607 1608out: 1609 DEVFS_UNLOCK(); 1610 1611 devfs_bulk_notify(&event_log); 1612 devfs_release_event_log(&event_log, need_free); 1613 return new_dev; 1614} 1615 1616/* 1617 * Function: devfs_make_link 1618 * 1619 * Purpose: 1620 * Create a link to a previously created device node. 1621 * 1622 * Returns: 1623 * 0 if successful, -1 if failed 1624 */ 1625int 1626devfs_make_link(void *original, char *fmt, ...) 1627{ 1628 devdirent_t * new_dev = NULL; 1629 devdirent_t * orig = (devdirent_t *) original; 1630 devnode_t * dirnode; /* devnode for parent directory */ 1631 struct devfs_event_log event_log; 1632 uint32_t log_count; 1633 1634 va_list ap; 1635 char *p, buf[256]; /* XXX */ 1636 int i; 1637 1638 DEVFS_LOCK(); 1639 1640 if (!devfs_ready) { 1641 DEVFS_UNLOCK(); 1642 printf("devfs_make_link: not ready for devices!\n"); 1643 return -1; 1644 } 1645 DEVFS_UNLOCK(); 1646 1647 va_start(ap, fmt); 1648 vsnprintf(buf, sizeof(buf), fmt, ap); 1649 va_end(ap); 1650 1651 p = NULL; 1652 1653 for(i=strlen(buf); i>0; i--) { 1654 if(buf[i] == '/') { 1655 p=&buf[i]; 1656 buf[i]=0; 1657 break; 1658 } 1659 } 1660 1661 /* 1662 * One slot for each directory, one for each devnode 1663 * whose link count changes 1664 */ 1665 log_count = devfs_nmountplanes * 2; 1666wrongsize: 1667 if (devfs_init_event_log(&event_log, log_count, NULL) != 0) { 1668 /* No lock held, no allocations done, can just return */ 1669 return -1; 1670 } 1671 1672 DEVFS_LOCK(); 1673 1674 if (log_count < devfs_nmountplanes) { 1675 DEVFS_UNLOCK(); 1676 devfs_release_event_log(&event_log, 1); 1677 log_count = log_count * 2; 1678 goto wrongsize; 1679 } 1680 1681 if (p) { 1682 *p++ = '\0'; 1683 1684 if (dev_finddir(buf, NULL, DEVFS_CREATE, &dirnode, &event_log) 1685 || dev_add_name(p, dirnode, NULL, orig->de_dnp, &new_dev)) 1686 goto fail; 1687 } else { 1688 if (dev_finddir("", NULL, DEVFS_CREATE, &dirnode, &event_log) 1689 || dev_add_name(buf, dirnode, NULL, orig->de_dnp, &new_dev)) 1690 goto fail; 1691 } 1692 devfs_propogate(dirnode->dn_typeinfo.Dir.myname, new_dev, &event_log); 1693fail: 1694 DEVFS_UNLOCK(); 1695 devfs_bulk_notify(&event_log); 1696 devfs_release_event_log(&event_log, 1); 1697 1698 return ((new_dev != NULL) ? 0 : -1); 1699} 1700