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 #include <os/refcnt.h>
103 #define BSD_KERNEL_PRIVATE 1 /* devfs_make_link() prototype */
105 #include "devfsdefs.h"
108 #include <security/mac_framework.h>
115 typedef struct devfs_vnode_event
{
119 } *devfs_vnode_event_t
;
122 * Size of stack buffer (fast path) for notifications. If
123 * the number of mounts is small, no need to malloc a buffer.
125 #define NUM_STACK_ENTRIES 5
127 typedef struct devfs_event_log
{
130 devfs_vnode_event_t del_entries
;
131 } *devfs_event_log_t
;
134 static void dev_free_hier(devdirent_t
*);
135 static int devfs_propogate(devdirent_t
*, devdirent_t
*, devfs_event_log_t
);
136 static int dev_finddir(const char *, devnode_t
*, int, devnode_t
**, devfs_event_log_t
);
137 static int dev_dup_entry(devnode_t
*, devdirent_t
*, devdirent_t
**, struct devfsmount
*);
138 void devfs_ref_node(devnode_t
*);
139 void devfs_rele_node(devnode_t
*);
140 static void devfs_record_event(devfs_event_log_t
, devnode_t
*, uint32_t);
141 static int devfs_init_event_log(devfs_event_log_t
, uint32_t, devfs_vnode_event_t
);
142 static void devfs_release_event_log(devfs_event_log_t
, int);
143 static void devfs_bulk_notify(devfs_event_log_t
);
144 static devdirent_t
*devfs_make_node_internal(dev_t
, devfstype_t type
, uid_t
, gid_t
, int,
145 int (*clone
)(dev_t dev
, int action
), const char *fmt
, va_list ap
);
148 lck_grp_t
* devfs_lck_grp
;
149 lck_grp_attr_t
* devfs_lck_grp_attr
;
150 lck_attr_t
* devfs_lck_attr
;
151 lck_mtx_t devfs_mutex
;
152 lck_mtx_t devfs_attr_mutex
;
154 os_refgrp_decl(static, devfs_refgrp
, "devfs", NULL
);
156 devdirent_t
* dev_root
= NULL
; /* root of backing tree */
157 struct devfs_stats devfs_stats
; /* hold stats */
159 static ino_t devfs_unique_fileno
= 0;
161 #ifdef HIDDEN_MOUNTPOINT
162 static struct mount
*devfs_hidden_mount
;
163 #endif /* HIDDEN_MOINTPOINT */
165 static int devfs_ready
= 0;
166 static uint32_t devfs_nmountplanes
= 0; /* The first plane is not used for a mount */
168 #define DEVFS_NOCREATE FALSE
169 #define DEVFS_CREATE TRUE
172 * Set up the root directory node in the backing plane
173 * This is happenning before the vfs system has been
174 * set up yet, so be careful about what we reference..
175 * Notice that the ops are by indirection.. as they haven't
177 * DEVFS has a hidden mountpoint that is used as the anchor point
178 * for the internal 'blueprint' version of the dev filesystem tree.
186 devfs_lck_grp_attr
= lck_grp_attr_alloc_init();
187 devfs_lck_grp
= lck_grp_alloc_init("devfs_lock", devfs_lck_grp_attr
);
189 devfs_lck_attr
= lck_attr_alloc_init();
191 lck_mtx_init(&devfs_mutex
, devfs_lck_grp
, devfs_lck_attr
);
192 lck_mtx_init(&devfs_attr_mutex
, devfs_lck_grp
, devfs_lck_attr
);
195 error
= dev_add_entry("root", NULL
, DEV_DIR
, NULL
, NULL
, NULL
, &dev_root
);
199 printf("devfs_sinit: dev_add_entry failed ");
202 #ifdef HIDDEN_MOUNTPOINT
203 devfs_hidden_mount
= zalloc_flags(mount_zone
, Z_WAITOK
| Z_ZERO
);
204 mount_lock_init(devfs_hidden_mount
);
205 TAILQ_INIT(&devfs_hidden_mount
->mnt_vnodelist
);
206 TAILQ_INIT(&devfs_hidden_mount
->mnt_workerqueue
);
207 TAILQ_INIT(&devfs_hidden_mount
->mnt_newvnodes
);
209 mac_mount_label_init(devfs_hidden_mount
);
210 mac_mount_label_associate(vfs_context_kernel(), devfs_hidden_mount
);
213 /* Initialize the default IO constraints */
214 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
215 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
217 mp
->mnt_realrootvp
= NULLVP
;
218 mp
->mnt_authcache_ttl
= CACHED_LOOKUP_RIGHT_TTL
;
220 devfs_mount(devfs_hidden_mount
, "dummy", NULL
, NULL
, NULL
);
221 dev_root
->de_dnp
->dn_dvm
222 = (struct devfsmount
*)devfs_hidden_mount
->mnt_data
;
223 #endif /* HIDDEN_MOUNTPOINT */
225 mac_devfs_label_associate_directory("/", (int) strlen("/"),
226 dev_root
->de_dnp
, "/");
232 /***********************************************************************\
233 *************************************************************************
234 * Routines used to find our way to a point in the tree *
235 *************************************************************************
236 \***********************************************************************/
240 /***************************************************************
241 * Search down the linked list off a dir to find "name"
242 * return the devnode_t * for that node.
244 * called with DEVFS_LOCK held
245 ***************************************************************/
247 dev_findname(devnode_t
* dir
, const char *name
)
250 if (dir
->dn_type
!= DEV_DIR
) {
251 return 0; /*XXX*/ /* printf?*/
253 if (name
[0] == '.') {
255 return dir
->dn_typeinfo
.Dir
.myname
;
257 if ((name
[1] == '.') && (name
[2] == 0)) {
258 /* for root, .. == . */
259 return dir
->dn_typeinfo
.Dir
.parent
->dn_typeinfo
.Dir
.myname
;
262 newfp
= dir
->dn_typeinfo
.Dir
.dirlist
;
265 if (!(strncmp(name
, newfp
->de_name
, sizeof(newfp
->de_name
)))) {
268 newfp
= newfp
->de_next
;
273 /***********************************************************************
274 * Given a starting node (0 for root) and a pathname, return the node
275 * for the end item on the path. It MUST BE A DIRECTORY. If the 'DEVFS_CREATE'
276 * option is true, then create any missing nodes in the path and create
277 * and return the final node as well.
278 * This is used to set up a directory, before making nodes in it..
280 * called with DEVFS_LOCK held
281 ***********************************************************************/
283 dev_finddir(const char * path
,
287 devfs_event_log_t delp
)
289 devnode_t
* dnp
= NULL
;
293 char fullpath
[DEVMAXPATHSIZE
];
297 if (!dirnode
) { /* dirnode == NULL means start at root */
298 dirnode
= dev_root
->de_dnp
;
301 if (dirnode
->dn_type
!= DEV_DIR
) {
305 if (strlen(path
) > (DEVMAXPATHSIZE
- 1)) {
310 strlcpy(fullpath
, path
, DEVMAXPATHSIZE
);
314 while (*scan
== '/') {
321 char component
[DEVMAXPATHSIZE
];
322 devdirent_t
* dirent_p
;
326 /* we hit the end of the string, we're done */
331 while (*scan
!= '/' && *scan
) {
335 strlcpy(component
, start
, (scan
- start
) + 1);
340 dirent_p
= dev_findname(dirnode
, component
);
342 dnp
= dirent_p
->de_dnp
;
343 if (dnp
->dn_type
!= DEV_DIR
) {
352 error
= dev_add_entry(component
, dirnode
,
353 DEV_DIR
, NULL
, NULL
, NULL
, &dirent_p
);
357 dnp
= dirent_p
->de_dnp
;
359 mac_devfs_label_associate_directory(
360 dirnode
->dn_typeinfo
.Dir
.myname
->de_name
,
361 (int) strlen(dirnode
->dn_typeinfo
.Dir
.myname
->de_name
),
364 devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, dirent_p
, delp
);
366 dirnode
= dnp
; /* continue relative to this directory */
372 /***********************************************************************
373 * Add a new NAME element to the devfs
374 * If we're creating a root node, then dirname is NULL
375 * Basically this creates a new namespace entry for the device node
377 * Creates a name node, and links it to the supplied node
379 * called with DEVFS_LOCK held
380 ***********************************************************************/
382 dev_add_name(const char * name
, devnode_t
* dirnode
, __unused devdirent_t
* back
,
383 devnode_t
* dnp
, devdirent_t
* *dirent_pp
)
385 devdirent_t
* dirent_p
= NULL
;
387 if (dirnode
!= NULL
) {
388 if (dirnode
->dn_type
!= DEV_DIR
) {
392 if (dev_findname(dirnode
, name
)) {
397 * make sure the name is legal
398 * slightly misleading in the case of NULL
400 if (!name
|| (strlen(name
) > (DEVMAXNAMESIZE
- 1))) {
405 * Allocate and fill out a new directory entry
407 MALLOC(dirent_p
, devdirent_t
*, sizeof(devdirent_t
),
408 M_DEVFSNAME
, M_WAITOK
);
412 bzero(dirent_p
, sizeof(devdirent_t
));
414 /* inherrit our parent's mount info */ /*XXX*/
415 /* a kludge but.... */
416 if (dirnode
&& (dnp
->dn_dvm
== NULL
)) {
417 dnp
->dn_dvm
= dirnode
->dn_dvm
;
418 /* if(!dnp->dn_dvm) printf("parent had null dvm "); */
422 * Link the two together
423 * include the implicit link in the count of links to the devnode..
424 * this stops it from being accidentally freed later.
426 dirent_p
->de_dnp
= dnp
;
427 dnp
->dn_links
++; /* implicit from our own name-node */
430 * Make sure that we can find all the links that reference a node
431 * so that we can get them all if we need to zap the node.
433 if (dnp
->dn_linklist
) {
434 dirent_p
->de_nextlink
= dnp
->dn_linklist
;
435 dirent_p
->de_prevlinkp
= dirent_p
->de_nextlink
->de_prevlinkp
;
436 dirent_p
->de_nextlink
->de_prevlinkp
= &(dirent_p
->de_nextlink
);
437 *dirent_p
->de_prevlinkp
= dirent_p
;
439 dirent_p
->de_nextlink
= dirent_p
;
440 dirent_p
->de_prevlinkp
= &(dirent_p
->de_nextlink
);
442 dnp
->dn_linklist
= dirent_p
;
445 * If the node is a directory, then we need to handle the
446 * creation of the .. link.
447 * A NULL dirnode indicates a root node, so point to ourself.
449 if (dnp
->dn_type
== DEV_DIR
) {
450 dnp
->dn_typeinfo
.Dir
.myname
= dirent_p
;
452 * If we are unlinking from an old dir, decrement its links
453 * as we point our '..' elsewhere
454 * Note: it's up to the calling code to remove the
455 * us from the original directory's list
457 if (dnp
->dn_typeinfo
.Dir
.parent
) {
458 dnp
->dn_typeinfo
.Dir
.parent
->dn_links
--;
461 dnp
->dn_typeinfo
.Dir
.parent
= dirnode
;
463 dnp
->dn_typeinfo
.Dir
.parent
= dnp
;
465 dnp
->dn_typeinfo
.Dir
.parent
->dn_links
++; /* account for the new '..' */
469 * put the name into the directory entry.
471 strlcpy(dirent_p
->de_name
, name
, DEVMAXNAMESIZE
);
475 * Check if we are not making a root node..
480 * Put it on the END of the linked list of directory entries
482 dirent_p
->de_parent
= dirnode
; /* null for root */
483 dirent_p
->de_prevp
= dirnode
->dn_typeinfo
.Dir
.dirlast
;
484 dirent_p
->de_next
= *(dirent_p
->de_prevp
); /* should be NULL */
486 *(dirent_p
->de_prevp
) = dirent_p
;
487 dirnode
->dn_typeinfo
.Dir
.dirlast
= &(dirent_p
->de_next
);
488 dirnode
->dn_typeinfo
.Dir
.entrycount
++;
489 dirnode
->dn_len
+= strlen(name
) + 8;/*ok, ok?*/
492 *dirent_pp
= dirent_p
;
493 DEVFS_INCR_ENTRIES();
498 /***********************************************************************
499 * Add a new element to the devfs plane.
501 * Creates a new dev_node to go with it if the prototype should not be
502 * reused. (Is a DIR, or we select SPLIT_DEVS at compile time)
503 * typeinfo gives us info to make our node if we don't have a prototype.
504 * If typeinfo is null and proto exists, then the typeinfo field of
505 * the proto is used intead in the DEVFS_CREATE case.
506 * note the 'links' count is 0 (except if a dir)
507 * but it is only cleared on a transition
508 * so this is ok till we link it to something
509 * Even in SPLIT_DEVS mode,
510 * if the node already exists on the wanted plane, just return it
512 * called with DEVFS_LOCK held
513 ***********************************************************************/
515 dev_add_node(int entrytype
, devnode_type_t
* typeinfo
, devnode_t
* proto
,
516 devnode_t
* *dn_pp
, struct devfsmount
*dvm
)
518 devnode_t
* dnp
= NULL
;
521 #if defined SPLIT_DEVS
523 * If we have a prototype, then check if there is already a sibling
524 * on the mount plane we are looking at, if so, just return it.
527 dnp
= proto
->dn_nextsibling
;
528 while (dnp
!= proto
) {
529 if (dnp
->dn_dvm
== dvm
) {
533 dnp
= dnp
->dn_nextsibling
;
535 if (typeinfo
== NULL
) {
536 typeinfo
= &(proto
->dn_typeinfo
);
539 #else /* SPLIT_DEVS */
541 switch (proto
->type
) {
548 #endif /* SPLIT_DEVS */
549 MALLOC(dnp
, devnode_t
*, sizeof(devnode_t
), M_DEVFSNODE
, M_WAITOK
);
555 * If we have a proto, that means that we are duplicating some
556 * other device, which can only happen if we are not at the back plane
559 bcopy(proto
, dnp
, sizeof(devnode_t
));
561 dnp
->dn_linklist
= NULL
;
564 /* add to END of siblings list */
565 dnp
->dn_prevsiblingp
= proto
->dn_prevsiblingp
;
566 *(dnp
->dn_prevsiblingp
) = dnp
;
567 dnp
->dn_nextsibling
= proto
;
568 proto
->dn_prevsiblingp
= &(dnp
->dn_nextsibling
);
570 mac_devfs_label_init(dnp
);
571 mac_devfs_label_copy(proto
->dn_label
, dnp
->dn_label
);
577 * We have no prototype, so start off with a clean slate
580 bzero(dnp
, sizeof(devnode_t
));
581 dnp
->dn_type
= entrytype
;
582 dnp
->dn_nextsibling
= dnp
;
583 dnp
->dn_prevsiblingp
= &(dnp
->dn_nextsibling
);
584 dnp
->dn_atime
.tv_sec
= tv
.tv_sec
;
585 dnp
->dn_mtime
.tv_sec
= tv
.tv_sec
;
586 dnp
->dn_ctime
.tv_sec
= tv
.tv_sec
;
588 mac_devfs_label_init(dnp
);
593 /* Note: this inits the reference count to 1, this is considered unreferenced */
594 os_ref_init_raw(&dnp
->dn_refcount
, &devfs_refgrp
);
595 dnp
->dn_ino
= devfs_unique_fileno
;
596 devfs_unique_fileno
++;
599 * fill out the dev node according to type
604 * As it's a directory, make sure
605 * it has a null entries list
607 dnp
->dn_typeinfo
.Dir
.dirlast
= &(dnp
->dn_typeinfo
.Dir
.dirlist
);
608 dnp
->dn_typeinfo
.Dir
.dirlist
= (devdirent_t
*)0;
609 dnp
->dn_typeinfo
.Dir
.entrycount
= 0;
610 /* until we know better, it has a null parent pointer*/
611 dnp
->dn_typeinfo
.Dir
.parent
= NULL
;
612 dnp
->dn_links
++; /* for .*/
613 dnp
->dn_typeinfo
.Dir
.myname
= NULL
;
615 * make sure that the ops associated with it are the ops
616 * that we use (by default) for directories
618 dnp
->dn_ops
= &devfs_vnodeop_p
;
619 dnp
->dn_mode
|= 0555; /* default perms */
623 * As it's a symlink allocate and store the link info
624 * Symlinks should only ever be created by the user,
625 * so they are not on the back plane and should not be
626 * propogated forward.. a bit like directories in that way..
627 * A symlink only exists on one plane and has its own
628 * node.. therefore we might be on any random plane.
630 MALLOC(dnp
->dn_typeinfo
.Slnk
.name
, char *,
631 typeinfo
->Slnk
.namelen
+ 1,
632 M_DEVFSNODE
, M_WAITOK
);
633 if (!dnp
->dn_typeinfo
.Slnk
.name
) {
637 strlcpy(dnp
->dn_typeinfo
.Slnk
.name
, typeinfo
->Slnk
.name
,
638 typeinfo
->Slnk
.namelen
+ 1);
639 dnp
->dn_typeinfo
.Slnk
.namelen
= typeinfo
->Slnk
.namelen
;
640 DEVFS_INCR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen
+ 1);
641 dnp
->dn_ops
= &devfs_vnodeop_p
;
642 dnp
->dn_mode
|= 0555; /* default perms */
647 * Make sure it has DEVICE type ops
648 * and device specific fields are correct
650 dnp
->dn_ops
= &devfs_spec_vnodeop_p
;
651 dnp
->dn_typeinfo
.dev
= typeinfo
->dev
;
655 /* /dev/fd is special */
657 dnp
->dn_ops
= &devfs_devfd_vnodeop_p
;
658 dnp
->dn_mode
|= 0555; /* default perms */
667 FREE(dnp
, M_DEVFSNODE
);
677 /***********************************************************************
678 * called with DEVFS_LOCK held
679 **********************************************************************/
681 devnode_free(devnode_t
* dnp
)
684 mac_devfs_label_destroy(dnp
);
686 if (dnp
->dn_type
== DEV_SLNK
) {
687 DEVFS_DECR_STRINGSPACE(dnp
->dn_typeinfo
.Slnk
.namelen
+ 1);
688 FREE(dnp
->dn_typeinfo
.Slnk
.name
, M_DEVFSNODE
);
691 FREE(dnp
, M_DEVFSNODE
);
695 /***********************************************************************
696 * called with DEVFS_LOCK held
697 **********************************************************************/
699 devfs_dn_free(devnode_t
* dnp
)
701 if (--dnp
->dn_links
<= 0) { /* can be -1 for initial free, on error */
702 /*probably need to do other cleanups XXX */
703 if (dnp
->dn_nextsibling
!= dnp
) {
704 devnode_t
* * prevp
= dnp
->dn_prevsiblingp
;
705 *prevp
= dnp
->dn_nextsibling
;
706 dnp
->dn_nextsibling
->dn_prevsiblingp
= prevp
;
709 /* Can only free if there are no references; otherwise, wait for last vnode to be reclaimed */
710 os_ref_count_t rc
= os_ref_get_count_raw(&dnp
->dn_refcount
);
712 /* release final reference from dev_add_node */
713 (void) os_ref_release_locked_raw(&dnp
->dn_refcount
, &devfs_refgrp
);
716 dnp
->dn_lflags
|= DN_DELETE
;
721 /***********************************************************************\
722 * Front Node Operations *
723 * Add or delete a chain of front nodes *
724 \***********************************************************************/
727 /***********************************************************************
728 * Given a directory backing node, and a child backing node, add the
729 * appropriate front nodes to the front nodes of the directory to
730 * represent the child node to the user
732 * on failure, front nodes will either be correct or not exist for each
733 * front dir, however dirs completed will not be stripped of completed
734 * frontnodes on failure of a later frontnode
736 * This allows a new node to be propogated through all mounted planes
738 * called with DEVFS_LOCK held
739 ***********************************************************************/
741 devfs_propogate(devdirent_t
* parent
, devdirent_t
* child
, devfs_event_log_t delp
)
744 devdirent_t
* newnmp
;
745 devnode_t
* dnp
= child
->de_dnp
;
746 devnode_t
* pdnp
= parent
->de_dnp
;
747 devnode_t
* adnp
= parent
->de_dnp
;
748 int type
= child
->de_dnp
->dn_type
;
751 events
= (dnp
->dn_type
== DEV_DIR
? VNODE_EVENT_DIR_CREATED
: VNODE_EVENT_FILE_CREATED
);
753 devfs_record_event(delp
, pdnp
, events
);
756 /***********************************************
757 * Find the other instances of the parent node
758 ***********************************************/
759 for (adnp
= pdnp
->dn_nextsibling
;
761 adnp
= adnp
->dn_nextsibling
) {
763 * Make the node, using the original as a prototype)
764 * if the node already exists on that plane it won't be
767 if ((error
= dev_add_entry(child
->de_name
, adnp
, type
,
768 NULL
, dnp
, adnp
->dn_dvm
,
770 printf("duplicating %s failed\n", child
->de_name
);
773 devfs_record_event(delp
, adnp
, events
);
776 * Slightly subtle. We're guaranteed that there will
777 * only be a vnode hooked into this devnode if we're creating
778 * a new link to an existing node; otherwise, the devnode is new
779 * and no one can have looked it up yet. If we're making a link,
780 * then the buffer is large enough for two nodes in each
781 * plane; otherwise, there's no vnode and this call will
784 devfs_record_event(delp
, newnmp
->de_dnp
, VNODE_EVENT_LINK
);
788 return 0; /* for now always succeed */
792 remove_notify_count(devnode_t
*dnp
)
794 uint32_t notify_count
= 0;
798 * Could need to notify for one removed node on each mount and
799 * one parent for each such node.
801 notify_count
= devfs_nmountplanes
;
802 notify_count
+= dnp
->dn_links
;
803 for (dnp2
= dnp
->dn_nextsibling
; dnp2
!= dnp
; dnp2
= dnp2
->dn_nextsibling
) {
804 notify_count
+= dnp2
->dn_links
;
810 /***********************************************************************
811 * remove all instances of this devicename [for backing nodes..]
812 * note.. if there is another link to the node (non dir nodes only)
813 * then the devfs_node will still exist as the ref count will be non-0
814 * removing a directory node will remove all sup-nodes on all planes (ZAP)
816 * Used by device drivers to remove nodes that are no longer relevant
817 * The argument is the 'cookie' they were given when they created the node
818 * this function is exported.. see devfs.h
819 ***********************************************************************/
821 devfs_remove(void *dirent_p
)
823 devnode_t
* dnp
= ((devdirent_t
*)dirent_p
)->de_dnp
;
826 struct devfs_event_log event_log
;
827 uint32_t log_count
= 0;
830 struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
];
835 printf("devfs_remove: not ready for devices!\n");
839 log_count
= remove_notify_count(dnp
);
841 if (log_count
> NUM_STACK_ENTRIES
) {
845 if (devfs_init_event_log(&event_log
, log_count
, NULL
) == 0) {
851 new_count
= remove_notify_count(dnp
);
852 if (need_free
&& (new_count
> log_count
)) {
853 devfs_release_event_log(&event_log
, 1);
856 log_count
= log_count
* 2;
860 if (devfs_init_event_log(&event_log
, NUM_STACK_ENTRIES
, &stackbuf
[0]) == 0) {
865 /* This file has been deleted */
866 if (do_notify
!= 0) {
867 devfs_record_event(&event_log
, dnp
, VNODE_EVENT_DELETE
);
870 /* keep removing the next sibling till only we exist. */
871 while ((dnp2
= dnp
->dn_nextsibling
) != dnp
) {
873 * Keep removing the next front node till no more exist
875 dnp
->dn_nextsibling
= dnp2
->dn_nextsibling
;
876 dnp
->dn_nextsibling
->dn_prevsiblingp
= &(dnp
->dn_nextsibling
);
877 dnp2
->dn_nextsibling
= dnp2
;
878 dnp2
->dn_prevsiblingp
= &(dnp2
->dn_nextsibling
);
880 /* This file has been deleted in this plane */
881 if (do_notify
!= 0) {
882 devfs_record_event(&event_log
, dnp2
, VNODE_EVENT_DELETE
);
885 if (dnp2
->dn_linklist
) {
887 lastlink
= (1 == dnp2
->dn_links
);
888 /* Each parent of a link to this file has lost a child in this plane */
889 if (do_notify
!= 0) {
890 devfs_record_event(&event_log
, dnp2
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
);
892 dev_free_name(dnp2
->dn_linklist
);
898 * then free the main node
899 * If we are not running in SPLIT_DEVS mode, then
900 * THIS is what gets rid of the propogated nodes.
902 if (dnp
->dn_linklist
) {
904 lastlink
= (1 == dnp
->dn_links
);
905 /* Each parent of a link to this file has lost a child */
906 if (do_notify
!= 0) {
907 devfs_record_event(&event_log
, dnp
->dn_linklist
->de_parent
, VNODE_EVENT_FILE_REMOVED
);
909 dev_free_name(dnp
->dn_linklist
);
914 if (do_notify
!= 0) {
915 devfs_bulk_notify(&event_log
);
916 devfs_release_event_log(&event_log
, need_free
);
924 /***************************************************************
925 * duplicate the backing tree into a tree of nodes hung off the
926 * mount point given as the argument. Do this by
927 * calling dev_dup_entry which recurses all the way
930 * called with DEVFS_LOCK held
931 **************************************************************/
933 dev_dup_plane(struct devfsmount
*devfs_mp_p
)
938 if ((error
= dev_dup_entry(NULL
, dev_root
, &new, devfs_mp_p
))) {
941 devfs_mp_p
->plane_root
= new;
942 devfs_nmountplanes
++;
948 /***************************************************************
951 * called with DEVFS_LOCK held
952 ***************************************************************/
954 devfs_free_plane(struct devfsmount
*devfs_mp_p
)
956 devdirent_t
* dirent_p
;
958 dirent_p
= devfs_mp_p
->plane_root
;
960 dev_free_hier(dirent_p
);
961 dev_free_name(dirent_p
);
963 devfs_mp_p
->plane_root
= NULL
;
964 devfs_nmountplanes
--;
966 if (devfs_nmountplanes
> (devfs_nmountplanes
+ 1)) {
967 panic("plane count wrapped around.\n");
972 /***************************************************************
973 * Create and link in a new front element..
974 * Parent can be 0 for a root node
975 * Not presently usable to make a symlink XXX
976 * (Ok, symlinks don't propogate)
977 * recursively will create subnodes corresponding to equivalent
978 * child nodes in the base level
980 * called with DEVFS_LOCK held
981 ***************************************************************/
983 dev_dup_entry(devnode_t
* parent
, devdirent_t
* back
, devdirent_t
* *dnm_pp
,
984 struct devfsmount
*dvm
)
986 devdirent_t
* entry_p
= NULL
;
987 devdirent_t
* newback
;
988 devdirent_t
* newfront
;
990 devnode_t
* dnp
= back
->de_dnp
;
991 int type
= dnp
->dn_type
;
994 * go get the node made (if we need to)
995 * use the back one as a prototype
997 error
= dev_add_entry(back
->de_name
, parent
, type
, NULL
, dnp
,
998 parent
?parent
->dn_dvm
:dvm
, &entry_p
);
999 if (!error
&& (entry_p
== NULL
)) {
1000 error
= ENOMEM
; /* Really can't happen, but make static analyzer happy */
1003 printf("duplicating %s failed\n", back
->de_name
);
1008 * If we have just made the root, then insert the pointer to the
1012 entry_p
->de_dnp
->dn_dvm
= dvm
;
1016 * If it is a directory, then recurse down all the other
1017 * subnodes in it....
1018 * note that this time we don't pass on the mount info..
1020 if (type
== DEV_DIR
) {
1021 for (newback
= back
->de_dnp
->dn_typeinfo
.Dir
.dirlist
;
1022 newback
; newback
= newback
->de_next
) {
1023 if ((error
= dev_dup_entry(entry_p
->de_dnp
,
1024 newback
, &newfront
, NULL
)) != 0) {
1025 break; /* back out with an error */
1035 /***************************************************************
1037 * remember that if there are other names pointing to the
1038 * dev_node then it may not get freed yet
1039 * can handle if there is no dnp
1041 * called with DEVFS_LOCK held
1042 ***************************************************************/
1045 dev_free_name(devdirent_t
* dirent_p
)
1047 devnode_t
* parent
= dirent_p
->de_parent
;
1048 devnode_t
* dnp
= dirent_p
->de_dnp
;
1051 if (dnp
->dn_type
== DEV_DIR
) {
1054 if (dnp
->dn_typeinfo
.Dir
.dirlist
) {
1057 p
= dnp
->dn_typeinfo
.Dir
.parent
;
1058 devfs_dn_free(dnp
); /* account for '.' */
1059 devfs_dn_free(p
); /* '..' */
1062 * unlink us from the list of links for this node
1063 * If we are the only link, it's easy!
1064 * if we are a DIR of course there should not be any
1067 if (dirent_p
->de_nextlink
== dirent_p
) {
1068 dnp
->dn_linklist
= NULL
;
1070 if (dnp
->dn_linklist
== dirent_p
) {
1071 dnp
->dn_linklist
= dirent_p
->de_nextlink
;
1077 dirent_p
->de_nextlink
->de_prevlinkp
= dirent_p
->de_prevlinkp
;
1078 *(dirent_p
->de_prevlinkp
) = dirent_p
->de_nextlink
;
1081 * unlink ourselves from the directory on this plane
1083 if (parent
) { /* if not fs root */
1084 if ((*dirent_p
->de_prevp
= dirent_p
->de_next
)) {/* yes, assign */
1085 dirent_p
->de_next
->de_prevp
= dirent_p
->de_prevp
;
1087 parent
->dn_typeinfo
.Dir
.dirlast
1088 = dirent_p
->de_prevp
;
1090 parent
->dn_typeinfo
.Dir
.entrycount
--;
1091 parent
->dn_len
-= strlen(dirent_p
->de_name
) + 8;
1094 DEVFS_DECR_ENTRIES();
1095 FREE(dirent_p
, M_DEVFSNAME
);
1100 /***************************************************************
1101 * Free a hierarchy starting at a directory node name
1102 * remember that if there are other names pointing to the
1103 * dev_node then it may not get freed yet
1104 * can handle if there is no dnp
1105 * leave the node itself allocated.
1107 * called with DEVFS_LOCK held
1108 ***************************************************************/
1111 dev_free_hier(devdirent_t
* dirent_p
)
1113 devnode_t
* dnp
= dirent_p
->de_dnp
;
1116 if (dnp
->dn_type
== DEV_DIR
) {
1117 while (dnp
->dn_typeinfo
.Dir
.dirlist
) {
1118 dev_free_hier(dnp
->dn_typeinfo
.Dir
.dirlist
);
1119 dev_free_name(dnp
->dn_typeinfo
.Dir
.dirlist
);
1126 /***************************************************************
1127 * given a dev_node, find the appropriate vnode if one is already
1128 * associated, or get a new one and associate it with the dev_node
1130 * called with DEVFS_LOCK held
1132 * If an error is returned, then the dnp may have been freed (we
1133 * raced with a delete and lost). A devnode should not be accessed
1134 * after devfs_dntovn() fails.
1135 ****************************************************************/
1137 devfs_dntovn(devnode_t
* dnp
, struct vnode
**vn_pp
, __unused
struct proc
* p
)
1141 struct vnode_fsparam vfsp
;
1142 enum vtype vtype
= 0;
1145 int n_minor
= DEVFS_CLONE_ALLOC
; /* new minor number for clone device */
1148 * We should never come in and find that our devnode has been marked for delete.
1149 * The lookup should have held the lock from entry until now; it should not have
1150 * been able to find a removed entry. Any other pathway would have just created
1151 * the devnode and come here without dropping the devfs lock, so no one would
1152 * have a chance to delete.
1154 if (dnp
->dn_lflags
& DN_DELETE
) {
1155 panic("devfs_dntovn: DN_DELETE set on a devnode upon entry.");
1158 devfs_ref_node(dnp
);
1164 if (vn_p
) { /* already has a vnode */
1167 vid
= vnode_vid(vn_p
);
1172 * We want to use the drainok variant of vnode_getwithvid
1173 * because we _don't_ want to get an iocount if the vnode is
1174 * is blocked in vnode_drain as it can cause infinite
1175 * loops in vn_open_auth. While in use vnodes are typically
1176 * only reclaimed on forced unmounts, In use devfs tty vnodes
1177 * can be quite frequently reclaimed by revoke(2) or by the
1178 * exit of a controlling process.
1180 error
= vnode_getwithvid_drainok(vn_p
, vid
);
1184 if (dnp
->dn_lflags
& DN_DELETE
) {
1186 * our BUSY node got marked for
1187 * deletion while the DEVFS lock
1192 * vnode_getwithvid returned a valid ref
1193 * which we need to drop
1199 * This entry is no longer in the namespace. This is only
1200 * possible for lookup: no other path would not find an existing
1201 * vnode. Therefore, ENOENT is a valid result.
1204 } else if (error
== ENODEV
) {
1206 * The Filesystem is getting unmounted.
1209 } else if (error
&& (nretries
< DEV_MAX_VNODE_RETRY
)) {
1211 * If we got an error from vnode_getwithvid, it means
1212 * we raced with a recycle and lost i.e. we asked for
1213 * an iocount only after vnode_drain had been entered
1214 * for the vnode and returned with an error only after
1215 * devfs_reclaim was called on the vnode. devfs_reclaim
1216 * sets dn_vn to NULL but while we were waiting to
1217 * reacquire DEVFS_LOCK, another vnode might have gotten
1218 * associated with the dnp. In either case, we need to
1219 * retry otherwise we will end up returning an ENOENT
1220 * for this lookup but the next lookup will succeed
1221 * because it creates a new vnode (or a racing lookup
1222 * created a new vnode already).
1236 * If we get here, then we've beaten any deletes;
1237 * if someone sets DN_DELETE during a subsequent drop
1238 * of the devfs lock, we'll still vend a vnode.
1241 if (dnp
->dn_lflags
& DN_CREATE
) {
1242 dnp
->dn_lflags
|= DN_CREATEWAIT
;
1243 msleep(&dnp
->dn_lflags
, &devfs_mutex
, PRIBIO
, 0, 0);
1247 dnp
->dn_lflags
|= DN_CREATE
;
1249 switch (dnp
->dn_type
) {
1254 if (dnp
->dn_typeinfo
.Dir
.parent
== dnp
) {
1261 vtype
= (dnp
->dn_type
== DEV_BDEV
) ? VBLK
: VCHR
;
1269 vfsp
.vnfs_mp
= dnp
->dn_dvm
->mount
;
1270 vfsp
.vnfs_vtype
= vtype
;
1271 vfsp
.vnfs_str
= "devfs";
1273 vfsp
.vnfs_fsnode
= dnp
;
1275 vfsp
.vnfs_vops
= *(dnp
->dn_ops
);
1277 if (vtype
== VBLK
|| vtype
== VCHR
) {
1279 * Ask the clone minor number function for a new minor number
1280 * to use for the next device instance. If an administative
1281 * limit has been reached, this function will return -1.
1283 if (dnp
->dn_clone
!= NULL
) {
1284 int n_major
= major(dnp
->dn_typeinfo
.dev
);
1286 n_minor
= (*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_ALLOC
);
1287 if (n_minor
== -1) {
1292 vfsp
.vnfs_rdev
= makedev(n_major
, n_minor
);;
1294 vfsp
.vnfs_rdev
= dnp
->dn_typeinfo
.dev
;
1299 vfsp
.vnfs_filesize
= 0;
1300 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
1301 /* Tag system files */
1302 vfsp
.vnfs_marksystem
= 0;
1303 vfsp
.vnfs_markroot
= markroot
;
1307 error
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &vn_p
);
1309 /* Do this before grabbing the lock */
1311 vnode_setneedinactive(vn_p
);
1317 vnode_settag(vn_p
, VT_DEVFS
);
1319 if ((dnp
->dn_clone
!= NULL
) && (dnp
->dn_vn
!= NULLVP
)) {
1320 panic("devfs_dntovn: cloning device with a vnode?\n");
1326 * Another vnode that has this devnode as its v_data.
1327 * This reference, unlike the one taken at the start
1328 * of the function, persists until a VNOP_RECLAIM
1329 * comes through for this vnode.
1331 devfs_ref_node(dnp
);
1334 * A cloned vnode is not hooked into the devnode; every lookup
1337 if (dnp
->dn_clone
== NULL
) {
1340 } else if (n_minor
!= DEVFS_CLONE_ALLOC
) {
1342 * If we failed the create, we need to release the cloned minor
1343 * back to the free list. In general, this is only useful if
1344 * the clone function results in a state change in the cloned
1345 * device for which the minor number was obtained. If we get
1346 * past this point withouth falling into this case, it's
1347 * assumed that any state to be released will be released when
1348 * the vnode is dropped, instead.
1350 (void)(*dnp
->dn_clone
)(dnp
->dn_typeinfo
.dev
, DEVFS_CLONE_FREE
);
1353 dnp
->dn_lflags
&= ~DN_CREATE
;
1354 if (dnp
->dn_lflags
& DN_CREATEWAIT
) {
1355 dnp
->dn_lflags
&= ~DN_CREATEWAIT
;
1356 wakeup(&dnp
->dn_lflags
);
1361 * Release the reference we took to prevent deletion while we weren't holding the lock.
1362 * If not returning success, then dropping this reference could delete the devnode;
1363 * no one should access a devnode after a call to devfs_dntovn fails.
1365 devfs_rele_node(dnp
);
1371 * Increment refcount on a devnode; prevents free of the node
1372 * while the devfs lock is not held.
1375 devfs_ref_node(devnode_t
*dnp
)
1377 os_ref_retain_locked_raw(&dnp
->dn_refcount
, &devfs_refgrp
);
1381 * Release a reference on a devnode. If the devnode is marked for
1382 * free and the refcount is dropped to one, do the free.
1385 devfs_rele_node(devnode_t
*dnp
)
1387 os_ref_count_t rc
= os_ref_release_locked_raw(&dnp
->dn_refcount
, &devfs_refgrp
);
1389 panic("devfs_rele_node: devnode without a refcount!\n");
1390 } else if ((rc
== 1) && (dnp
->dn_lflags
& DN_DELETE
)) {
1391 /* release final reference from dev_add_node */
1392 (void) os_ref_release_locked_raw(&dnp
->dn_refcount
, &devfs_refgrp
);
1397 /***********************************************************************
1398 * add a whole device, with no prototype.. make name element and node
1399 * Used for adding the original device entries
1401 * called with DEVFS_LOCK held
1402 ***********************************************************************/
1404 dev_add_entry(const char *name
, devnode_t
* parent
, int type
, devnode_type_t
* typeinfo
,
1405 devnode_t
* proto
, struct devfsmount
*dvm
, devdirent_t
* *nm_pp
)
1410 if ((error
= dev_add_node(type
, typeinfo
, proto
, &dnp
,
1411 (parent
?parent
->dn_dvm
:dvm
))) != 0) {
1412 printf("devfs: %s: base node allocation failed (Errno=%d)\n",
1416 if ((error
= dev_add_name(name
, parent
, NULL
, dnp
, nm_pp
)) != 0) {
1417 devfs_dn_free(dnp
); /* 1->0 for dir, 0->(-1) for other */
1418 printf("devfs: %s: name slot allocation failed (Errno=%d)\n",
1425 devfs_bulk_notify(devfs_event_log_t delp
)
1428 for (i
= 0; i
< delp
->del_used
; i
++) {
1429 devfs_vnode_event_t dvep
= &delp
->del_entries
[i
];
1430 if (vnode_getwithvid(dvep
->dve_vp
, dvep
->dve_vid
) == 0) {
1431 vnode_notify(dvep
->dve_vp
, dvep
->dve_events
, NULL
);
1432 vnode_put(dvep
->dve_vp
);
1438 devfs_record_event(devfs_event_log_t delp
, devnode_t
*dnp
, uint32_t events
)
1440 if (delp
->del_used
>= delp
->del_max
) {
1441 panic("devfs event log overflowed.\n");
1444 /* Can only notify for nodes that have an associated vnode */
1445 if (dnp
->dn_vn
!= NULLVP
&& vnode_ismonitored(dnp
->dn_vn
)) {
1446 devfs_vnode_event_t dvep
= &delp
->del_entries
[delp
->del_used
];
1447 dvep
->dve_vp
= dnp
->dn_vn
;
1448 dvep
->dve_vid
= vnode_vid(dnp
->dn_vn
);
1449 dvep
->dve_events
= events
;
1455 devfs_init_event_log(devfs_event_log_t delp
, uint32_t count
, devfs_vnode_event_t buf
)
1457 devfs_vnode_event_t dvearr
;
1460 MALLOC(dvearr
, devfs_vnode_event_t
, count
* sizeof(struct devfs_vnode_event
), M_TEMP
, M_WAITOK
| M_ZERO
);
1461 if (dvearr
== NULL
) {
1468 delp
->del_max
= count
;
1470 delp
->del_entries
= dvearr
;
1475 devfs_release_event_log(devfs_event_log_t delp
, int need_free
)
1477 if (delp
->del_entries
== NULL
) {
1478 panic("Free of devfs notify info that has not been intialized.\n");
1482 FREE(delp
->del_entries
, M_TEMP
);
1485 delp
->del_entries
= NULL
;
1489 * Function: devfs_make_node
1492 * Create a device node with the given pathname in the devfs namespace.
1495 * dev - the dev_t value to associate
1496 * chrblk - block or character device (DEVFS_CHAR or DEVFS_BLOCK)
1497 * uid, gid - ownership
1498 * perms - permissions
1499 * clone - minor number cloning function
1500 * fmt, ... - path format string with printf args to format the path name
1502 * A handle to a device node if successful, NULL otherwise.
1505 devfs_make_node_clone(dev_t dev
, int chrblk
, uid_t uid
,
1506 gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
),
1507 const char *fmt
, ...)
1509 devdirent_t
* new_dev
= NULL
;
1525 new_dev
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, clone
, fmt
, ap
);
1533 * Function: devfs_make_node
1536 * Create a device node with the given pathname in the devfs namespace.
1539 * dev - the dev_t value to associate
1540 * chrblk - block or character device (DEVFS_CHAR or DEVFS_BLOCK)
1541 * uid, gid - ownership
1542 * perms - permissions
1543 * fmt, ... - path format string with printf args to format the path name
1545 * A handle to a device node if successful, NULL otherwise.
1548 devfs_make_node(dev_t dev
, int chrblk
, uid_t uid
,
1549 gid_t gid
, int perms
, const char *fmt
, ...)
1551 devdirent_t
* new_dev
= NULL
;
1555 if (chrblk
!= DEVFS_CHAR
&& chrblk
!= DEVFS_BLOCK
) {
1559 type
= (chrblk
== DEVFS_BLOCK
? DEV_BDEV
: DEV_CDEV
);
1562 new_dev
= devfs_make_node_internal(dev
, type
, uid
, gid
, perms
, NULL
, fmt
, ap
);
1569 static devdirent_t
*
1570 devfs_make_node_internal(dev_t dev
, devfstype_t type
, uid_t uid
,
1571 gid_t gid
, int perms
, int (*clone
)(dev_t dev
, int action
), const char *fmt
, va_list ap
)
1573 devdirent_t
* new_dev
= NULL
;
1575 devnode_type_t typeinfo
;
1577 char *name
, buf
[256]; /* XXX */
1580 char buff
[sizeof(buf
)];
1584 struct devfs_event_log event_log
;
1585 struct devfs_vnode_event stackbuf
[NUM_STACK_ENTRIES
];
1588 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1591 bcopy(buf
, buff
, sizeof(buff
));
1592 buff
[sizeof(buff
) - 1] = 0;
1596 for (i
= strlen(buf
); i
> 0; i
--) {
1597 if (buf
[i
] == '/') {
1612 log_count
= devfs_nmountplanes
;
1613 if (log_count
> NUM_STACK_ENTRIES
) {
1616 if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) {
1621 log_count
= NUM_STACK_ENTRIES
;
1622 if (devfs_init_event_log(&event_log
, log_count
, &stackbuf
[0]) != 0) {
1628 if (log_count
< devfs_nmountplanes
) {
1630 devfs_release_event_log(&event_log
, need_free
);
1631 log_count
= log_count
* 2;
1636 printf("devfs_make_node: not ready for devices!\n");
1640 /* find/create directory path ie. mkdir -p */
1641 if (dev_finddir(path
, NULL
, DEVFS_CREATE
, &dnp
, &event_log
) == 0) {
1643 if (dev_add_entry(name
, dnp
, type
, &typeinfo
, NULL
, NULL
, &new_dev
) == 0) {
1644 new_dev
->de_dnp
->dn_gid
= gid
;
1645 new_dev
->de_dnp
->dn_uid
= uid
;
1646 new_dev
->de_dnp
->dn_mode
|= perms
;
1647 new_dev
->de_dnp
->dn_clone
= clone
;
1649 mac_devfs_label_associate_device(dev
, new_dev
->de_dnp
, buff
);
1651 devfs_propogate(dnp
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
);
1658 devfs_bulk_notify(&event_log
);
1659 devfs_release_event_log(&event_log
, need_free
);
1664 * Function: devfs_make_link
1667 * Create a link to a previously created device node.
1670 * 0 if successful, -1 if failed
1673 devfs_make_link(void *original
, char *fmt
, ...)
1675 devdirent_t
* new_dev
= NULL
;
1676 devdirent_t
* orig
= (devdirent_t
*) original
;
1677 devnode_t
* dirnode
; /* devnode for parent directory */
1678 struct devfs_event_log event_log
;
1682 char *p
, buf
[256]; /* XXX */
1689 printf("devfs_make_link: not ready for devices!\n");
1695 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1700 for (i
= strlen(buf
); i
> 0; i
--) {
1701 if (buf
[i
] == '/') {
1709 * One slot for each directory, one for each devnode
1710 * whose link count changes
1712 log_count
= devfs_nmountplanes
* 2;
1714 if (devfs_init_event_log(&event_log
, log_count
, NULL
) != 0) {
1715 /* No lock held, no allocations done, can just return */
1721 if (log_count
< devfs_nmountplanes
) {
1723 devfs_release_event_log(&event_log
, 1);
1724 log_count
= log_count
* 2;
1731 if (dev_finddir(buf
, NULL
, DEVFS_CREATE
, &dirnode
, &event_log
)
1732 || dev_add_name(p
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) {
1736 if (dev_finddir("", NULL
, DEVFS_CREATE
, &dirnode
, &event_log
)
1737 || dev_add_name(buf
, dirnode
, NULL
, orig
->de_dnp
, &new_dev
)) {
1741 devfs_propogate(dirnode
->dn_typeinfo
.Dir
.myname
, new_dev
, &event_log
);
1744 devfs_bulk_notify(&event_log
);
1745 devfs_release_event_log(&event_log
, 1);
1747 return (new_dev
!= NULL
) ? 0 : -1;