2  * Copyright (c) 2000-2007 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
; 
 152 devdirent_t 
*           dev_root 
= NULL
;        /* root of backing tree */ 
 153 struct devfs_stats      devfs_stats
;            /* hold stats */ 
 155 static ino_t            devfs_unique_fileno 
= 0; 
 157 #ifdef HIDDEN_MOUNTPOINT 
 158 static struct mount 
*devfs_hidden_mount
; 
 159 #endif /* HIDDEN_MOINTPOINT */ 
 161 static int devfs_ready 
= 0; 
 162 static uint32_t devfs_nmountplanes 
= 0; /* The first plane is not used for a mount */ 
 164 #define DEVFS_NOCREATE  FALSE 
 165 #define DEVFS_CREATE    TRUE 
 168  * Set up the root directory node in the backing plane 
 169  * This is happenning before the vfs system has been 
 170  * set up yet, so be careful about what we reference.. 
 171  * Notice that the ops are by indirection.. as they haven't 
 173  * DEVFS has a hidden mountpoint that is used as the anchor point 
 174  * for the internal 'blueprint' version of the dev filesystem tree. 
 182     devfs_lck_grp_attr 
= lck_grp_attr_alloc_init(); 
 183         devfs_lck_grp 
= lck_grp_alloc_init("devfs_lock", devfs_lck_grp_attr
); 
 185         devfs_lck_attr 
= lck_attr_alloc_init(); 
 187         lck_mtx_init(&devfs_mutex
, devfs_lck_grp
, devfs_lck_attr
); 
 190         error 
