2  * Copyright (c) 2000-2014 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  30  * Copyright 1997,1998 Julian Elischer.  All rights reserved. 
  33  * Redistribution and use in source and binary forms, with or without 
  34  * modification, are permitted provided that the following conditions are 
  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. 
  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 
  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, 
  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 
  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 */ 
  89 #define SPLIT_DEVS 1 /* maybe make this an option */ 
  90 /*#define SPLIT_DEVS 1*/ 
  92 #include <sys/param.h> 
  93 #include <sys/systm.h> 
  94 #include <sys/kernel.h> 
  96 #include <sys/malloc.h> 
  97 #include <sys/mount_internal.h> 
  99 #include <sys/vnode_internal.h> 
 101 #include <libkern/OSAtomic.h> 
 102 #define BSD_KERNEL_PRIVATE      1       /* devfs_make_link() prototype */ 
 104 #include "devfsdefs.h" 
 107 #include <security/mac_framework.h> 
 114 typedef struct devfs_vnode_event 
{ 
 118 } *devfs_vnode_event_t
; 
 121  * Size of stack buffer (fast path) for notifications.  If 
 122  * the number of mounts is small, no need to malloc a buffer. 
 124 #define NUM_STACK_ENTRIES 5 
 126 typedef struct devfs_event_log 
{ 
 129         devfs_vnode_event_t     del_entries
; 
 130 } *devfs_event_log_t
; 
 133 static void     dev_free_hier(devdirent_t 
*); 
 134 static int      devfs_propogate(devdirent_t 
*, devdirent_t 
*, devfs_event_log_t
); 
 135 static int      dev_finddir(const char *, devnode_t 
*, int, devnode_t 
**, devfs_event_log_t
); 
 136 static int      dev_dup_entry(devnode_t 
*, devdirent_t 
*, devdirent_t 
**, struct devfsmount 
*); 
 137 void            devfs_ref_node(devnode_t 
*); 
 138 void            devfs_rele_node(devnode_t 
*); 
 139 static void     devfs_record_event(devfs_event_log_t
, devnode_t
*, uint32_t); 
 140 static int      devfs_init_event_log(devfs_event_log_t
, uint32_t, devfs_vnode_event_t
); 
 141 static void     devfs_release_event_log(devfs_event_log_t
, int); 
 142 static void     devfs_bulk_notify(devfs_event_log_t
); 
 143 static 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
); 
 147 lck_grp_t       
* devfs_lck_grp
; 
 148 lck_grp_attr_t  
* devfs_lck_grp_attr
; 
 149 lck_attr_t      
* devfs_lck_attr
; 
 150 lck_mtx_t         devfs_mutex
; 
 151 lck_mtx_t         devfs_attr_mutex
; 
 153 devdirent_t 
*           dev_root 
= NULL
;        /* root of backing tree */ 
 154 struct devfs_stats      devfs_stats
;            /* hold stats */ 
 156 static ino_t            devfs_unique_fileno 
= 0; 
 158 #ifdef HIDDEN_MOUNTPOINT 
 159 static struct mount 
*devfs_hidden_mount
; 
 160 #endif /* HIDDEN_MOINTPOINT */ 
 162 static int devfs_ready 
= 0; 
 163 static uint32_t devfs_nmountplanes 
= 0; /* The first plane is not used for a mount */ 
 165 #define DEVFS_NOCREATE  FALSE 
 166 #define DEVFS_CREATE    TRUE 
 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 
 174  * DEVFS has a hidden mountpoint that is used as the anchor point 
 175  * for the internal 'blueprint' version of the dev filesystem tree. 
 183         devfs_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 184         devfs_lck_grp 
= lck_grp_alloc_init("devfs_lock", devfs_lck_grp_attr
); 
 186         devfs_lck_attr 
= lck_attr_alloc_init(); 
 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
); 
 192         error 
= dev_add_entry("root", NULL
, DEV_DIR
, NULL
, NULL
, NULL
, &dev_root
); 
 196                 printf("devfs_sinit: dev_add_entry failed "); 
 199 #ifdef HIDDEN_MOUNTPOINT 
 200         MALLOC(devfs_hidden_mount
, struct mount 
*, sizeof(struct mount
), 
 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
); 
 208         mac_mount_label_init(devfs_hidden_mount
); 
 209         mac_mount_label_associate(vfs_context_kernel(), devfs_hidden_mount
); 
 212         /* Initialize the default IO constraints */ 
 213         mp
->mnt_maxreadcnt 
= mp
->mnt_maxwritecnt 
= MAXPHYS
; 
 214         mp
->mnt_segreadcnt 
= mp
->mnt_segwritecnt 
= 32; 
 216         mp
->mnt_realrootvp 
= NULLVP
; 
 217         mp