= dev_add_entry("root", NULL
, DEV_DIR
, NULL
, NULL
, NULL
, &dev_root
); 
 194             printf("devfs_sinit: dev_add_entry failed "); 
 197 #ifdef HIDDEN_MOUNTPOINT 
 198         MALLOC(devfs_hidden_mount
, struct mount 
*, sizeof(struct mount
), 
 200         bzero(devfs_hidden_mount
,sizeof(struct mount
)); 
 201         mount_lock_init(devfs_hidden_mount
); 
 202         TAILQ_INIT(&devfs_hidden_mount
->mnt_vnodelist
); 
 203         TAILQ_INIT(&devfs_hidden_mount
->mnt_workerqueue
); 
 204         TAILQ_INIT(&devfs_hidden_mount
->mnt_newvnodes
); 
 206         mac_mount_label_init(devfs_hidden_mount
); 
 207         mac_mount_label_associate(vfs_context_kernel(), devfs_hidden_mount
); 
 210         /* Initialize the default IO constraints */ 
 211         mp
->mnt_maxreadcnt 
= mp
->mnt_maxwritecnt 
= MAXPHYS
; 
 212         mp
->mnt_segreadcnt 
= mp
->mnt_segwritecnt 
= 32; 
 214         mp
->mnt_realrootvp 
= NULLVP
; 
 215         mp
->mnt_authcache_ttl 
= CACHED_LOOKUP_RIGHT_TTL
; 
 217         devfs_mount(devfs_hidden_mount
,"dummy",NULL
,NULL
,NULL
); 
 218         dev_root
->de_dnp
->dn_dvm 
 
 219             = (struct devfsmount 
*)devfs_hidden_mount
->mnt_data
; 
 220 #endif /* HIDDEN_MOUNTPOINT */ 
 222         mac_devfs_label_associate_directory("/", strlen("/"), 
 223             dev_root
->de_dnp
, "/"); 
 229 /***********************************************************************\ 
 230 ************************************************************************* 
 231 *       Routines used to find our way to a point in the tree            * 
 232 ************************************************************************* 
 233 \***********************************************************************/ 
 237 /*************************************************************** 
 238  * Search down the linked list off a dir to find "name"          
 239  * return the devnode_t * for that node. 
 241  * called with DEVFS_LOCK held 
 242  ***************************************************************/ 
 244 dev_findname(devnode_t 
* dir
, const char *name
) 
 247         if (dir
->dn_type 
!= DEV_DIR
) return 0;/*XXX*/ /* printf?*/ 
 253                         return dir
->dn_typeinfo
.Dir
.myname
; 
 255                 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
; 
 265                 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
; 
 299         if (dirnode
->dn_type 
!= DEV_DIR
)  
 302         if (strlen(path
) > (DEVMAXPATHSIZE 
- 1))  
 306         strlcpy (fullpath
, path
, DEVMAXPATHSIZE
); 
 316             char                component
[DEVMAXPATHSIZE
]; 
 317             devdirent_t 
*       dirent_p
; 
 321                 /* we hit the end of the string, we're done */ 
 326             while (*scan 
!= '/' && *scan
) 
 329             strlcpy(component
, start
, scan 
- start
); 
 333             dirent_p 
= dev_findname(dirnode
, component
); 
 335                 dnp 
= dirent_p
->de_dnp
; 
 336                 if (dnp
->dn_type 
!= DEV_DIR
) { 
 346                 error 
= dev_add_entry(component
, dirnode
,  
 347                                        DEV_DIR
, NULL
, NULL
, NULL
, &dirent_p
); 
 350                 dnp 
= dirent_p
->de_dnp
; 
 352                 mac_devfs_label_associate_directory( 
 353                     dirnode
->dn_typeinfo
.Dir
.myname
->de_name
,  
 354                     strlen(dirnode
->dn_typeinfo
.Dir
.myname
->de_name
), 
 357                 devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, dirent_p
, delp
); 
 359             dirnode 
= dnp
; /* continue relative to this directory */ 
 365 /*********************************************************************** 
 366  * Add a new NAME element to the devfs 
 367  * If we're creating a root node, then dirname is NULL 
 368  * Basically this creates a new namespace entry for the device node 
 370  * Creates a name node, and links it to the supplied node 
 372  * called with DEVFS_LOCK held 
 373  ***********************************************************************/ 
 375 dev_add_name(const char * name
, devnode_t 
* dirnode
, __unused devdirent_t 
* back
,  
 376     devnode_t 
* dnp
, devdirent_t 
* *dirent_pp
) 
 378         devdirent_t 
*   dirent_p 
= NULL
; 
 380         if(dirnode 
!= NULL 
) { 
 381                 if(dirnode
->dn_type 
!= DEV_DIR
) return(ENOTDIR
); 
 383                 if( dev_findname(dirnode
,name
)) 
 387          * make sure the name is legal 
 388          * slightly misleading in the case of NULL 
 390         if (!name 
|| (strlen(name
) > (DEVMAXNAMESIZE 
- 1))) 
 391             return (ENAMETOOLONG
); 
 394          * Allocate and fill out a new directory entry  
 396         MALLOC(dirent_p
, devdirent_t 
*, sizeof(devdirent_t
),  
 397                M_DEVFSNAME
, M_WAITOK
); 
 401         bzero(dirent_p
,sizeof(devdirent_t
)); 
 403         /* inherrit our parent's mount info */ /*XXX*/ 
 404         /* a kludge but.... */ 
 405         if(dirnode 
&& ( dnp
->dn_dvm 
== NULL
)) { 
 406                 dnp
->dn_dvm 
= dirnode
->dn_dvm
; 
 407                 /* if(!dnp->dn_dvm) printf("parent had null dvm "); */ 
 411          * Link the two together 
 412          * include the implicit link in the count of links to the devnode.. 
 413          * this stops it from being accidentally freed later. 
 415         dirent_p
->de_dnp 
= dnp
; 
 416         dnp
->dn_links
++ ; /* implicit from our own name-node */ 
 419          * Make sure that we can find all the links that reference a node 
 420          * so that we can get them all if we need to zap the node. 
 422         if(dnp
->dn_linklist
) { 
 423                 dirent_p
->de_nextlink 
= dnp
->dn_linklist
; 
 424                 dirent_p
->de_prevlinkp 
= dirent_p
->de_nextlink
->de_prevlinkp
; 
 425                 dirent_p
->de_nextlink
->de_prevlinkp 
= &(dirent_p
->de_nextlink
); 
 426                 *dirent_p
->de_prevlinkp 
= dirent_p
; 
 428                 dirent_p
->de_nextlink 
= dirent_p
; 
 429                 dirent_p
->de_prevlinkp 
= &(dirent_p
->de_nextlink
); 
 431         dnp
->dn_linklist 
= dirent_p
; 
 434          * If the node is a directory, then we need to handle the  
 435          * creation of the .. link. 
 436          * A NULL dirnode indicates a root node, so point to ourself. 
 438         if(dnp
->dn_type 
== DEV_DIR
) { 
 439                 dnp
->dn_typeinfo
.Dir
.myname 
= dirent_p
; 
 441                  * If we are unlinking from an old dir, decrement its links 
 442                  * as we point our '..' elsewhere 
 443                  * Note: it's up to the calling code to remove the  
 444                  * us from the original directory's list 
 446                 if(dnp
->dn_typeinfo
.Dir
.parent
) { 
 447                         dnp
->dn_typeinfo
.Dir
.parent
->dn_links
--; 
 450                         dnp
->dn_typeinfo
.Dir
.parent 
= dirnode
; 
 452                         dnp
->dn_typeinfo
.Dir
.parent 
= dnp
; 
 454                 dnp
->dn_typeinfo
.Dir
.parent
->dn_links
++; /* account for the new '..' */ 
 458          * put the name into the directory entry. 
 460         strlcpy(dirent_p
->de_name
, name
, DEVMAXNAMESIZE
); 
 464          * Check if we are not making a root node.. 
 469                  * Put it on the END of the linked list of directory entries 
 471                 dirent_p
->de_parent 
= dirnode
; /* null for root */ 
 472                 dirent_p
->de_prevp 
= dirnode
->dn_typeinfo
.Dir
.dirlast
; 
 473                 dirent_p
->de_next 
= *(dirent_p
->de_prevp
); /* should be NULL */  
 475                 *(dirent_p
->de_prevp
) = dirent_p
; 
 476                 dirnode
->dn_typeinfo
.Dir
.dirlast 
= &(dirent_p
->de_next
); 
 477                 dirnode
->dn_typeinfo
.Dir
.entrycount
++; 
 478                 dirnode
->dn_len 
+= strlen(name
) + 8;/*ok, ok?*/ 
 481         *dirent_pp 
= dirent_p
; 
 482         DEVFS_INCR_ENTRIES(); 
 487 /*********************************************************************** 
 488  * Add a new element to the devfs plane. 
 490  * Creates a new dev_node to go with it if the prototype should not be 
 491  * reused. (Is a DIR, or we select SPLIT_DEVS at compile time) 
 492  * typeinfo gives us info to make our node if we don't have a prototype. 
 493  * If typeinfo is null and proto exists, then the typeinfo field of 
 494  * the proto is used intead in the DEVFS_CREATE case. 
 495  * note the 'links' count is 0 (except if a dir) 
 496  * but it is only cleared on a transition 
 497  * so this is ok till we link it to something 
 498  * Even in SPLIT_DEVS mode, 
 499  * if the node already exists on the wanted plane, just return it 
 501  * called with DEVFS_LOCK held 
 502 ***********************************************************************/ 
 504 dev_add_node(int entrytype
, devnode_type_t 
* typeinfo
, devnode_t 
* proto
, 
 505              devnode_t 
* *dn_pp
, struct devfsmount 
*dvm
) 
 507         devnode_t 
*     dnp 
= NULL
; 
 509 #if defined SPLIT_DEVS 
 511          * If we have a prototype, then check if there is already a sibling 
 512          * on the mount plane we are looking at, if so, just return it. 
 515                 dnp 
= proto
->dn_nextsibling
; 
 516                 while( dnp 
!= proto
) { 
 517                         if (dnp
->dn_dvm 
== dvm
) { 
 521                         dnp 
= dnp
->dn_nextsibling
; 
 523                 if (typeinfo 
== NULL
) 
 524                         typeinfo 
= &(proto
->dn_typeinfo
); 
 526 #else   /* SPLIT_DEVS */ 
 528                 switch (proto
->type
) { 
 535 #endif  /* SPLIT_DEVS */ 
 536         MALLOC(dnp
, devnode_t 
*, sizeof(devnode_t
), M_DEVFSNODE
, M_WAITOK
); 
 542          * If we have a proto, that means that we are duplicating some 
 543          * other device, which can only happen if we are not at the back plane 
 546                 bcopy(proto
, dnp
, sizeof(devnode_t
)); 
 548                 dnp
->dn_linklist 
= NULL
; 
 551                 /* add to END of siblings list */ 
 552                 dnp
->dn_prevsiblingp 
= proto
->dn_prevsiblingp
; 
 553                 *(dnp
->dn_prevsiblingp
) = dnp
; 
 554                 dnp
->dn_nextsibling 
= proto
; 
 555                 proto
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 557                 mac_devfs_label_init(dnp
); 
 558                 mac_devfs_label_copy(proto
->dn_label
, dnp
->dn_label
); 
 564                  * We have no prototype, so start off with a clean slate 
 567                 bzero(dnp
, sizeof(devnode_t
)); 
 568                 dnp
->dn_type 
= entrytype
; 
 569                 dnp
->dn_nextsibling 
= dnp
; 
 570                 dnp
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 571                 dnp
->dn_atime
.tv_sec 
= tv
.tv_sec
; 
 572                 dnp
->dn_mtime
.tv_sec 
= tv
.tv_sec
; 
 573                 dnp
->dn_ctime
.tv_sec 
= tv
.tv_sec
; 
 575                 mac_devfs_label_init(dnp
); 
 579         dnp
->dn_refcount 
= 0; 
 580         dnp
->dn_ino 
= devfs_unique_fileno
; 
 581         devfs_unique_fileno
++; 
 584          * fill out the dev node according to type 
 589                  * As it's a directory, make sure 
 590                  * it has a null entries list 
 592                 dnp
->dn_typeinfo
.Dir
.dirlast 
= &(dnp
->dn_typeinfo
.Dir
.dirlist
); 
 593                 dnp
->dn_typeinfo
.Dir
.dirlist 
= (devdirent_t 
*)0; 
 594                 dnp
->dn_typeinfo
.Dir
.entrycount 
= 0; 
 595                 /*  until we know better, it has a null parent pointer*/ 
 596                 dnp
->dn_typeinfo
.Dir
.parent 
= NULL
; 
 597                 dnp
->dn_links
++; /* for .*/ 
 598                 dnp
->dn_typeinfo
.Dir
.myname 
= NULL
; 
 600                  * make sure that the ops associated with it are the ops 
 601                  * that we use (by default) for directories 
 603                 dnp
->dn_ops 
= &devfs_vnodeop_p
; 
 604                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 608                  * As it's a symlink allocate and store the link info 
 609                  * Symlinks should only ever be created by the user, 
 610                  * so they are not on the back plane and should not be  
 611                  * propogated forward.. a bit like directories in that way.. 
 612                  * A symlink only exists on one plane and has its own 
 613                  * node.. therefore we might be on any random plane. 
 615                 MALLOC(dnp
->dn_typeinfo
.Slnk
.name
, char *,  
 616                        typeinfo
->Slnk
.namelen
+1, 
 617                        M_DEVFSNODE
, M_WAITOK
); 
 618                 if (!dnp
->dn_typeinfo
.Slnk
.name
) { 
 619                         FREE(dnp
,M_DEVFSNODE
); 
 622                 strlcpy(dnp
->dn_typeinfo
.Slnk
.name
, typeinfo
->Slnk
.name
, 
 623                         typeinfo
->Slnk
.namelen 
+ 1); 
 624                 dnp
->dn_typeinfo
.Slnk
.namelen 
= typeinfo
->Slnk
.namelen
; 
 625                 DEVFS_INCR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen 
+ 1); 
 626                 dnp
->dn_ops 
= &devfs_vnodeop_p
; 
 627                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 632                  * Make sure it has DEVICE type ops 
 633                  * and device specific fields are correct 
 635                 dnp
->dn_ops 
= &devfs_spec_vnodeop_p
; 
 636                 dnp
->dn_typeinfo
.dev 
= typeinfo
->dev
; 
 640         /* /dev/fd is special */ 
 642                 dnp
->dn_ops 
= &devfs_devfd_vnodeop_p
; 
 643                 dnp
->dn_mode 
|= 0555;   /* default perms */ 
 657 /*********************************************************************** 
 658  * called with DEVFS_LOCK held 
 659  **********************************************************************/ 
 661 devnode_free(devnode_t 
* dnp
) 
 664         mac_devfs_label_destroy(dnp
); 
 666     if (dnp
->dn_type 
== DEV_SLNK
) { 
 667         DEVFS_DECR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen 
+ 1); 
 668         FREE(dnp
->dn_typeinfo
.Slnk
.name
, M_DEVFSNODE
); 
 671     FREE(dnp
, M_DEVFSNODE
); 
 675 /*********************************************************************** 
 676  * called with DEVFS_LOCK held 
 677  **********************************************************************/ 
 679 devfs_dn_free(devnode_t 
* dnp
) 
 681         if(--dnp
->dn_links 
<= 0 ) /* can be -1 for initial free, on error */ 
 683                 /*probably need to do other cleanups XXX */ 
 684                 if (dnp
->dn_nextsibling 
!= dnp
) { 
 685                         devnode_t 
* *   prevp 
= dnp
->dn_prevsiblingp
; 
 686                         *prevp 
= dnp
->dn_nextsibling
; 
 687                         dnp
->dn_nextsibling
->dn_prevsiblingp 
= prevp
; 
 691                 /* Can only free if there are no references; otherwise, wait for last vnode to be reclaimed */ 
 692                 if (dnp
->dn_refcount 
== 0) { 
 696                     dnp
->dn_lflags 
|= DN_DELETE
; 
 701 /***********************************************************************\ 
 702 *       Front Node Operations                                           *  
 703 *       Add or delete a chain of front nodes                            * 
 704 \***********************************************************************/ 
 707 /*********************************************************************** 
 708  * Given a directory backing node, and a child backing node, add the 
 709  * appropriate front nodes to the front nodes of the directory to 
 710  * represent the child node to the user 
 712  * on failure, front nodes will either be correct or not exist for each 
 713  * front dir, however dirs completed will not be stripped of completed 
 714  * frontnodes on failure of a later frontnode 
 716  * This allows a new node to be propogated through all mounted planes 
 718  * called with DEVFS_LOCK held 
 719  ***********************************************************************/ 
 721 devfs_propogate(devdirent_t 
* parent
,devdirent_t 
* child
, devfs_event_log_t delp
) 
 724         devdirent_t 
* newnmp
; 
 725         devnode_t 
*     dnp 
= child
->de_dnp
; 
 726         devnode_t 
*     pdnp 
= parent
->de_dnp
; 
 727         devnode_t 
*     adnp 
= parent
->de_dnp
; 
 728         int type 
= child
->de_dnp
->dn_type
; 
 731         events 
= (dnp
->dn_type 
== DEV_DIR 
? VNODE_EVENT_DIR_CREATED 
: VNODE_EVENT_FILE_CREATED
); 
 733                 devfs_record_event(delp
, pdnp
, events
); 
 736         /*********************************************** 
 737          * Find the other instances of the parent node 
 738          ***********************************************/ 
 739         for (adnp 
= pdnp
->dn_nextsibling
; 
 741                 adnp 
= adnp
->dn_nextsibling
) 
 744                  * Make the node, using the original as a prototype) 
 745                  * if the node already exists on that plane it won't be 
 748                 if ((error 
= dev_add_entry(child
->de_name
, adnp
, type
, 
 749                                            NULL
, dnp
, adnp
->dn_dvm
,  
 751                         printf("duplicating %s failed\n",child
->de_name
); 
 754                                 devfs_record_event(delp
, adnp
, events
); 
 757                                  * Slightly subtle.  We're guaranteed that there will 
 758                                  * only be a vnode hooked into this devnode if we're creating 
 759                                  * a new link to an existing node; otherwise, the devnode is new 
 760                                  * and no one can have looked it up yet. If we're making a link, 
 761                                  * then the buffer is large enough for two nodes in each  
 762                                  * plane; otherwise, there's no vnode and this call will 
 765                                 devfs_record_event(delp
, newnmp
->de_dnp
, VNODE_EVENT_LINK
); 
 769         return 0;       /* for now always succeed */ 
 773 remove_notify_count(devnode_t 
*dnp
) 
 775         uint32_t notify_count 
= 0; 
 779          * Could need to notify for one removed node on each mount and  
 780          * one parent for each such node. 
 782         notify_count 
= devfs_nmountplanes
; 
 783         notify_count 
+= dnp
->dn_links
;   
 784         for (dnp2 
= dnp
->dn_nextsibling
; dnp2 
!= dnp
; dnp2 
= dnp2
->dn_nextsibling
) { 
 785                 notify_count 
+= dnp2
->dn_links
;  
 792 /*********************************************************************** 
 793  * remove all instances of this devicename [for backing nodes..] 
 794  * note.. if there is another link to the node (non dir nodes only) 
 795  * then the devfs_node will still exist as the ref count will be non-0 
 796  * removing a directory node will remove all sup-nodes on all planes (ZAP) 
 798  * Used by device drivers to remove nodes that are no longer relevant 
 799  * The argument is the 'cookie' they were given when they created the node 
 800  * this function is exported.. see devfs.h 
 801  ***********************************************************************/ 
 803 devfs_remove(void *dirent_p
) 
 805         devnode_t 
* dnp 
= ((devdirent_t 
*)dirent_p
)->de_dnp
; 
 808         struct devfs_event_log event_log
; 
 809         uint32_t    log_count 
= 0; 
 812         struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
]; 
 817                 printf("devfs_remove: not ready for devices!\n"); 
 821         log_count 
= remove_notify_count(dnp
); 
 823         if (log_count 
> NUM_STACK_ENTRIES
) { 
 827                 if (devfs_init_event_log(&event_log
, log_count
, NULL
) == 0) { 
 833                 new_count 
= remove_notify_count(dnp
); 
 834                 if (need_free 
&& (new_count 
> log_count
)) { 
 835                         devfs_release_event_log(&event_log
, 1); 
 838                         log_count 
= log_count 
* 2; 
 842                 if (devfs_init_event_log(&event_log
, NUM_STACK_ENTRIES
, &stackbuf
[0]) == 0) { 
 847         /* This file has been deleted */ 
 848         if (do_notify 
!= 0) { 
 849                 devfs_record_event(&event_log
, dnp
, VNODE_EVENT_DELETE
); 
 852         /* keep removing the next sibling till only we exist. */ 
 853         while ((dnp2 
= dnp
->dn_nextsibling
) != dnp
) { 
 856                  * Keep removing the next front node till no more exist 
 858                 dnp
->dn_nextsibling 
= dnp2
->dn_nextsibling
;  
 859                 dnp
->dn_nextsibling
->dn_prevsiblingp 
= &(dnp
->dn_nextsibling
); 
 860                 dnp2
->dn_nextsibling 
= dnp2
; 
 861                 dnp2
->dn_prevsiblingp 
= &(dnp2
->dn_nextsibling
); 
 863                 /* This file has been deleted in this plane */ 
 864                 if (do_notify 
!= 0) { 
 865                         devfs_record_event(&event_log
, dnp2
, VNODE_EVENT_DELETE
); 
 868                 if (dnp2
->dn_linklist
) { 
 870                                 lastlink 
= (1 == dnp2
->dn_links
); 
 871                                 /* Each parent of a link to this file has lost a child in this plane */ 
 872                                 if (do_notify 
!= 0) { 
 873                                         devfs_record_event(&event_log
, dnp2
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
); 
 875                                 dev_free_name(dnp2
->dn_linklist
); 
 881          * then free the main node 
 882          * If we are not running in SPLIT_DEVS mode, then 
 883          * THIS is what gets rid of the propogated nodes. 
 885         if (dnp
->dn_linklist
) { 
 887                         lastlink 
= (1 == dnp
->dn_links
); 
 888                         /* Each parent of a link to this file has lost a child */ 
 889                         if (do_notify 
!= 0) { 
 890                                 devfs_record_event(&event_log
, dnp
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
); 
 892                         dev_free_name(dnp
->dn_linklist
); 
 897         if (do_notify 
!= 0) { 
 898                 devfs_bulk_notify(&event_log
); 
 899                 devfs_release_event_log(&event_log
, need_free
); 
 907 /*************************************************************** 
 908  * duplicate the backing tree into a tree of nodes hung off the 
 909  * mount point given as the argument. Do this by 
 910  * calling dev_dup_entry which recurses all the way 
 913  * called with DEVFS_LOCK held 
 914  **************************************************************/ 
 916 dev_dup_plane(struct devfsmount 
*devfs_mp_p
) 
 921         if ((error 
= dev_dup_entry(NULL
, dev_root
, &new, devfs_mp_p
))) 
 923         devfs_mp_p
->plane_root 
= new; 
 924         devfs_nmountplanes
++; 
 930 /*************************************************************** 
 933  * called with DEVFS_LOCK held 
 934  ***************************************************************/ 
 936 devfs_free_plane(struct devfsmount 
*devfs_mp_p
) 
 938         devdirent_t 
* dirent_p
; 
 940         dirent_p 
= devfs_mp_p
->plane_root
; 
 942                 dev_free_hier(dirent_p
); 
 943                 dev_free_name(dirent_p
); 
 945         devfs_mp_p
->plane_root 
= NULL
; 
 946         devfs_nmountplanes
--; 
 948         if (devfs_nmountplanes 
> (devfs_nmountplanes
+1)) { 
 949                 panic("plane count wrapped around.\n"); 
 954 /*************************************************************** 
 955  * Create and link in a new front element.. 
 956  * Parent can be 0 for a root node 
 957  * Not presently usable to make a symlink XXX 
 958  * (Ok, symlinks don't propogate) 
 959  * recursively will create subnodes corresponding to equivalent 
 960  * child nodes in the base level 
 962  * called with DEVFS_LOCK held 
 963  ***************************************************************/ 
 965 dev_dup_entry(devnode_t 
* parent
, devdirent_t 
* back
, devdirent_t 
* *dnm_pp
, 
 966               struct devfsmount 
*dvm
) 
 968         devdirent_t 
*   entry_p
; 
 969         devdirent_t 
*   newback
; 
 970         devdirent_t 
*   newfront
; 
 972         devnode_t 
*     dnp 
= back
->de_dnp
; 
 973         int type 
= dnp
->dn_type
; 
 976          * go get the node made (if we need to) 
 977          * use the back one as a prototype 
 979         if ((error 
= dev_add_entry(back
->de_name
, parent
, type
, 
 981                                 parent
?parent
->dn_dvm
:dvm
, &entry_p
)) != 0) { 
 982                 printf("duplicating %s failed\n",back
->de_name
); 
 986          * If we have just made the root, then insert the pointer to the 
 990                 entry_p
->de_dnp
->dn_dvm 
= dvm
; 
 994          * If it is a directory, then recurse down all the other 
 996          * note that this time we don't pass on the mount info.. 
1000                 for(newback 
= back
->de_dnp
->dn_typeinfo
.Dir
.dirlist
; 
1001                                 newback
; newback 
= newback
->de_next
) 
1003                         if((error 
= dev_dup_entry(entry_p
->de_dnp
, 
1004                                             newback
, &newfront
, NULL
)) != 0) 
1006                                 break; /* back out with an error */ 
1015 /*************************************************************** 
1017  * remember that if there are other names pointing to the 
1018  * dev_node then it may not get freed yet 
1019  * can handle if there is no dnp 
1021  * called with DEVFS_LOCK held 
1022  ***************************************************************/ 
1025 dev_free_name(devdirent_t 
* dirent_p
) 
1027         devnode_t 
*     parent 
= dirent_p
->de_parent
; 
1028         devnode_t 
*     dnp 
= dirent_p
->de_dnp
; 
1031                 if(dnp
->dn_type 
== DEV_DIR
) 
1035                         if(dnp
->dn_typeinfo
.Dir
.dirlist
) 
1037                         p 
= dnp
->dn_typeinfo
.Dir
.parent
; 
1038                         devfs_dn_free(dnp
);     /* account for '.' */ 
1039                         devfs_dn_free(p
);       /* '..' */ 
1042                  * unlink us from the list of links for this node 
1043                  * If we are the only link, it's easy! 
1044                  * if we are a DIR of course there should not be any 
1047                 if(dirent_p
->de_nextlink 
== dirent_p
) { 
1048                                 dnp
->dn_linklist 
= NULL
; 
1050                         if(dnp
->dn_linklist 
== dirent_p
) { 
1051                                 dnp
->dn_linklist 
= dirent_p
->de_nextlink
; 
1053                         dirent_p
->de_nextlink
->de_prevlinkp 
 
1054                             = dirent_p
->de_prevlinkp
; 
1055                         *dirent_p
->de_prevlinkp 
= dirent_p
->de_nextlink
; 
1061          * unlink ourselves from the directory on this plane 
1063         if(parent
) /* if not fs root */ 
1065                 if( (*dirent_p
->de_prevp 
= dirent_p
->de_next
) )/* yes, assign */ 
1067                         dirent_p
->de_next
->de_prevp 
= dirent_p
->de_prevp
; 
1071                         parent
->dn_typeinfo
.Dir
.dirlast
 
1072                                 = dirent_p
->de_prevp
; 
1074                 parent
->dn_typeinfo
.Dir
.entrycount
--; 
1075                 parent
->dn_len 
-= strlen(dirent_p
->de_name
) + 8; 
1078         DEVFS_DECR_ENTRIES(); 
1079         FREE(dirent_p
, M_DEVFSNAME
); 
1084 /*************************************************************** 
1085  * Free a hierarchy starting at a directory node name 
1086  * remember that if there are other names pointing to the 
1087  * dev_node then it may not get freed yet 
1088  * can handle if there is no dnp 
1089  * leave the node itself allocated. 
1091  * called with DEVFS_LOCK held 
1092  ***************************************************************/ 
1095 dev_free_hier(devdirent_t 
* dirent_p
) 
1097         devnode_t 
*     dnp 
= dirent_p
->de_dnp
; 
1100                 if(dnp
->dn_type 
== DEV_DIR
) 
1102                         while(dnp
->dn_typeinfo
.Dir
.dirlist
) 
1104                                 dev_free_hier(dnp
->dn_typeinfo
.Dir
.dirlist
); 
1105                                 dev_free_name(dnp
->dn_typeinfo
.Dir
.dirlist
); 
1112 /*************************************************************** 
1113  * given a dev_node, find the appropriate vnode if one is already 
1114  * associated, or get a new one and associate it with the dev_node 
1116  * called with DEVFS_LOCK held 
1118  * If an error is returned, then the dnp may have been freed (we 
1119  * raced with a delete and lost).  A devnode should not be accessed 
1120  * after devfs_dntovn() fails. 
1121  ****************************************************************/ 
1123 devfs_dntovn(devnode_t 
* dnp
, struct vnode 
**vn_pp
, __unused 
struct proc 
* p
) 
1127         struct vnode_fsparam vfsp
; 
1128         enum vtype vtype 
= 0; 
1130         int n_minor 
= DEVFS_CLONE_ALLOC
; /* new minor number for clone device */ 
1133          * We should never come in and find that our devnode has been marked for delete. 
1134          * The lookup should have held the lock from entry until now; it should not have 
1135          * been able to find a removed entry. Any other pathway would have just created 
1136          * the devnode and come here without dropping the devfs lock, so no one would 
1137          * have a chance to delete. 
1139         if (dnp
->dn_lflags 
& DN_DELETE
) { 
1140                 panic("devfs_dntovn: DN_DELETE set on a devnode upon entry."); 
1143         devfs_ref_node(dnp
); 
1149         if (vn_p
) { /* already has a vnode */ 
1152                 vid 
= vnode_vid(vn_p
); 
1156                 error 
= vnode_getwithvid(vn_p
, vid
); 
1160                 if (dnp
->dn_lflags 
& DN_DELETE
) { 
1162                          * our BUSY node got marked for 
1163                          * deletion while the DEVFS lock 
1168                                  * vnode_getwithvid returned a valid ref 
1169                                  * which we need to drop 
1175                          * This entry is no longer in the namespace.  This is only  
1176                          * possible for lookup: no other path would not find an existing 
1177                          * vnode.  Therefore, ENOENT is a valid result. 
1188          * If we get here, then we've beaten any deletes;  
1189          * if someone sets DN_DELETE during a subsequent drop 
1190          * of the devfs lock, we'll still vend a vnode. 
1193         if (dnp
->dn_lflags 
& DN_CREATE
) { 
1194                 dnp
->dn_lflags 
|= DN_CREATEWAIT
; 
1195                 msleep(&dnp
->dn_lflags
, &devfs_mutex
, PRIBIO
, 0 , 0); 
1199         dnp
->dn_lflags 
|= DN_CREATE
; 
1201         switch (dnp
->dn_type
) { 
1206                         if (dnp
->dn_typeinfo
.Dir
.parent 
== dnp
) { 
1213                         vtype 
= (dnp
->dn_type 
== DEV_BDEV
) ? VBLK 
: VCHR
; 
1221         vfsp
.vnfs_mp 
= dnp
->dn_dvm
->mount
; 
1222         vfsp
.vnfs_vtype 
= vtype
; 
1223         vfsp
.vnfs_str 
= "devfs"; 
1225         vfsp
.vnfs_fsnode 
= dnp
; 
1227         vfsp
.vnfs_vops 
= *(dnp
->dn_ops
); 
1229         if (vtype 
== VBLK 
|| vtype 
== VCHR
) { 
1231                  * Ask the clone minor number function for a new minor number 
1232                  * to use for the next device instance.  If an administative 
1233                  * limit has been reached, this function will return -1. 
1235                 if (dnp
->dn_clone 
!= NULL
) { 
1236                         int     n_major 
= major(dnp
->dn_typeinfo
.dev
); 
1238                         n_minor 
= (*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_ALLOC
); 
1239                         if (n_minor 
== -1) { 
1244                         vfsp
.vnfs_rdev 
= makedev(n_major
, n_minor
);; 
1246                 vfsp
.vnfs_rdev 
= dnp
->dn_typeinfo
.dev
; 
1251         vfsp
.vnfs_filesize 
= 0; 
1252         vfsp
.vnfs_flags 
= VNFS_NOCACHE 
| VNFS_CANTCACHE
; 
1253         /* Tag system files */ 
1254         vfsp
.vnfs_marksystem 
= 0; 
1255         vfsp
.vnfs_markroot 
= markroot
; 
1259         error 
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &vn_p
); 
1261         /* Do this before grabbing the lock */ 
1263                 vnode_setneedinactive(vn_p
); 
1269                         vnode_settag(vn_p
, VT_DEVFS
); 
1271                         if ((dnp
->dn_clone 
!= NULL
) && (dnp
->dn_vn 
!= NULLVP
) ) 
1272                                 panic("devfs_dntovn: cloning device with a vnode?\n"); 
1277                          * Another vnode that has this devnode as its v_data. 
1278                          * This reference, unlike the one taken at the start 
1279                          * of the function, persists until a VNOP_RECLAIM 
1280                          * comes through for this vnode. 
1282                         devfs_ref_node(dnp
); 
1285                          * A cloned vnode is not hooked into the devnode; every lookup 
1288                         if (dnp
->dn_clone 
== NULL
) { 
1291         } else if (n_minor 
!= DEVFS_CLONE_ALLOC
) { 
1293                  * If we failed the create, we need to release the cloned minor 
1294                  * back to the free list.  In general, this is only useful if 
1295                  * the clone function results in a state change in the cloned 
1296                  * device for which the minor number was obtained.  If we get 
1297                  * past this point withouth falling into this case, it's 
1298                  * assumed that any state to be released will be released when 
1299                  * the vnode is dropped, instead. 
1301                  (void)(*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_FREE
); 
1304         dnp
->dn_lflags 
&= ~DN_CREATE
; 
1305         if (dnp
->dn_lflags 
& DN_CREATEWAIT
) { 
1306                 dnp
->dn_lflags 
&= ~DN_CREATEWAIT
; 
1307                 wakeup(&dnp
->dn_lflags
); 
1312          * Release the reference we took to prevent deletion while we weren't holding the lock. 
1313          * If not returning success, then dropping this reference could delete the devnode; 
1314          * no one should access a devnode after a call to devfs_dntovn fails. 
1316         devfs_rele_node(dnp
); 
1322  * Increment refcount on a devnode; prevents free of the node 
1323  * while the devfs lock is not held. 
1326 devfs_ref_node(devnode_t 
*dnp
)  
1332  * Release a reference on a devnode.  If the devnode is marked for  
1333  * free and the refcount is dropped to zero, do the free. 
1336 devfs_rele_node(devnode_t 
*dnp
) 
1339         if (dnp
->dn_refcount 
< 0) { 
1340                 panic("devfs_rele_node: devnode with a negative refcount!\n"); 
1341         } else if ((dnp
->dn_refcount 
== 0) && (dnp
->dn_lflags 
& DN_DELETE
))  { 
1347 /*********************************************************************** 
1348  * add a whole device, with no prototype.. make name element and node 
1349  * Used for adding the original device entries 
1351  * called with DEVFS_LOCK held 
1352  ***********************************************************************/ 
1354 dev_add_entry(const char *name
, devnode_t 
* parent
, int type
, devnode_type_t 
* typeinfo
, 
1355               devnode_t 
* proto
, struct devfsmount 
*dvm
, devdirent_t 
* *nm_pp
) 
1360         if ((error 
= dev_add_node(type
, typeinfo
, proto
, &dnp
,  
1361                         (parent
?parent
->dn_dvm
:dvm
))) != 0) 
1363                 printf("devfs: %s: base node allocation failed (Errno=%d)\n", 
1367         if ((error 
= dev_add_name(name 
,parent 
,NULL
, dnp
, nm_pp
)) != 0) 
1369                 devfs_dn_free(dnp
); /* 1->0 for dir, 0->(-1) for other */ 
1370                 printf("devfs: %s: name slot allocation failed (Errno=%d)\n", 
1378 devfs_bulk_notify(devfs_event_log_t delp
)  
1381         for (i 
= 0; i 
< delp
->del_used
; i
++) { 
1382                 devfs_vnode_event_t dvep 
= &delp
->del_entries
[i
]; 
1383                 if (vnode_getwithvid(dvep
->dve_vp
, dvep
->dve_vid
) == 0) { 
1384                         vnode_notify(dvep
->dve_vp
, dvep
->dve_events
, NULL
); 
1385                         vnode_put(dvep
->dve_vp
); 
1391 devfs_record_event(devfs_event_log_t delp
, devnode_t 
*dnp
, uint32_t events
) 
1393         if (delp
->del_used 
>= delp
->del_max
) { 
1394                 panic("devfs event log overflowed.\n"); 
1397         /* Can only notify for nodes that have an associated vnode */ 
1398         if (dnp
->dn_vn 
!= NULLVP 
&& vnode_ismonitored(dnp
->dn_vn
)) { 
1399                 devfs_vnode_event_t dvep 
= &delp
->del_entries
[delp
->del_used
]; 
1400                 dvep
->dve_vp 
= dnp
->dn_vn
; 
1401                 dvep
->dve_vid 
= vnode_vid(dnp
->dn_vn
); 
1402                 dvep
->dve_events 
= events
; 
1408 devfs_init_event_log(devfs_event_log_t delp
, uint32_t count
, devfs_vnode_event_t buf
)  
1410         devfs_vnode_event_t dvearr
; 
1413                 MALLOC(dvearr
, devfs_vnode_event_t
, count 
* sizeof(struct devfs_vnode_event
), M_TEMP
, M_WAITOK 
| M_ZERO
); 
1414                 if (dvearr 
== NULL
) { 
1421         delp
->del_max 
= count
; 
1423         delp
->del_entries 
= dvearr
; 
1428 devfs_release_event_log(devfs_event_log_t delp
, int need_free
) 
1430         if (delp
->del_entries 
== NULL
) { 
1431                 panic("Free of devfs notify info that has not been intialized.\n"); 
1435                 FREE(delp
->del_entries
, M_TEMP
); 
1438         delp
->del_entries 
= NULL
; 
1442  * Function: devfs_make_node 
1445  *   Create a device node with the given pathname in the devfs namespace. 
1448  *   dev        - the dev_t value to associate 
1449  *   chrblk     - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 
1450  *   uid, gid   - ownership 
1451  *   perms      - permissions 
1452  *   clone      - minor number cloning function 
1453  *   fmt, ...   - path format string with printf args to format the path name 
1455  *   A handle to a device node if successful, NULL otherwise. 
1458 devfs_make_node_clone(dev_t dev
, int chrblk
, uid_t uid
, 
1459                 gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
), 
1460                 const char *fmt
, ...) 
1462         devdirent_t 
*   new_dev 
= NULL
; 
1478         new_dev 
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, clone
, fmt
, ap
); 
1486  * Function: devfs_make_node 
1489  *   Create a device node with the given pathname in the devfs namespace. 
1492  *   dev        - the dev_t value to associate 
1493  *   chrblk     - block or character device (DEVFS_CHAR or DEVFS_BLOCK) 
1494  *   uid, gid   - ownership 
1495  *   perms      - permissions 
1496  *   fmt, ...   - path format string with printf args to format the path name 
1498  *   A handle to a device node if successful, NULL otherwise. 
1501 devfs_make_node(dev_t dev
, int chrblk
, uid_t uid
, 
1502                 gid_t gid
, int perms
, const char *fmt
, ...) 
1504         devdirent_t 
*   new_dev 
= NULL
; 
1508         if (chrblk 
!= DEVFS_CHAR 
&& chrblk 
!= DEVFS_BLOCK
) 
1511         type 
= (chrblk 
== DEVFS_BLOCK 
? DEV_BDEV 
: DEV_CDEV
); 
1514         new_dev 
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, NULL
, fmt
, ap
); 
1521 static devdirent_t 
* 
1522 devfs_make_node_internal(dev_t dev
, devfstype_t type
, uid_t uid
,  
1523                 gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
), const char *fmt
, va_list ap
) 
1525         devdirent_t 
*   new_dev 
= NULL
; 
1527         devnode_type_t  typeinfo
; 
1529         char            *name
, buf
[256]; /* XXX */ 
1532         char buff
[sizeof(buf
)]; 
1536         struct devfs_event_log event_log
; 
1537         struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
]; 
1540         vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1543         bcopy(buf
, buff
, sizeof(buff
)); 
1544         buff
[sizeof(buff
)-1] = 0; 
1548         for(i
=strlen(buf
); i
>0; i
--) 
1563         log_count 
= devfs_nmountplanes
; 
1564         if (log_count 
> NUM_STACK_ENTRIES
) { 
1567                 if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) { 
1572                 log_count 
= NUM_STACK_ENTRIES
; 
1573                 if (devfs_init_event_log(&event_log
, log_count
, &stackbuf
[0]) != 0) { 
1579         if (log_count 
< devfs_nmountplanes
) { 
1581                 devfs_release_event_log(&event_log
, need_free
); 
1582                 log_count 
= log_count 
* 2; 
1587                 printf("devfs_make_node: not ready for devices!\n"); 
1591         /* find/create directory path ie. mkdir -p */ 
1592         if (dev_finddir(path
, NULL
, DEVFS_CREATE
, &dnp
, &event_log
) == 0) { 
1594             if (dev_add_entry(name
, dnp
, type
, &typeinfo
, NULL
, NULL
, &new_dev
) == 0) { 
1595                 new_dev
->de_dnp
->dn_gid 
= gid
; 
1596                 new_dev
->de_dnp
->dn_uid 
= uid
; 
1597                 new_dev
->de_dnp
->dn_mode 
|= perms
; 
1598                 new_dev
->de_dnp
->dn_clone 
= clone
; 
1600                 mac_devfs_label_associate_device(dev
, new_dev
->de_dnp
, buff
); 
1602                 devfs_propogate(dnp
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
); 
1609         devfs_bulk_notify(&event_log
); 
1610         devfs_release_event_log(&event_log
, need_free
); 
1615  * Function: devfs_make_link 
1618  *   Create a link to a previously created device node. 
1621  *   0 if successful, -1 if failed 
1624 devfs_make_link(void *original
, char *fmt
, ...) 
1626         devdirent_t 
*   new_dev 
= NULL
; 
1627         devdirent_t 
*   orig 
= (devdirent_t 
*) original
; 
1628         devnode_t 
*     dirnode
;        /* devnode for parent directory */ 
1629         struct devfs_event_log event_log
; 
1633         char *p
, buf
[256]; /* XXX */ 
1640                 printf("devfs_make_link: not ready for devices!\n"); 
1646         vsnprintf(buf
, sizeof(buf
), fmt
, ap
); 
1651         for(i
=strlen(buf
); i
>0; i
--) { 
1660          * One slot for each directory, one for each devnode  
1661          * whose link count changes  
1663         log_count 
= devfs_nmountplanes 
* 2; 
1665         if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) { 
1666                 /* No lock held, no allocations done, can just return */ 
1672         if (log_count 
< devfs_nmountplanes
) { 
1674                 devfs_release_event_log(&event_log
, 1); 
1675                 log_count 
= log_count 
* 2; 
1682                 if (dev_finddir(buf
, NULL
, DEVFS_CREATE
, &dirnode
, &event_log
) 
1683                     || dev_add_name(p
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) 
1686                 if (dev_finddir("", NULL
, DEVFS_CREATE
, &dirnode
, &event_log
) 
1687                     || dev_add_name(buf
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) 
1690         devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
); 
1693         devfs_bulk_notify(&event_log
); 
1694         devfs_release_event_log(&event_log
, 1); 
1696         return ((new_dev 
!= NULL
) ? 0 : -1);