->mnt_authcache_ttl 
= CACHED_LOOKUP_RIGHT_TTL
; 
 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 */ 
 224         mac_devfs_label_associate_directory("/", strlen("/"), 
 225             dev_root
->de_dnp
, "/"); 
 231 /***********************************************************************\ 
 232 ************************************************************************* 
 233 *       Routines used to find our way to a point in the tree            * 
 234 ************************************************************************* 
 235 \***********************************************************************/ 
 239 /*************************************************************** 
 240 * Search down the linked list off a dir to find "name" 
 241 * return the devnode_t * for that node. 
 243 * called with DEVFS_LOCK held 
 244 ***************************************************************/ 
 246 dev_findname(devnode_t 
* dir
, const char *name
) 
 249         if (dir
->dn_type 
!= DEV_DIR
) { 
 250                 return 0;                     /*XXX*/ /* printf?*/ 
 252         if (name
[0] == '.') { 
 254                         return dir
->dn_typeinfo
.Dir
.myname
; 
 256                 if ((name
[1] == '.') && (name
[2] == 0)) { 
 257                         /* for root, .. == . */ 
 258                         return dir
->dn_typeinfo
.Dir
.parent
->dn_typeinfo
.Dir
.myname
; 
 261         newfp 
= dir
->dn_typeinfo
.Dir
.dirlist
; 
 264                 if (!(strncmp(name
, newfp
->de_name
, sizeof(newfp
->de_name
)))) { 
 267                 newfp 
= newfp
->de_next
; 
 272 /*********************************************************************** 
 273 * Given a starting node (0 for root) and a pathname, return the node 
 274 * for the end item on the path. It MUST BE A DIRECTORY. If the 'DEVFS_CREATE' 
 275 * option is true, then create any missing nodes in the path and create 
 276 * and return the final node as well. 
 277 * This is used to set up a directory, before making nodes in it.. 
 279 * called with DEVFS_LOCK held 
 280 ***********************************************************************/ 
 282 dev_finddir(const char * path
, 
 286     devfs_event_log_t delp
) 
 288         devnode_t 
*     dnp 
= NULL
; 
 292         char            fullpath
[DEVMAXPATHSIZE
]; 
 296         if (!dirnode
) { /* dirnode == NULL means start at root */ 
 297                 dirnode 
= dev_root
->de_dnp
; 
 300         if (dirnode
->dn_type 
!= DEV_DIR
) { 
 304         if (strlen(path
) > (DEVMAXPATHSIZE 
- 1)) { 
 309         strlcpy(fullpath
, path
, DEVMAXPATHSIZE
); 
 313         while (*scan 
== '/') { 
 320                 char                component
[DEVMAXPATHSIZE
]; 
 321                 devdirent_t 
*       dirent_p
; 
 325                         /* we hit the end of the string, we're done */ 
 330                 while (*scan 
!= '/' && *scan
) { 
 334                 strlcpy(component
, start
, (scan 
- start
) + 1); 
 339                 dirent_p 
= dev_findname(dirnode
, component
); 
 341                         dnp 
= dirent_p
->de_dnp
; 
 342                         if (dnp
->dn_type 
!= DEV_DIR
) { 
 351                         error 
= dev_add_entry(component
, dirnode
, 
 352                             DEV_DIR
, NULL
, NULL
, NULL
, &dirent_p
); 
 356                         dnp 
= dirent_p
->de_dnp
; 
 358                         mac_devfs_label_associate_directory( 
 359                                 dirnode
->dn_typeinfo
.Dir
.myname
->de_name
, 
 360                                 strlen(dirnode
->dn_typeinfo
.Dir
.myname
->de_name
), 
 363                         devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, dirent_p
, delp
); 
 365                 dirnode 
= dnp
; /* continue relative to this directory */ 
 371 /*********************************************************************** 
 372 * Add a new NAME element to the devfs 
 373 * If we're creating a root node, then dirname is NULL 
 374 * Basically this creates a new namespace entry for the device node 
 376 * Creates a name node, and links it to the supplied node 
 378 * called with DEVFS_LOCK held 
 379 ***********************************************************************/ 
 381 dev_add_name(const char * name
, devnode_t 
* dirnode
, __unused devdirent_t 
* back
, 
 382     devnode_t 
* dnp
, devdirent_t 
* *dirent_pp
) 
 384         devdirent_t 
*   dirent_p 
= NULL
; 
 386         if (dirnode 
!= NULL
) { 
 387                 if (dirnode
->dn_type 
!= DEV_DIR
) { 
 391                 if (dev_findname(dirnode
, name
)) { 
 396          * make sure the name is legal 
 397          * slightly misleading in the case of NULL 
 399         if (!name 
|| (strlen(name
) > (DEVMAXNAMESIZE 
- 1))) { 
 404          * Allocate and fill out a new directory entry 
 406         MALLOC(dirent_p
, devdirent_t 
*, sizeof(devdirent_t
), 
 407             M_DEVFSNAME
, M_WAITOK
); 
 411         bzero(dirent_p
, sizeof(devdirent_t
)); 
 413         /* inherrit our parent's mount info */ /*XXX*/ 
 414         /* a kludge but.... */ 
 415         if (dirnode 
&& (dnp
->dn_dvm 
== NULL
)) { 
 416                 dnp
->dn_dvm 
= dirnode
->dn_dvm
; 
 417                 /* if(!dnp->dn_dvm) printf("parent had null dvm "); */ 
 421          * Link the two together 
 422          * include the implicit link in the count of links to the devnode.. 
 423          * this stops it from being accidentally freed later. 
 425         dirent_p
->de_dnp 
= dnp
; 
 426         dnp
->dn_links
++;  /* implicit from our own name-node */ 
 429          * Make sure that we can find all the links that reference a node 
 430          * so that we can get them all if we need to zap the node. 
 432         if (dnp
->dn_linklist
) { 
 433                 dirent_p
->de_nextlink 
= dnp
->dn_linklist
; 
 434                 dirent_p
->de_prevlinkp 
= dirent_p
->de_nextlink
->de_prevlinkp
; 
 435                 dirent_p
->de_nextlink
->de_prevlinkp 
= &(dirent_p
->de_nextlink
); 
 436                 *dirent_p
->de_prevlinkp 
= dirent_p
; 
 438                 dirent_p
->de_nextlink 
= dirent_p
; 
 439                 dirent_p
->de_prevlinkp 
= &(dirent_p
->de_nextlink
); 
 441         dnp
->dn_linklist 
= dirent_p
; 
 444          * If the node is a directory, then we need to handle the 
 445          * creation of the .. link. 
 446          * A NULL dirnode indicates a root node, so point to ourself. 
 448         if (dnp
->dn_type 
== DEV_DIR
) { 
 449                 dnp
->dn_typeinfo
.Dir
.myname 
= dirent_p
; 
 451                  * If we are unlinking from an old dir, decrement its links 
 452                  * as we point our '..' elsewhere 
 453                  * Note: it's up to the calling code to remove the 
 454                  * us from the original directory's list 
 456                 if (dnp
->dn_typeinfo
.Dir
.parent
) { 
 457                         dnp
->dn_typeinfo
.Dir
.parent
->dn_links
--; 
 460                         dnp
->dn_typeinfo
.Dir
.parent 
= dirnode
; 
 462                         dnp
->dn_typeinfo
.Dir
.parent 
= dnp
; 
 464                 dnp
->dn_typeinfo
.Dir
.parent
->dn_links
++; /* account for the new '..' */ 
 468          * put the name into the directory entry. 
 470         strlcpy(dirent_p
->de_name
, name
, DEVMAXNAMESIZE
); 
 474          * Check if we are not making a root node.. 
 479                  * Put it on the END of the linked list of directory entries 
 481                 dirent_p
->de_parent 
= dirnode
; /* null for root */ 
 482                 dirent_p
->de_prevp 
= dirnode
->dn_typeinfo
.Dir
.dirlast
; 
 483                 dirent_p
->de_next 
= *(dirent_p
->de_prevp
); /* should be NULL */ 
 485                 *(dirent_p
->de_prevp
) = dirent_p
; 
 486                 dirnode
->dn_typeinfo
.Dir
.dirlast 
= &(dirent_p
->de_next
); 
 487                 dirnode
->dn_typeinfo
.Dir
.entrycount
++; 
 488                 dirnode
->dn_len 
+= strlen(name
) + 8;/*ok, ok?*/ 
 491         *dirent_pp 
= dirent_p
; 
 492         DEVFS_INCR_ENTRIES(); 
 497 /*********************************************************************** 
 498 * Add a new element to the devfs plane. 
 500 * Creates a new dev_node to go with it if the prototype should not be 
 501 * reused. (Is a DIR, or we select SPLIT_DEVS at compile time) 
 502 * typeinfo gives us info to make our node if we don't have a prototype. 
 503 * If typeinfo is null and proto exists, then the typeinfo field of 
 504 * the proto is used intead in the DEVFS_CREATE case. 
 505 * note the 'links' count is 0 (except if a dir) 
 506 * but it is only cleared on a transition 
 507 * so this is ok till we link it to something 
 508 * Even in SPLIT_DEVS mode, 
 509 * if the node already exists on the wanted plane, just return it 
 511 * called with DEVFS_LOCK held 
 512 ***********************************************************************/ 
 514 dev_add_node(int entrytype
, devnode_type_t 
* typeinfo
, devnode_t 
* proto
, 
 515     devnode_t 
* *dn_pp
, struct devfsmount 
*dvm
) 
 517         devnode_t 
*     dnp 
= NULL
; 
 519 #if defined SPLIT_DEVS 
 521          * If we have a prototype, then check if there is already a sibling 
 522          * on the mount plane we are looking at, if so, just return it. 
 525                 dnp 
= proto
->dn_nextsibling
; 
 526                 while (dnp 
!= proto
) { 
 527                         if (dnp
->dn_dvm 
== dvm
) { 
 531                         dnp 
= dnp
->dn_nextsibling
; 
 533                 if (typeinfo 
== NULL
) { 
 534                         typeinfo 
= &(proto
->dn_typeinfo
); 
 537 #else   /* SPLIT_DEVS */ 
 539                 switch (proto
->type
) { 
 546 #endif  /* SPLIT_DEVS */ 
 547         MALLOC(dnp
, devnode_t 
*, sizeof(devnode_t
), M_DEVFSNODE
, M_WAITOK
); 
 553          * If we have a proto, that means that we are duplicating some 
 554          * other device, which can only happen if we are not at the back plane 
 557                 bcopy(proto
, dnp
, sizeof(devnode_t
)); 
 559                 dnp
->dn_linklist 
= NULL
; 
 562                 /* add to END of siblings list */ 
 563                 dnp
->dn_prevsiblingp 
= proto
->dn_prevsiblingp
; 
 564                 *(dnp
->dn_prevsiblingp
) = dnp
; 
 565                 dnp
->dn_nextsibling 
= proto
; 
 566                 proto
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 568                 mac_devfs_label_init(dnp
); 
 569                 mac_devfs_label_copy(proto
->dn_label
, dnp
->dn_label
); 
 575                  * We have no prototype, so start off with a clean slate 
 578                 bzero(dnp
, sizeof(devnode_t
)); 
 579                 dnp
->dn_type 
= entrytype
; 
 580                 dnp
->dn_nextsibling 
= dnp
; 
 581                 dnp
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 582                 dnp
->dn_atime
.tv_sec 
= tv
.tv_sec
; 
 583                 dnp
->dn_mtime
.tv_sec 
= tv
.tv_sec
; 
 584                 dnp
->dn_ctime
.tv_sec 
= tv
.tv_sec
; 
 586                 mac_devfs_label_init(dnp
); 
 590         dnp
->dn_refcount 
= 0; 
 591         dnp
->dn_ino 
= devfs_unique_fileno
; 
 592         devfs_unique_fileno
++; 
 595          * fill out the dev node according to type 
 600                  * As it's a directory, make sure 
 601                  * it has a null entries list 
 603                 dnp
->dn_typeinfo
.Dir
.dirlast 
= &(dnp
->dn_typeinfo
.Dir
.dirlist
); 
 604                 dnp
->dn_typeinfo
.Dir
.dirlist 
= (devdirent_t 
*)0; 
 605                 dnp
->dn_typeinfo
.Dir
.entrycount 
= 0; 
 606                 /*  until we know better, it has a null parent pointer*/ 
 607                 dnp
->dn_typeinfo
.Dir
.parent 
= NULL
; 
 608                 dnp
->dn_links
++; /* for .*/ 
 609                 dnp
->dn_typeinfo
.Dir
.myname 
= NULL
; 
 611                  * make sure that the ops associated with it are the ops 
 612                  * that we use (by default) for directories 
 614                 dnp
->dn_ops 
= &devfs_vnodeop_p
; 
 615                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 619                  * As it's a symlink allocate and store the link info 
 620                  * Symlinks should only ever be created by the user, 
 621                  * so they are not on the back plane and should not be 
 622                  * propogated forward.. a bit like directories in that way.. 
 623                  * A symlink only exists on one plane and has its own 
 624                  * node.. therefore we might be on any random plane. 
 626                 MALLOC(dnp
->dn_typeinfo
.Slnk
.name
, char *, 
 627                     typeinfo
->Slnk
.namelen 
+ 1, 
 628                     M_DEVFSNODE
, M_WAITOK
); 
 629                 if (!dnp
->dn_typeinfo
.Slnk
.name
) { 
 630                         FREE(dnp
, M_DEVFSNODE
); 
 633                 strlcpy(dnp
->dn_typeinfo
.Slnk
.name
, typeinfo
->Slnk
.name
, 
 634                     typeinfo
->Slnk
.namelen 
+ 1); 
 635                 dnp
->dn_typeinfo
.Slnk
.namelen 
= typeinfo
->Slnk
.namelen
; 
 636                 DEVFS_INCR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen 
+ 1); 
 637                 dnp
->dn_ops 
= &devfs_vnodeop_p
; 
 638                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 643                  * Make sure it has DEVICE type ops 
 644                  * and device specific fields are correct 
 646                 dnp
->dn_ops 
= &devfs_spec_vnodeop_p
; 
 647                 dnp
->dn_typeinfo
.dev 
= typeinfo
->dev
; 
 651         /* /dev/fd is special */ 
 653                 dnp
->dn_ops 
= &devfs_devfd_vnodeop_p
; 
 654                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 668 /*********************************************************************** 
 669  * called with DEVFS_LOCK held 
 670  **********************************************************************/ 
 672 devnode_free(devnode_t 
* dnp
) 
 675         mac_devfs_label_destroy(dnp
); 
 677         if (dnp
->dn_type 
== DEV_SLNK
) { 
 678                 DEVFS_DECR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen 
+ 1); 
 679                 FREE(dnp
->dn_typeinfo
.Slnk
.name
, M_DEVFSNODE
); 
 682         FREE(dnp
, M_DEVFSNODE
); 
 686 /*********************************************************************** 
 687  * called with DEVFS_LOCK held 
 688  **********************************************************************/ 
 690 devfs_dn_free(devnode_t 
* dnp
) 
 692         if (--dnp
->dn_links 
<= 0) { /* can be -1 for initial free, on error */ 
 693                 /*probably need to do other cleanups XXX */ 
 694                 if (dnp
->dn_nextsibling 
!= dnp
) { 
 695                         devnode_t 
* *   prevp 
= dnp
->dn_prevsiblingp
; 
 696                         *prevp 
= dnp
->dn_nextsibling
; 
 697                         dnp
->dn_nextsibling
->dn_prevsiblingp 
= prevp
; 
 700                 /* Can only free if there are no references; otherwise, wait for last vnode to be reclaimed */ 
 701                 if (dnp
->dn_refcount 
== 0) { 
 704                         dnp
->dn_lflags 
|= DN_DELETE
; 
 709 /***********************************************************************\ 
 710 *       Front Node Operations                                           * 
 711 *       Add or delete a chain of front nodes                            * 
 712 \***********************************************************************/ 
 715 /*********************************************************************** 
 716 * Given a directory backing node, and a child backing node, add the 
 717 * appropriate front nodes to the front nodes of the directory to 
 718 * represent the child node to the user 
 720 * on failure, front nodes will either be correct or not exist for each 
 721 * front dir, however dirs completed will not be stripped of completed 
 722 * frontnodes on failure of a later frontnode 
 724 * This allows a new node to be propogated through all mounted planes 
 726 * called with DEVFS_LOCK held 
 727 ***********************************************************************/ 
 729 devfs_propogate(devdirent_t 
* parent
, devdirent_t 
* child
, devfs_event_log_t delp
) 
 732         devdirent_t 
* newnmp
; 
 733         devnode_t 
*     dnp 
= child
->de_dnp
; 
 734         devnode_t 
*     pdnp 
= parent
->de_dnp
; 
 735         devnode_t 
*     adnp 
= parent
->de_dnp
; 
 736         int type 
= child
->de_dnp
->dn_type
; 
 739         events 
= (dnp
->dn_type 
== DEV_DIR 
? VNODE_EVENT_DIR_CREATED 
: VNODE_EVENT_FILE_CREATED
); 
 741                 devfs_record_event(delp
, pdnp
, events
); 
 744         /*********************************************** 
 745         * Find the other instances of the parent node 
 746         ***********************************************/ 
 747         for (adnp 
= pdnp
->dn_nextsibling
; 
 749             adnp 
= adnp
->dn_nextsibling
) { 
 751                  * Make the node, using the original as a prototype) 
 752                  * if the node already exists on that plane it won't be 
 755                 if ((error 
= dev_add_entry(child
->de_name
, adnp
, type
, 
 756                     NULL
, dnp
, adnp
->dn_dvm
, 
 758                         printf("duplicating %s failed\n", child
->de_name
); 
 761                                 devfs_record_event(delp
, adnp
, events
); 
 764                                  * Slightly subtle.  We're guaranteed that there will 
 765                                  * only be a vnode hooked into this devnode if we're creating 
 766                                  * a new link to an existing node; otherwise, the devnode is new 
 767                                  * and no one can have looked it up yet. If we're making a link, 
 768                                  * then the buffer is large enough for two nodes in each 
 769                                  * plane; otherwise, there's no vnode and this call will 
 772                                 devfs_record_event(delp
, newnmp
->de_dnp
, VNODE_EVENT_LINK
); 
 776         return 0;       /* for now always succeed */ 
 780 remove_notify_count(devnode_t 
*dnp
) 
 782         uint32_t notify_count 
= 0; 
 786          * Could need to notify for one removed node on each mount and 
 787          * one parent for each such node. 
 789         notify_count 
= devfs_nmountplanes
; 
 790         notify_count 
+= dnp
->dn_links
; 
 791         for (dnp2 
= dnp
->dn_nextsibling
; dnp2 
!= dnp
; dnp2 
= dnp2
->dn_nextsibling
) { 
 792                 notify_count 
+= dnp2
->dn_links
; 
 798 /*********************************************************************** 
 799 * remove all instances of this devicename [for backing nodes..] 
 800 * note.. if there is another link to the node (non dir nodes only) 
 801 * then the devfs_node will still exist as the ref count will be non-0 
 802 * removing a directory node will remove all sup-nodes on all planes (ZAP) 
 804 * Used by device drivers to remove nodes that are no longer relevant 
 805 * The argument is the 'cookie' they were given when they created the node 
 806 * this function is exported.. see devfs.h 
 807 ***********************************************************************/ 
 809 devfs_remove(void *dirent_p
) 
 811         devnode_t 
* dnp 
= ((devdirent_t 
*)dirent_p
)->de_dnp
; 
 814         struct devfs_event_log event_log
; 
 815         uint32_t    log_count 
= 0; 
 818         struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
]; 
 823                 printf("devfs_remove: not ready for devices!\n"); 
 827         log_count 
= remove_notify_count(dnp
); 
 829         if (log_count 
> NUM_STACK_ENTRIES
) { 
 833                 if (devfs_init_event_log(&event_log
, log_count
, NULL
) == 0) { 
 839                 new_count 
= remove_notify_count(dnp
); 
 840                 if (need_free 
&& (new_count 
> log_count
)) { 
 841                         devfs_release_event_log(&event_log
, 1); 
 844                         log_count 
= log_count 
* 2; 
 848                 if (devfs_init_event_log(&event_log
, NUM_STACK_ENTRIES
, &stackbuf
[0]) == 0) { 
 853         /* This file has been deleted */ 
 854         if (do_notify 
!= 0) { 
 855                 devfs_record_event(&event_log
, dnp
, VNODE_EVENT_DELETE
); 
 858         /* keep removing the next sibling till only we exist. */ 
 859         while ((dnp2 
= dnp
->dn_nextsibling
) != dnp
) { 
 861                  * Keep removing the next front node till no more exist 
 863                 dnp
->dn_nextsibling 
= dnp2
->dn_nextsibling
; 
 864                 dnp
->dn_nextsibling
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 865                 dnp2
->dn_nextsibling 
= dnp2
; 
 866                 dnp2
->dn_prevsiblingp 
= &(dnp2
->dn_nextsibling
); 
 868                 /* This file has been deleted in this plane */ 
 869                 if (do_notify 
!= 0) { 
 870                         devfs_record_event(&event_log
, dnp2
, VNODE_EVENT_DELETE
); 
 873                 if (dnp2
->dn_linklist
) { 
 875                                 lastlink 
= (1 == dnp2
->dn_links
); 
 876                                 /* Each parent of a link to this file has lost a child in this plane */ 
 877                                 if (do_notify 
!= 0) { 
 878                                         devfs_record_event(&event_log
, dnp2
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
); 
 880                                 dev_free_name(dnp2
->dn_linklist
); 
 886          * then free the main node 
 887          * If we are not running in SPLIT_DEVS mode, then 
 888          * THIS is what gets rid of the propogated nodes. 
 890         if (dnp
->dn_linklist
) { 
 892                         lastlink 
= (1 == dnp
->dn_links
); 
 893                         /* Each parent of a link to this file has lost a child */ 
 894                         if (do_notify 
!= 0) { 
 895                                 devfs_record_event(&event_log
, dnp
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
); 
 897                         dev_free_name(dnp
->dn_linklist
); 
 902         if (do_notify 
!= 0) { 
 903                 devfs_bulk_notify(&event_log
); 
 904                 devfs_release_event_log(&event_log
, need_free
); 
 912 /*************************************************************** 
 913  * duplicate the backing tree into a tree of nodes hung off the 
 914  * mount point given as the argument. Do this by 
 915  * calling dev_dup_entry which recurses all the way 
 918  * called with DEVFS_LOCK held 
 919  **************************************************************/ 
 921 dev_dup_plane(struct devfsmount 
*devfs_mp_p
) 
 926         if ((error 
= dev_dup_entry(NULL
, dev_root
, &new, devfs_mp_p
))) { 
 929         devfs_mp_p
->plane_root 
= new; 
 930         devfs_nmountplanes
++; 
 936 /*************************************************************** 
 939 * called with DEVFS_LOCK held 
 940 ***************************************************************/ 
 942 devfs_free_plane(struct devfsmount 
*devfs_mp_p
) 
 944         devdirent_t 
* dirent_p
; 
 946         dirent_p 
= devfs_mp_p
->plane_root
; 
 948                 dev_free_hier(dirent_p
); 
 949                 dev_free_name(dirent_p
); 
 951         devfs_mp_p
->plane_root 
= NULL
; 
 952         devfs_nmountplanes
--; 
 954         if (devfs_nmountplanes 
> (devfs_nmountplanes 
+ 1)) { 
 955                 panic("plane count wrapped around.\n"); 
 960 /*************************************************************** 
 961 * Create and link in a new front element.. 
 962 * Parent can be 0 for a root node 
 963 * Not presently usable to make a symlink XXX 
 964 * (Ok, symlinks don't propogate) 
 965 * recursively will create subnodes corresponding to equivalent 
 966 * child nodes in the base level 
 968 * called with DEVFS_LOCK held 
 969 ***************************************************************/ 
 971 dev_dup_entry(devnode_t 
* parent
, devdirent_t 
* back
, devdirent_t 
* *dnm_pp
, 
 972     struct devfsmount 
*dvm
) 
 974         devdirent_t 
*   entry_p 
= NULL
; 
 975         devdirent_t 
*   newback
; 
 976         devdirent_t 
*   newfront
; 
 978         devnode_t 
*     dnp 
= back
->de_dnp
; 
 979         int type 
= dnp
->dn_type
; 
 982          * go get the node made (if we need to) 
 983          * use the back one as a prototype 
 985         error 
= dev_add_entry(back
->de_name
, parent
, type
, NULL
, dnp
, 
 986             parent
?parent
->dn_dvm
:dvm
, &entry_p
); 
 987         if (!error 
&& (entry_p 
== NULL
)) { 
 988                 error 
= ENOMEM
; /* Really can't happen, but make static analyzer happy */ 
 991                 printf("duplicating %s failed\n", back
->de_name
); 
 996          * If we have just made the root, then insert the pointer to the 
1000                 entry_p
->de_dnp
->dn_dvm 
= dvm
; 
1004          * If it is a directory, then recurse down all the other 
1005          * subnodes in it.... 
1006          * note that this time we don't pass on the mount info.. 
1008         if (type 
== DEV_DIR
) { 
1009                 for (newback 
= back
->de_dnp
->dn_typeinfo
.Dir
.dirlist
; 
1010                     newback
; newback 
= newback
->de_next
) { 
1011                         if ((error 
= dev_dup_entry(entry_p
->de_dnp
, 
1012                             newback
, &newfront
, NULL
)) != 0) { 
1013                                 break; /* back out with an error */ 
1023 /*************************************************************** 
1025 * remember that if there are other names pointing to the 
1026 * dev_node then it may not get freed yet 
1027 * can handle if there is no dnp 
1029 * called with DEVFS_LOCK held 
1030 ***************************************************************/ 
1033 dev_free_name(devdirent_t 
* dirent_p
) 
1035         devnode_t 
*     parent 
= dirent_p
->de_parent
; 
1036         devnode_t 
*     dnp 
= dirent_p
->de_dnp
; 
1039                 if (dnp
->dn_type 
== DEV_DIR
) { 
1042                         if (dnp
->dn_typeinfo
.Dir
.dirlist
) { 
1045                         p 
= dnp
->dn_typeinfo
.Dir
.parent
; 
1046                         devfs_dn_free(dnp
);     /* account for '.' */ 
1047                         devfs_dn_free(p
);       /* '..' */ 
1050                  * unlink us from the list of links for this node 
1051                  * If we are the only link, it's easy! 
1052                  * if we are a DIR of course there should not be any 
1055                 if (dirent_p
->de_nextlink 
== dirent_p
) { 
1056                         dnp
->dn_linklist 
= NULL
; 
1058                         if (dnp
->dn_linklist 
== dirent_p
) { 
1059                                 dnp
->dn_linklist 
= dirent_p
->de_nextlink
; 
1065         dirent_p
->de_nextlink
->de_prevlinkp 
= dirent_p
->de_prevlinkp
; 
1066         *(dirent_p
->de_prevlinkp
) = dirent_p
->de_nextlink
; 
1069          * unlink ourselves from the directory on this plane 
1071         if (parent
) { /* if not fs root */ 
1072                 if ((*dirent_p
->de_prevp 
= dirent_p
->de_next
)) {/* yes, assign */ 
1073                         dirent_p
->de_next
->de_prevp 
= dirent_p
->de_prevp
; 
1075                         parent
->dn_typeinfo
.Dir
.dirlast
 
1076                                 = dirent_p
->de_prevp
; 
1078                 parent
->dn_typeinfo
.Dir
.entrycount
--; 
1079                 parent
->dn_len 
-= strlen(dirent_p
->de_name
) + 8; 
1082         DEVFS_DECR_ENTRIES(); 
1083         FREE(dirent_p
, M_DEVFSNAME
); 
1088 /*************************************************************** 
1089 * Free a hierarchy starting at a directory node name 
1090 * remember that if there are other names pointing to the 
1091 * dev_node then it may not get freed yet 
1092 * can handle if there is no dnp 
1093 * leave the node itself allocated. 
1095 * called with DEVFS_LOCK held 
1096 ***************************************************************/ 
1099 dev_free_hier(devdirent_t 
* dirent_p
) 
1101         devnode_t 
*     dnp 
= dirent_p
->de_dnp
; 
1104                 if (dnp
->dn_type 
== DEV_DIR
) { 
1105                         while (dnp
->dn_typeinfo
.Dir
.dirlist
) { 
1106                                 dev_free_hier(dnp
->dn_typeinfo
.Dir
.dirlist
); 
1107                                 dev_free_name(dnp
->dn_typeinfo
.Dir
.dirlist
); 
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 
1118  * called with DEVFS_LOCK held 
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  ****************************************************************/ 
1125 devfs_dntovn(devnode_t 
* dnp
, struct vnode 
**vn_pp
, __unused 
struct proc 
* p
) 
1129         struct vnode_fsparam vfsp
; 
1130         enum vtype vtype 
= 0; 
1133         int n_minor 
= DEVFS_CLONE_ALLOC
; /* new minor number for clone device */ 
1136          * We should never come in and find that our devnode has been marked for delete. 
1137          * The lookup should have held the lock from entry until now; it should not have 
1138          * been able to find a removed entry. Any other pathway would have just created 
1139          * the devnode and come here without dropping the devfs lock, so no one would 
1140          * have a chance to delete. 
1142         if (dnp
->dn_lflags 
& DN_DELETE
) { 
1143                 panic("devfs_dntovn: DN_DELETE set on a devnode upon entry."); 
1146         devfs_ref_node(dnp
); 
1152         if (vn_p
) { /* already has a vnode */ 
1155                 vid 
= vnode_vid(vn_p
); 
1160                  * We want to use the drainok variant of vnode_getwithvid 
1161                  * because we _don't_ want to get an iocount if the vnode is 
1162                  * is blocked in vnode_drain as it can cause infinite 
1163                  * loops in vn_open_auth. While in use vnodes are typically 
1164                  * only reclaimed on forced unmounts, In use devfs tty vnodes 
1165                  * can  be quite frequently reclaimed by revoke(2) or by the 
1166                  * exit of a controlling process. 
1168                 error 
= vnode_getwithvid_drainok(vn_p
, vid
); 
1172                 if (dnp
->dn_lflags 
& DN_DELETE
) { 
1174                          * our BUSY node got marked for 
1175                          * deletion while the DEVFS lock 
1180                                  * vnode_getwithvid returned a valid ref 
1181                                  * which we need to drop 
1187                          * This entry is no longer in the namespace.  This is only 
1188                          * possible for lookup: no other path would not find an existing 
1189                          * vnode.  Therefore, ENOENT is a valid result. 
1192                 } else if (error 
== ENODEV
) { 
1194                          * The Filesystem is getting unmounted. 
1197                 } else if (error 
&& (nretries 
< DEV_MAX_VNODE_RETRY
)) { 
1199                          * If we got an error from vnode_getwithvid, it means 
1200                          * we raced with a recycle and lost i.e. we asked for 
1201                          * an iocount only after vnode_drain had been entered 
1202                          * for the vnode and returned with an error only after 
1203                          * devfs_reclaim was called on the vnode.  devfs_reclaim 
1204                          * sets dn_vn to NULL but while we were waiting to 
1205                          * reacquire DEVFS_LOCK, another vnode might have gotten 
1206                          * associated with the dnp. In either case, we need to 
1207                          * retry otherwise we will end up returning an ENOENT 
1208                          * for this lookup but the next lookup will  succeed 
1209                          * because it creates a new vnode (or a racing  lookup 
1210                          * created a new vnode already). 
1224          * If we get here, then we've beaten any deletes; 
1225          * if someone sets DN_DELETE during a subsequent drop 
1226          * of the devfs lock, we'll still vend a vnode. 
1229         if (dnp
->dn_lflags 
& DN_CREATE
) { 
1230                 dnp
->dn_lflags 
|= DN_CREATEWAIT
; 
1231                 msleep(&dnp
->dn_lflags
, &devfs_mutex
, PRIBIO
, 0, 0); 
1235         dnp
->dn_lflags 
|= DN_CREATE
; 
1237         switch (dnp
->dn_type
) { 
1242                 if (dnp
->dn_typeinfo
.Dir
.parent 
== dnp
) { 
1249                 vtype 
= (dnp
->dn_type 
== DEV_BDEV
) ? VBLK 
: VCHR
; 
1257         vfsp
.vnfs_mp 
= dnp
->dn_dvm
->mount
; 
1258         vfsp
.vnfs_vtype 
= vtype
; 
1259         vfsp
.vnfs_str 
= "devfs"; 
1261         vfsp
.vnfs_fsnode 
= dnp
; 
1263         vfsp
.vnfs_vops 
= *(dnp
->dn_ops
); 
1265         if (vtype 
== VBLK 
|| vtype 
== VCHR
) { 
1267                  * Ask the clone minor number function for a new minor number 
1268                  * to use for the next device instance.  If an administative 
1269                  * limit has been reached, this function will return -1. 
1271                 if (dnp
->dn_clone 
!= NULL
) { 
1272                         int     n_major 
= major(dnp
->dn_typeinfo
.dev
); 
1274                         n_minor 
= (*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_ALLOC
); 
1275                         if (n_minor 
== -1) { 
1280                         vfsp
.vnfs_rdev 
= makedev(n_major
, n_minor
);; 
1282                         vfsp
.vnfs_rdev 
= dnp
->dn_typeinfo
.dev
; 
1287         vfsp
.vnfs_filesize 
= 0; 
1288         vfsp
.vnfs_flags 
= VNFS_NOCACHE 
| VNFS_CANTCACHE
; 
1289         /* Tag system files */ 
1290         vfsp
.vnfs_marksystem 
= 0; 
1291         vfsp
.vnfs_markroot 
= markroot
; 
1295         error 
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &vn_p
); 
1297         /* Do this before grabbing the lock */ 
1299                 vnode_setneedinactive(vn_p
); 
1305                 vnode_settag(vn_p
, VT_DEVFS
); 
1307                 if ((dnp
->dn_clone 
!= NULL
) && (dnp
->dn_vn 
!= NULLVP
)) { 
1308                         panic("devfs_dntovn: cloning device with a vnode?\n"); 
1314                  * Another vnode that has this devnode as its v_data. 
1315                  * This reference, unlike the one taken at the start 
1316                  * of the function, persists until a VNOP_RECLAIM 
1317                  * comes through for this vnode. 
1319                 devfs_ref_node(dnp
); 
1322                  * A cloned vnode is not hooked into the devnode; every lookup 
1325                 if (dnp
->dn_clone 
== NULL
) { 
1328         } else if (n_minor 
!= DEVFS_CLONE_ALLOC
) { 
1330                  * If we failed the create, we need to release the cloned minor 
1331                  * back to the free list.  In general, this is only useful if 
1332                  * the clone function results in a state change in the cloned 
1333                  * device for which the minor number was obtained.  If we get 
1334                  * past this point withouth falling into this case, it's 
1335                  * assumed that any state to be released will be released when 
1336                  * the vnode is dropped, instead. 
1338                 (void)(*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_FREE
); 
1341         dnp
->dn_lflags 
&= ~DN_CREATE
; 
1342         if (dnp
->dn_lflags 
& DN_CREATEWAIT
) { 
1343                 dnp
->dn_lflags 
&= ~DN_CREATEWAIT
; 
1344                 wakeup(&dnp
->dn_lflags
); 
1349          * Release the reference we took to prevent deletion while we weren't holding the lock. 
1350          * If not returning success, then dropping this reference could delete the devnode; 
1351          * no one should access a devnode after a call to devfs_dntovn fails. 
1353         devfs_rele_node(dnp
); 
1359  * Increment refcount on a devnode; prevents free of the node 
1360  * while the devfs lock is not held. 
1363 devfs_ref_node(devnode_t 
*dnp
) 
1369  * Release a reference on a devnode.  If the devnode is marked for 
1370  * free and the refcount is dropped to zero, do the free. 
1373 devfs_rele_node(devnode_t 
*dnp
) 
1376         if (dnp
->dn_refcount 
< 0) { 
1377                 panic("devfs_rele_node: devnode with a negative refcount!\n"); 
1378         } else if ((dnp
->dn_refcount 
== 0) && (dnp
->dn_lflags 
& DN_DELETE
)) { 
1383 /*********************************************************************** 
1384 * add a whole device, with no prototype.. make name element and node 
1385 * Used for adding the original device entries 
1387 * called with DEVFS_LOCK held 
1388 ***********************************************************************/ 
1390 dev_add_entry(const char *name
, devnode_t 
* parent
, int type
, devnode_type_t 
* typeinfo
, 
1391     devnode_t 
* proto
, struct devfsmount 
*dvm
, devdirent_t 
* *nm_pp
) 
1396         if ((error 
= dev_add_node(type
, typeinfo
, proto
, &dnp
, 
1397             (parent
?parent
->dn_dvm
:dvm
))) != 0) { 
1398                 printf("devfs: %s: base node allocation failed (Errno=%d)\n", 
1402         if ((error 
= dev_add_name(name
, parent
, NULL
, dnp
, nm_pp
)) != 0) { 
1403                 devfs_dn_free(dnp
); /* 1->0 for dir, 0->(-1) for other */ 
1404                 printf("devfs: %s: name slot allocation failed (Errno=%d)\n", 
1411 devfs_bulk_notify(devfs_event_log_t delp
) 
1414         for (i 
= 0; i 
< delp
->del_used
; i
++) { 
1415                 devfs_vnode_event_t dvep 
= &delp
->del_entries
[i
]; 
1416                 if (vnode_getwithvid(dvep
->dve_vp
, dvep
->dve_vid
) == 0) { 
1417                         vnode_notify(dvep
->dve_vp
, dvep
->dve_events
, NULL
); 
1418                         vnode_put(dvep
->dve_vp
); 
1424 devfs_record_event(devfs_event_log_t delp
, devnode_t 
*dnp
, uint32_t events
) 
1426         if (delp
->del_used 
>= delp
->del_max
) { 
1427                 panic("devfs event log overflowed.\n"); 
1430         /* Can only notify for nodes that have an associated vnode */ 
1431         if (dnp
->dn_vn 
!= NULLVP 
&& vnode_ismonitored(dnp
->dn_vn
)) { 
1432                 devfs_vnode_event_t dvep 
= &delp
->del_entries
[delp
->del_used
]; 
1433                 dvep
->dve_vp 
= dnp
->dn_vn
; 
1434                 dvep
->dve_vid 
= vnode_vid(dnp
->dn_vn
); 
1435                 dvep
->dve_events 
= events
; 
1441 devfs_init_event_log(devfs_event_log_t delp
, uint32_t count
, devfs_vnode_event_t buf
) 
1443         devfs_vnode_event_t dvearr
; 
1446                 MALLOC(dvearr
, devfs_vnode_event_t
, count 
* sizeof(struct devfs_vnode_event
), M_TEMP
, M_WAITOK 
| M_ZERO
); 
1447                 if (dvearr 
== NULL
) { 
1454         delp
->del_max 
= count
; 
1456         delp
->del_entries 
= dvearr
; 
1461 devfs_release_event_log(devfs_event_log_t delp
, int need_free
) 
1463         if (delp
->del_entries 
== NULL
) { 
1464                 panic("Free of devfs notify info that has not been intialized.\n"); 
1468                 FREE(delp
->del_entries
, M_TEMP
); 
1471         delp
->del_entries 
= NULL
; 
1475  * Function: devfs_make_node 
1478  *   Create a device node with the given pathname in the devfs namespace. 
1481  *   dev        - the dev_t value to associate 
1482  *   chrblk     - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 
1483  *   uid, gid   - ownership 
1484  *   perms      - permissions 
1485  *   clone      - minor number cloning function 
1486  *   fmt, ...   - path format string with printf args to format the path name 
1488  *   A handle to a device node if successful, NULL otherwise. 
1491 devfs_make_node_clone(dev_t dev
, int chrblk
, uid_t uid
, 
1492     gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
), 
1493     const char *fmt
, ...) 
1495         devdirent_t 
*   new_dev 
= NULL
; 
1511         new_dev 
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, clone
, fmt
, ap
); 
1519  * Function: devfs_make_node 
1522  *   Create a device node with the given pathname in the devfs namespace. 
1525  *   dev        - the dev_t value to associate 
1526  *   chrblk     - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 
1527  *   uid, gid   - ownership 
1528  *   perms      - permissions 
1529  *   fmt, ...   - path format string with printf args to format the path name 
1531  *   A handle to a device node if successful, NULL otherwise. 
1534 devfs_make_node(dev_t dev
, int chrblk
, uid_t uid
, 
1535     gid_t gid
, int perms
, const char *fmt
, ...) 
1537         devdirent_t 
*   new_dev 
= NULL
; 
1541         if (chrblk 
!= DEVFS_CHAR 
&& chrblk 
!= DEVFS_BLOCK
) { 
1545         type 
= (chrblk 
== DEVFS_BLOCK 
? DEV_BDEV 
: DEV_CDEV
); 
1548         new_dev 
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, NULL
, fmt
, ap
); 
1555 static devdirent_t 
* 
1556 devfs_make_node_internal(dev_t dev
, devfstype_t type
, uid_t uid
, 
1557     gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
), const char *fmt
, va_list ap
) 
1559         devdirent_t 
*   new_dev 
= NULL
; 
1561         devnode_type_t  typeinfo
; 
1563         char            *name
, buf
[256]; /* XXX */ 
1566         char buff
[sizeof(buf
)]; 
1570         struct devfs_event_log event_log
; 
1571         struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
]; 
1574         vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1577         bcopy(buf
, buff
, sizeof(buff
)); 
1578         buff
[sizeof(buff
) - 1] = 0; 
1582         for (i 
= strlen(buf
); i 
> 0; i
--) { 
1583                 if (buf
[i
] == '/') { 
1598         log_count 
= devfs_nmountplanes
; 
1599         if (log_count 
> NUM_STACK_ENTRIES
) { 
1602                 if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) { 
1607                 log_count 
= NUM_STACK_ENTRIES
; 
1608                 if (devfs_init_event_log(&event_log
, log_count
, &stackbuf
[0]) != 0) { 
1614         if (log_count 
< devfs_nmountplanes
) { 
1616                 devfs_release_event_log(&event_log
, need_free
); 
1617                 log_count 
= log_count 
* 2; 
1622                 printf("devfs_make_node: not ready for devices!\n"); 
1626         /* find/create directory path ie. mkdir -p */ 
1627         if (dev_finddir(path
, NULL
, DEVFS_CREATE
, &dnp
, &event_log
) == 0) { 
1629                 if (dev_add_entry(name
, dnp
, type
, &typeinfo
, NULL
, NULL
, &new_dev
) == 0) { 
1630                         new_dev
->de_dnp
->dn_gid 
= gid
; 
1631                         new_dev
->de_dnp
->dn_uid 
= uid
; 
1632                         new_dev
->de_dnp
->dn_mode 
|= perms
; 
1633                         new_dev
->de_dnp
->dn_clone 
= clone
; 
1635                         mac_devfs_label_associate_device(dev
, new_dev
->de_dnp
, buff
); 
1637                         devfs_propogate(dnp
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
); 
1644         devfs_bulk_notify(&event_log
); 
1645         devfs_release_event_log(&event_log
, need_free
); 
1650  * Function: devfs_make_link 
1653  *   Create a link to a previously created device node. 
1656  *   0 if successful, -1 if failed 
1659 devfs_make_link(void *original
, char *fmt
, ...) 
1661         devdirent_t 
*   new_dev 
= NULL
; 
1662         devdirent_t 
*   orig 
= (devdirent_t 
*) original
; 
1663         devnode_t 
*     dirnode
;        /* devnode for parent directory */ 
1664         struct devfs_event_log event_log
; 
1668         char *p
, buf
[256]; /* XXX */ 
1675                 printf("devfs_make_link: not ready for devices!\n"); 
1681         vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1686         for (i 
= strlen(buf
); i 
> 0; i
--) { 
1687                 if (buf
[i
] == '/') { 
1695          * One slot for each directory, one for each devnode 
1696          * whose link count changes 
1698         log_count 
= devfs_nmountplanes 
* 2; 
1700         if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) { 
1701                 /* No lock held, no allocations done, can just return */ 
1707         if (log_count 
< devfs_nmountplanes
) { 
1709                 devfs_release_event_log(&event_log
, 1); 
1710                 log_count 
= log_count 
* 2; 
1717                 if (dev_finddir(buf
, NULL
, DEVFS_CREATE
, &dirnode
, &event_log
) 
1718                     || dev_add_name(p
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) { 
1722                 if (dev_finddir("", NULL
, DEVFS_CREATE
, &dirnode
, &event_log
) 
1723                     || dev_add_name(buf
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) { 
1727         devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
); 
1730         devfs_bulk_notify(&event_log
); 
1731         devfs_release_event_log(&event_log
, 1); 
1733         return (new_dev 
!= NULL
) ? 0 : -1;