]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/devfs/devfs_tree.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_tree.c
1 /*
2 * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * Copyright 1997,1998 Julian Elischer. All rights reserved.
31 * julian@freebsd.org
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are
35 * met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright notice,
39 * this list of conditions and the following disclaimer in the documentation
40 * and/or other materials provided with the distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
43 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
44 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
46 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * devfs_tree.c
55 */
56 /*
57 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 */
62
63 /*
64 * HISTORY
65 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999
66 * - removed mounting of "hidden" mountpoint
67 * - fixed problem in which devnode->dn_vn pointer was not
68 * updated with the vnode returned from checkalias()
69 * - replaced devfs_vntodn() with a macro VTODN()
70 * - rewrote dev_finddir() to not use recursion
71 * - added locking to avoid data structure corruption (DEVFS_(UN)LOCK())
72 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999
73 * - fixed problem with devfs_dntovn() checking the v_id against the
74 * value cached in the device node; a union mount on top of us causes
75 * the v_id to get incremented thus, we would end up returning a new
76 * vnode instead of the existing one that has the mounted_here
77 * field filled in; the net effect was that the filesystem mounted
78 * on top of us would never show up
79 * - added devfs_stats to store how many data structures are actually
80 * allocated
81 */
82
83 /* SPLIT_DEVS means each devfs uses a different devnode for the same device */
84 /* Otherwise the same device always ends up at the same vnode even if */
85 /* reached througgh a different devfs instance. The practical difference */
86 /* is that with the same vnode, chmods and chowns show up on all instances of */
87 /* a device. (etc) */
88
89 #define SPLIT_DEVS 1 /* maybe make this an option */
90 /*#define SPLIT_DEVS 1*/
91
92 #include <sys/param.h>
93 #include <sys/systm.h>
94 #include <sys/kernel.h>
95 #include <sys/conf.h>
96 #include <sys/malloc.h>
97 #include <sys/mount_internal.h>
98 #include <sys/proc.h>
99 #include <sys/vnode_internal.h>
100 #include <stdarg.h>
101 #include <libkern/OSAtomic.h>
102 #include <os/refcnt.h>
103 #define BSD_KERNEL_PRIVATE 1 /* devfs_make_link() prototype */
104 #include "devfs.h"
105 #include "devfsdefs.h"
106
107 #if CONFIG_MACF
108 #include <security/mac_framework.h>
109 #endif
110
111 #if FDESC
112 #include "fdesc.h"
113 #endif
114
115 typedef struct devfs_vnode_event {
116 vnode_t dve_vp;
117 uint32_t dve_vid;
118 uint32_t dve_events;
119 } *devfs_vnode_event_t;
120
121 /*
122 * Size of stack buffer (fast path) for notifications. If
123 * the number of mounts is small, no need to malloc a buffer.
124 */
125 #define NUM_STACK_ENTRIES 5
126
127 typedef struct devfs_event_log {
128 size_t del_max;
129 size_t del_used;
130 devfs_vnode_event_t del_entries;
131 } *devfs_event_log_t;
132
133
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);
146
147
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;
153
154 os_refgrp_decl(static, devfs_refgrp, "devfs", NULL);
155
156 devdirent_t * dev_root = NULL; /* root of backing tree */
157 struct devfs_stats devfs_stats; /* hold stats */
158
159 static ino_t devfs_unique_fileno = 0;
160
161 #ifdef HIDDEN_MOUNTPOINT
162 static struct mount *devfs_hidden_mount;
163 #endif /* HIDDEN_MOINTPOINT */
164
165 static int devfs_ready = 0;
166 static uint32_t devfs_nmountplanes = 0; /* The first plane is not used for a mount */
167
168 #define DEVFS_NOCREATE FALSE
169 #define DEVFS_CREATE TRUE
170
171 /*
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
176 * been set up yet!
177 * DEVFS has a hidden mountpoint that is used as the anchor point
178 * for the internal 'blueprint' version of the dev filesystem tree.
179 */
180 /*proto*/
181 int
182 devfs_sinit(void)
183 {
184 int error;
185
186 devfs_lck_grp_attr = lck_grp_attr_alloc_init();
187 devfs_lck_grp = lck_grp_alloc_init("devfs_lock", devfs_lck_grp_attr);
188
189 devfs_lck_attr = lck_attr_alloc_init();
190
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);
193
194 DEVFS_LOCK();
195 error = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root);
196 DEVFS_UNLOCK();
197
198 if (error) {
199 printf("devfs_sinit: dev_add_entry failed ");
200 return ENOTSUP;
201 }
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);
208 #if CONFIG_MACF
209 mac_mount_label_init(devfs_hidden_mount);
210 mac_mount_label_associate(vfs_context_kernel(), devfs_hidden_mount);
211 #endif
212
213 /* Initialize the default IO constraints */
214 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
215 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
216 mp->mnt_ioflags = 0;
217 mp->mnt_realrootvp = NULLVP;
218 mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL;
219
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 */
224 #if CONFIG_MACF
225 mac_devfs_label_associate_directory("/", (int) strlen("/"),
226 dev_root->de_dnp, "/");
227 #endif
228 devfs_ready = 1;
229 return 0;
230 }
231
232 /***********************************************************************\
233 *************************************************************************
234 * Routines used to find our way to a point in the tree *
235 *************************************************************************
236 \***********************************************************************/
237
238
239
240 /***************************************************************
241 * Search down the linked list off a dir to find "name"
242 * return the devnode_t * for that node.
243 *
244 * called with DEVFS_LOCK held
245 ***************************************************************/
246 devdirent_t *
247 dev_findname(devnode_t * dir, const char *name)
248 {
249 devdirent_t * newfp;
250 if (dir->dn_type != DEV_DIR) {
251 return 0; /*XXX*/ /* printf?*/
252 }
253 if (name[0] == '.') {
254 if (name[1] == 0) {
255 return dir->dn_typeinfo.Dir.myname;
256 }
257 if ((name[1] == '.') && (name[2] == 0)) {
258 /* for root, .. == . */
259 return dir->dn_typeinfo.Dir.parent->dn_typeinfo.Dir.myname;
260 }
261 }
262 newfp = dir->dn_typeinfo.Dir.dirlist;
263
264 while (newfp) {
265 if (!(strncmp(name, newfp->de_name, sizeof(newfp->de_name)))) {
266 return newfp;
267 }
268 newfp = newfp->de_next;
269 }
270 return NULL;
271 }
272
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..
279 *
280 * called with DEVFS_LOCK held
281 ***********************************************************************/
282 static int
283 dev_finddir(const char * path,
284 devnode_t * dirnode,
285 int create,
286 devnode_t * * dn_pp,
287 devfs_event_log_t delp)
288 {
289 devnode_t * dnp = NULL;
290 int error = 0;
291 const char * scan;
292 #if CONFIG_MACF
293 char fullpath[DEVMAXPATHSIZE];
294 #endif
295
296
297 if (!dirnode) { /* dirnode == NULL means start at root */
298 dirnode = dev_root->de_dnp;
299 }
300
301 if (dirnode->dn_type != DEV_DIR) {
302 return ENOTDIR;
303 }
304
305 if (strlen(path) > (DEVMAXPATHSIZE - 1)) {
306 return ENAMETOOLONG;
307 }
308
309 #if CONFIG_MACF
310 strlcpy(fullpath, path, DEVMAXPATHSIZE);
311 #endif
312 scan = path;
313
314 while (*scan == '/') {
315 scan++;
316 }
317
318 *dn_pp = NULL;
319
320 while (1) {
321 char component[DEVMAXPATHSIZE];
322 devdirent_t * dirent_p;
323 const char * start;
324
325 if (*scan == 0) {
326 /* we hit the end of the string, we're done */
327 *dn_pp = dirnode;
328 break;
329 }
330 start = scan;
331 while (*scan != '/' && *scan) {
332 scan++;
333 }
334
335 strlcpy(component, start, (scan - start) + 1);
336 if (*scan == '/') {
337 scan++;
338 }
339
340 dirent_p = dev_findname(dirnode, component);
341 if (dirent_p) {
342 dnp = dirent_p->de_dnp;
343 if (dnp->dn_type != DEV_DIR) {
344 error = ENOTDIR;
345 break;
346 }
347 } else {
348 if (!create) {
349 error = ENOENT;
350 break;
351 }
352 error = dev_add_entry(component, dirnode,
353 DEV_DIR, NULL, NULL, NULL, &dirent_p);
354 if (error) {
355 break;
356 }
357 dnp = dirent_p->de_dnp;
358 #if CONFIG_MACF
359 mac_devfs_label_associate_directory(
360 dirnode->dn_typeinfo.Dir.myname->de_name,
361 (int) strlen(dirnode->dn_typeinfo.Dir.myname->de_name),
362 dnp, fullpath);
363 #endif
364 devfs_propogate(dirnode->dn_typeinfo.Dir.myname, dirent_p, delp);
365 }
366 dirnode = dnp; /* continue relative to this directory */
367 }
368 return error;
369 }
370
371
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
376 *
377 * Creates a name node, and links it to the supplied node
378 *
379 * called with DEVFS_LOCK held
380 ***********************************************************************/
381 int
382 dev_add_name(const char * name, devnode_t * dirnode, __unused devdirent_t * back,
383 devnode_t * dnp, devdirent_t * *dirent_pp)
384 {
385 devdirent_t * dirent_p = NULL;
386
387 if (dirnode != NULL) {
388 if (dirnode->dn_type != DEV_DIR) {
389 return ENOTDIR;
390 }
391
392 if (dev_findname(dirnode, name)) {
393 return EEXIST;
394 }
395 }
396 /*
397 * make sure the name is legal
398 * slightly misleading in the case of NULL
399 */
400 if (!name || (strlen(name) > (DEVMAXNAMESIZE - 1))) {
401 return ENAMETOOLONG;
402 }
403
404 /*
405 * Allocate and fill out a new directory entry
406 */
407 MALLOC(dirent_p, devdirent_t *, sizeof(devdirent_t),
408 M_DEVFSNAME, M_WAITOK);
409 if (!dirent_p) {
410 return ENOMEM;
411 }
412 bzero(dirent_p, sizeof(devdirent_t));
413
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 "); */
419 }
420
421 /*
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.
425 */
426 dirent_p->de_dnp = dnp;
427 dnp->dn_links++; /* implicit from our own name-node */
428
429 /*
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.
432 */
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;
438 } else {
439 dirent_p->de_nextlink = dirent_p;
440 dirent_p->de_prevlinkp = &(dirent_p->de_nextlink);
441 }
442 dnp->dn_linklist = dirent_p;
443
444 /*
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.
448 */
449 if (dnp->dn_type == DEV_DIR) {
450 dnp->dn_typeinfo.Dir.myname = dirent_p;
451 /*
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
456 */
457 if (dnp->dn_typeinfo.Dir.parent) {
458 dnp->dn_typeinfo.Dir.parent->dn_links--;
459 }
460 if (dirnode) {
461 dnp->dn_typeinfo.Dir.parent = dirnode;
462 } else {
463 dnp->dn_typeinfo.Dir.parent = dnp;
464 }
465 dnp->dn_typeinfo.Dir.parent->dn_links++; /* account for the new '..' */
466 }
467
468 /*
469 * put the name into the directory entry.
470 */
471 strlcpy(dirent_p->de_name, name, DEVMAXNAMESIZE);
472
473
474 /*
475 * Check if we are not making a root node..
476 * (i.e. have parent)
477 */
478 if (dirnode) {
479 /*
480 * Put it on the END of the linked list of directory entries
481 */
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 */
485 /*right?*/
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?*/
490 }
491
492 *dirent_pp = dirent_p;
493 DEVFS_INCR_ENTRIES();
494 return 0;
495 }
496
497
498 /***********************************************************************
499 * Add a new element to the devfs plane.
500 *
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
511 *
512 * called with DEVFS_LOCK held
513 ***********************************************************************/
514 int
515 dev_add_node(int entrytype, devnode_type_t * typeinfo, devnode_t * proto,
516 devnode_t * *dn_pp, struct devfsmount *dvm)
517 {
518 devnode_t * dnp = NULL;
519 int error = 0;
520
521 #if defined SPLIT_DEVS
522 /*
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.
525 */
526 if (proto) {
527 dnp = proto->dn_nextsibling;
528 while (dnp != proto) {
529 if (dnp->dn_dvm == dvm) {
530 *dn_pp = dnp;
531 return 0;
532 }
533 dnp = dnp->dn_nextsibling;
534 }
535 if (typeinfo == NULL) {
536 typeinfo = &(proto->dn_typeinfo);
537 }
538 }
539 #else /* SPLIT_DEVS */
540 if (proto) {
541 switch (proto->type) {
542 case DEV_BDEV:
543 case DEV_CDEV:
544 *dn_pp = proto;
545 return 0;
546 }
547 }
548 #endif /* SPLIT_DEVS */
549 MALLOC(dnp, devnode_t *, sizeof(devnode_t), M_DEVFSNODE, M_WAITOK);
550 if (!dnp) {
551 return ENOMEM;
552 }
553
554 /*
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
557 */
558 if (proto) {
559 bcopy(proto, dnp, sizeof(devnode_t));
560 dnp->dn_links = 0;
561 dnp->dn_linklist = NULL;
562 dnp->dn_vn = NULL;
563 dnp->dn_len = 0;
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);
569 #if CONFIG_MACF
570 mac_devfs_label_init(dnp);
571 mac_devfs_label_copy(proto->dn_label, dnp->dn_label);
572 #endif
573 } else {
574 struct timeval tv;
575
576 /*
577 * We have no prototype, so start off with a clean slate
578 */
579 microtime(&tv);
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;
587 #if CONFIG_MACF
588 mac_devfs_label_init(dnp);
589 #endif
590 }
591 dnp->dn_dvm = dvm;
592
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++;
597
598 /*
599 * fill out the dev node according to type
600 */
601 switch (entrytype) {
602 case DEV_DIR:
603 /*
604 * As it's a directory, make sure
605 * it has a null entries list
606 */
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;
614 /*
615 * make sure that the ops associated with it are the ops
616 * that we use (by default) for directories
617 */
618 dnp->dn_ops = &devfs_vnodeop_p;
619 dnp->dn_mode |= 0555; /* default perms */
620 break;
621 case DEV_SLNK:
622 /*
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.
629 */
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) {
634 error = ENOMEM;
635 break;
636 }
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 */
643 break;
644 case DEV_CDEV:
645 case DEV_BDEV:
646 /*
647 * Make sure it has DEVICE type ops
648 * and device specific fields are correct
649 */
650 dnp->dn_ops = &devfs_spec_vnodeop_p;
651 dnp->dn_typeinfo.dev = typeinfo->dev;
652 break;
653
654 #if FDESC
655 /* /dev/fd is special */
656 case DEV_DEVFD:
657 dnp->dn_ops = &devfs_devfd_vnodeop_p;
658 dnp->dn_mode |= 0555; /* default perms */
659 break;
660
661 #endif /* FDESC */
662 default:
663 error = EINVAL;
664 }
665
666 if (error) {
667 FREE(dnp, M_DEVFSNODE);
668 } else {
669 *dn_pp = dnp;
670 DEVFS_INCR_NODES();
671 }
672
673 return error;
674 }
675
676
677 /***********************************************************************
678 * called with DEVFS_LOCK held
679 **********************************************************************/
680 void
681 devnode_free(devnode_t * dnp)
682 {
683 #if CONFIG_MACF
684 mac_devfs_label_destroy(dnp);
685 #endif
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);
689 }
690 DEVFS_DECR_NODES();
691 FREE(dnp, M_DEVFSNODE);
692 }
693
694
695 /***********************************************************************
696 * called with DEVFS_LOCK held
697 **********************************************************************/
698 static void
699 devfs_dn_free(devnode_t * dnp)
700 {
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;
707 }
708
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);
711 if (rc == 1) {
712 /* release final reference from dev_add_node */
713 (void) os_ref_release_locked_raw(&dnp->dn_refcount, &devfs_refgrp);
714 devnode_free(dnp);
715 } else {
716 dnp->dn_lflags |= DN_DELETE;
717 }
718 }
719 }
720
721 /***********************************************************************\
722 * Front Node Operations *
723 * Add or delete a chain of front nodes *
724 \***********************************************************************/
725
726
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
731 *
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
735 *
736 * This allows a new node to be propogated through all mounted planes
737 *
738 * called with DEVFS_LOCK held
739 ***********************************************************************/
740 static int
741 devfs_propogate(devdirent_t * parent, devdirent_t * child, devfs_event_log_t delp)
742 {
743 int error;
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;
749 uint32_t events;
750
751 events = (dnp->dn_type == DEV_DIR ? VNODE_EVENT_DIR_CREATED : VNODE_EVENT_FILE_CREATED);
752 if (delp != NULL) {
753 devfs_record_event(delp, pdnp, events);
754 }
755
756 /***********************************************
757 * Find the other instances of the parent node
758 ***********************************************/
759 for (adnp = pdnp->dn_nextsibling;
760 adnp != pdnp;
761 adnp = adnp->dn_nextsibling) {
762 /*
763 * Make the node, using the original as a prototype)
764 * if the node already exists on that plane it won't be
765 * re-made..
766 */
767 if ((error = dev_add_entry(child->de_name, adnp, type,
768 NULL, dnp, adnp->dn_dvm,
769 &newnmp)) != 0) {
770 printf("duplicating %s failed\n", child->de_name);
771 } else {
772 if (delp != NULL) {
773 devfs_record_event(delp, adnp, events);
774
775 /*
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
782 * do nothing.
783 */
784 devfs_record_event(delp, newnmp->de_dnp, VNODE_EVENT_LINK);
785 }
786 }
787 }
788 return 0; /* for now always succeed */
789 }
790
791 static uint32_t
792 remove_notify_count(devnode_t *dnp)
793 {
794 uint32_t notify_count = 0;
795 devnode_t *dnp2;
796
797 /*
798 * Could need to notify for one removed node on each mount and
799 * one parent for each such node.
800 */
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;
805 }
806
807 return notify_count;
808 }
809
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)
815 *
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 ***********************************************************************/
820 void
821 devfs_remove(void *dirent_p)
822 {
823 devnode_t * dnp = ((devdirent_t *)dirent_p)->de_dnp;
824 devnode_t * dnp2;
825 boolean_t lastlink;
826 struct devfs_event_log event_log;
827 uint32_t log_count = 0;
828 int do_notify = 0;
829 int need_free = 0;
830 struct devfs_vnode_event stackbuf[NUM_STACK_ENTRIES];
831
832 DEVFS_LOCK();
833
834 if (!devfs_ready) {
835 printf("devfs_remove: not ready for devices!\n");
836 goto out;
837 }
838
839 log_count = remove_notify_count(dnp);
840
841 if (log_count > NUM_STACK_ENTRIES) {
842 uint32_t new_count;
843 wrongsize:
844 DEVFS_UNLOCK();
845 if (devfs_init_event_log(&event_log, log_count, NULL) == 0) {
846 do_notify = 1;
847 need_free = 1;
848 }
849 DEVFS_LOCK();
850
851 new_count = remove_notify_count(dnp);
852 if (need_free && (new_count > log_count)) {
853 devfs_release_event_log(&event_log, 1);
854 need_free = 0;
855 do_notify = 0;
856 log_count = log_count * 2;
857 goto wrongsize;
858 }
859 } else {
860 if (devfs_init_event_log(&event_log, NUM_STACK_ENTRIES, &stackbuf[0]) == 0) {
861 do_notify = 1;
862 }
863 }
864
865 /* This file has been deleted */
866 if (do_notify != 0) {
867 devfs_record_event(&event_log, dnp, VNODE_EVENT_DELETE);
868 }
869
870 /* keep removing the next sibling till only we exist. */
871 while ((dnp2 = dnp->dn_nextsibling) != dnp) {
872 /*
873 * Keep removing the next front node till no more exist
874 */
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);
879
880 /* This file has been deleted in this plane */
881 if (do_notify != 0) {
882 devfs_record_event(&event_log, dnp2, VNODE_EVENT_DELETE);
883 }
884
885 if (dnp2->dn_linklist) {
886 do {
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);
891 }
892 dev_free_name(dnp2->dn_linklist);
893 } while (!lastlink);
894 }
895 }
896
897 /*
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.
901 */
902 if (dnp->dn_linklist) {
903 do {
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);
908 }
909 dev_free_name(dnp->dn_linklist);
910 } while (!lastlink);
911 }
912 out:
913 DEVFS_UNLOCK();
914 if (do_notify != 0) {
915 devfs_bulk_notify(&event_log);
916 devfs_release_event_log(&event_log, need_free);
917 }
918
919 return;
920 }
921
922
923
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
928 * up the tree..
929 *
930 * called with DEVFS_LOCK held
931 **************************************************************/
932 int
933 dev_dup_plane(struct devfsmount *devfs_mp_p)
934 {
935 devdirent_t * new;
936 int error = 0;
937
938 if ((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p))) {
939 return error;
940 }
941 devfs_mp_p->plane_root = new;
942 devfs_nmountplanes++;
943 return error;
944 }
945
946
947
948 /***************************************************************
949 * Free a whole plane
950 *
951 * called with DEVFS_LOCK held
952 ***************************************************************/
953 void
954 devfs_free_plane(struct devfsmount *devfs_mp_p)
955 {
956 devdirent_t * dirent_p;
957
958 dirent_p = devfs_mp_p->plane_root;
959 if (dirent_p) {
960 dev_free_hier(dirent_p);
961 dev_free_name(dirent_p);
962 }
963 devfs_mp_p->plane_root = NULL;
964 devfs_nmountplanes--;
965
966 if (devfs_nmountplanes > (devfs_nmountplanes + 1)) {
967 panic("plane count wrapped around.\n");
968 }
969 }
970
971
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
979 *
980 * called with DEVFS_LOCK held
981 ***************************************************************/
982 static int
983 dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
984 struct devfsmount *dvm)
985 {
986 devdirent_t * entry_p = NULL;
987 devdirent_t * newback;
988 devdirent_t * newfront;
989 int error;
990 devnode_t * dnp = back->de_dnp;
991 int type = dnp->dn_type;
992
993 /*
994 * go get the node made (if we need to)
995 * use the back one as a prototype
996 */
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 */
1001 }
1002 if (error != 0) {
1003 printf("duplicating %s failed\n", back->de_name);
1004 goto out;
1005 }
1006
1007 /*
1008 * If we have just made the root, then insert the pointer to the
1009 * mount information
1010 */
1011 if (dvm) {
1012 entry_p->de_dnp->dn_dvm = dvm;
1013 }
1014
1015 /*
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..
1019 */
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 */
1026 }
1027 }
1028 }
1029 out:
1030 *dnm_pp = entry_p;
1031 return error;
1032 }
1033
1034
1035 /***************************************************************
1036 * Free a name node
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
1040 *
1041 * called with DEVFS_LOCK held
1042 ***************************************************************/
1043
1044 int
1045 dev_free_name(devdirent_t * dirent_p)
1046 {
1047 devnode_t * parent = dirent_p->de_parent;
1048 devnode_t * dnp = dirent_p->de_dnp;
1049
1050 if (dnp) {
1051 if (dnp->dn_type == DEV_DIR) {
1052 devnode_t * p;
1053
1054 if (dnp->dn_typeinfo.Dir.dirlist) {
1055 return ENOTEMPTY;
1056 }
1057 p = dnp->dn_typeinfo.Dir.parent;
1058 devfs_dn_free(dnp); /* account for '.' */
1059 devfs_dn_free(p); /* '..' */
1060 }
1061 /*
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
1065 * other links.
1066 */
1067 if (dirent_p->de_nextlink == dirent_p) {
1068 dnp->dn_linklist = NULL;
1069 } else {
1070 if (dnp->dn_linklist == dirent_p) {
1071 dnp->dn_linklist = dirent_p->de_nextlink;
1072 }
1073 }
1074 devfs_dn_free(dnp);
1075 }
1076
1077 dirent_p->de_nextlink->de_prevlinkp = dirent_p->de_prevlinkp;
1078 *(dirent_p->de_prevlinkp) = dirent_p->de_nextlink;
1079
1080 /*
1081 * unlink ourselves from the directory on this plane
1082 */
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;
1086 } else {
1087 parent->dn_typeinfo.Dir.dirlast
1088 = dirent_p->de_prevp;
1089 }
1090 parent->dn_typeinfo.Dir.entrycount--;
1091 parent->dn_len -= strlen(dirent_p->de_name) + 8;
1092 }
1093
1094 DEVFS_DECR_ENTRIES();
1095 FREE(dirent_p, M_DEVFSNAME);
1096 return 0;
1097 }
1098
1099
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.
1106 *
1107 * called with DEVFS_LOCK held
1108 ***************************************************************/
1109
1110 static void
1111 dev_free_hier(devdirent_t * dirent_p)
1112 {
1113 devnode_t * dnp = dirent_p->de_dnp;
1114
1115 if (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);
1120 }
1121 }
1122 }
1123 }
1124
1125
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
1129 *
1130 * called with DEVFS_LOCK held
1131 *
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 ****************************************************************/
1136 int
1137 devfs_dntovn(devnode_t * dnp, struct vnode **vn_pp, __unused struct proc * p)
1138 {
1139 struct vnode *vn_p;
1140 int error = 0;
1141 struct vnode_fsparam vfsp;
1142 enum vtype vtype = 0;
1143 int markroot = 0;
1144 int nretries = 0;
1145 int n_minor = DEVFS_CLONE_ALLOC; /* new minor number for clone device */
1146
1147 /*
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.
1153 */
1154 if (dnp->dn_lflags & DN_DELETE) {
1155 panic("devfs_dntovn: DN_DELETE set on a devnode upon entry.");
1156 }
1157
1158 devfs_ref_node(dnp);
1159
1160 retry:
1161 *vn_pp = NULL;
1162 vn_p = dnp->dn_vn;
1163
1164 if (vn_p) { /* already has a vnode */
1165 uint32_t vid;
1166
1167 vid = vnode_vid(vn_p);
1168
1169 DEVFS_UNLOCK();
1170
1171 /*
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.
1179 */
1180 error = vnode_getwithvid_drainok(vn_p, vid);
1181
1182 DEVFS_LOCK();
1183
1184 if (dnp->dn_lflags & DN_DELETE) {
1185 /*
1186 * our BUSY node got marked for
1187 * deletion while the DEVFS lock
1188 * was dropped...
1189 */
1190 if (error == 0) {
1191 /*
1192 * vnode_getwithvid returned a valid ref
1193 * which we need to drop
1194 */
1195 vnode_put(vn_p);
1196 }
1197
1198 /*
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.
1202 */
1203 error = ENOENT;
1204 } else if (error == ENODEV) {
1205 /*
1206 * The Filesystem is getting unmounted.
1207 */
1208 error = ENOENT;
1209 } else if (error && (nretries < DEV_MAX_VNODE_RETRY)) {
1210 /*
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).
1223 */
1224 error = 0;
1225 nretries++;
1226 goto retry;
1227 }
1228 if (!error) {
1229 *vn_pp = vn_p;
1230 }
1231
1232 goto out;
1233 }
1234
1235 /*
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.
1239 */
1240
1241 if (dnp->dn_lflags & DN_CREATE) {
1242 dnp->dn_lflags |= DN_CREATEWAIT;
1243 msleep(&dnp->dn_lflags, &devfs_mutex, PRIBIO, 0, 0);
1244 goto retry;
1245 }
1246
1247 dnp->dn_lflags |= DN_CREATE;
1248
1249 switch (dnp->dn_type) {
1250 case DEV_SLNK:
1251 vtype = VLNK;
1252 break;
1253 case DEV_DIR:
1254 if (dnp->dn_typeinfo.Dir.parent == dnp) {
1255 markroot = 1;
1256 }
1257 vtype = VDIR;
1258 break;
1259 case DEV_BDEV:
1260 case DEV_CDEV:
1261 vtype = (dnp->dn_type == DEV_BDEV) ? VBLK : VCHR;
1262 break;
1263 #if FDESC
1264 case DEV_DEVFD:
1265 vtype = VDIR;
1266 break;
1267 #endif /* FDESC */
1268 }
1269 vfsp.vnfs_mp = dnp->dn_dvm->mount;
1270 vfsp.vnfs_vtype = vtype;
1271 vfsp.vnfs_str = "devfs";
1272 vfsp.vnfs_dvp = 0;
1273 vfsp.vnfs_fsnode = dnp;
1274 vfsp.vnfs_cnp = 0;
1275 vfsp.vnfs_vops = *(dnp->dn_ops);
1276
1277 if (vtype == VBLK || vtype == VCHR) {
1278 /*
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.
1282 */
1283 if (dnp->dn_clone != NULL) {
1284 int n_major = major(dnp->dn_typeinfo.dev);
1285
1286 n_minor = (*dnp->dn_clone)(dnp->dn_typeinfo.dev, DEVFS_CLONE_ALLOC);
1287 if (n_minor == -1) {
1288 error = ENOMEM;
1289 goto out;
1290 }
1291
1292 vfsp.vnfs_rdev = makedev(n_major, n_minor);;
1293 } else {
1294 vfsp.vnfs_rdev = dnp->dn_typeinfo.dev;
1295 }
1296 } else {
1297 vfsp.vnfs_rdev = 0;
1298 }
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;
1304
1305 DEVFS_UNLOCK();
1306
1307 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &vn_p);
1308
1309 /* Do this before grabbing the lock */
1310 if (error == 0) {
1311 vnode_setneedinactive(vn_p);
1312 }
1313
1314 DEVFS_LOCK();
1315
1316 if (error == 0) {
1317 vnode_settag(vn_p, VT_DEVFS);
1318
1319 if ((dnp->dn_clone != NULL) && (dnp->dn_vn != NULLVP)) {
1320 panic("devfs_dntovn: cloning device with a vnode?\n");
1321 }
1322
1323 *vn_pp = vn_p;
1324
1325 /*
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.
1330 */
1331 devfs_ref_node(dnp);
1332
1333 /*
1334 * A cloned vnode is not hooked into the devnode; every lookup
1335 * gets a new vnode.
1336 */
1337 if (dnp->dn_clone == NULL) {
1338 dnp->dn_vn = vn_p;
1339 }
1340 } else if (n_minor != DEVFS_CLONE_ALLOC) {
1341 /*
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.
1349 */
1350 (void)(*dnp->dn_clone)(dnp->dn_typeinfo.dev, DEVFS_CLONE_FREE);
1351 }
1352
1353 dnp->dn_lflags &= ~DN_CREATE;
1354 if (dnp->dn_lflags & DN_CREATEWAIT) {
1355 dnp->dn_lflags &= ~DN_CREATEWAIT;
1356 wakeup(&dnp->dn_lflags);
1357 }
1358
1359 out:
1360 /*
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.
1364 */
1365 devfs_rele_node(dnp);
1366
1367 return error;
1368 }
1369
1370 /*
1371 * Increment refcount on a devnode; prevents free of the node
1372 * while the devfs lock is not held.
1373 */
1374 void
1375 devfs_ref_node(devnode_t *dnp)
1376 {
1377 os_ref_retain_locked_raw(&dnp->dn_refcount, &devfs_refgrp);
1378 }
1379
1380 /*
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.
1383 */
1384 void
1385 devfs_rele_node(devnode_t *dnp)
1386 {
1387 os_ref_count_t rc = os_ref_release_locked_raw(&dnp->dn_refcount, &devfs_refgrp);
1388 if (rc < 1) {
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);
1393 devnode_free(dnp);
1394 }
1395 }
1396
1397 /***********************************************************************
1398 * add a whole device, with no prototype.. make name element and node
1399 * Used for adding the original device entries
1400 *
1401 * called with DEVFS_LOCK held
1402 ***********************************************************************/
1403 int
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)
1406 {
1407 devnode_t * dnp;
1408 int error = 0;
1409
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",
1413 name, error);
1414 return error;
1415 }
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",
1419 name, error);
1420 }
1421 return error;
1422 }
1423
1424 static void
1425 devfs_bulk_notify(devfs_event_log_t delp)
1426 {
1427 uint32_t i;
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);
1433 }
1434 }
1435 }
1436
1437 static void
1438 devfs_record_event(devfs_event_log_t delp, devnode_t *dnp, uint32_t events)
1439 {
1440 if (delp->del_used >= delp->del_max) {
1441 panic("devfs event log overflowed.\n");
1442 }
1443
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;
1450 delp->del_used++;
1451 }
1452 }
1453
1454 static int
1455 devfs_init_event_log(devfs_event_log_t delp, uint32_t count, devfs_vnode_event_t buf)
1456 {
1457 devfs_vnode_event_t dvearr;
1458
1459 if (buf == NULL) {
1460 MALLOC(dvearr, devfs_vnode_event_t, count * sizeof(struct devfs_vnode_event), M_TEMP, M_WAITOK | M_ZERO);
1461 if (dvearr == NULL) {
1462 return ENOMEM;
1463 }
1464 } else {
1465 dvearr = buf;
1466 }
1467
1468 delp->del_max = count;
1469 delp->del_used = 0;
1470 delp->del_entries = dvearr;
1471 return 0;
1472 }
1473
1474 static void
1475 devfs_release_event_log(devfs_event_log_t delp, int need_free)
1476 {
1477 if (delp->del_entries == NULL) {
1478 panic("Free of devfs notify info that has not been intialized.\n");
1479 }
1480
1481 if (need_free) {
1482 FREE(delp->del_entries, M_TEMP);
1483 }
1484
1485 delp->del_entries = NULL;
1486 }
1487
1488 /*
1489 * Function: devfs_make_node
1490 *
1491 * Purpose
1492 * Create a device node with the given pathname in the devfs namespace.
1493 *
1494 * Parameters:
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
1501 * Returns:
1502 * A handle to a device node if successful, NULL otherwise.
1503 */
1504 void *
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, ...)
1508 {
1509 devdirent_t * new_dev = NULL;
1510 devfstype_t type;
1511 va_list ap;
1512
1513 switch (chrblk) {
1514 case DEVFS_CHAR:
1515 type = DEV_CDEV;
1516 break;
1517 case DEVFS_BLOCK:
1518 type = DEV_BDEV;
1519 break;
1520 default:
1521 goto out;
1522 }
1523
1524 va_start(ap, fmt);
1525 new_dev = devfs_make_node_internal(dev, type, uid, gid, perms, clone, fmt, ap);
1526 va_end(ap);
1527 out:
1528 return new_dev;
1529 }
1530
1531
1532 /*
1533 * Function: devfs_make_node
1534 *
1535 * Purpose
1536 * Create a device node with the given pathname in the devfs namespace.
1537 *
1538 * Parameters:
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
1544 * Returns:
1545 * A handle to a device node if successful, NULL otherwise.
1546 */
1547 void *
1548 devfs_make_node(dev_t dev, int chrblk, uid_t uid,
1549 gid_t gid, int perms, const char *fmt, ...)
1550 {
1551 devdirent_t * new_dev = NULL;
1552 devfstype_t type;
1553 va_list ap;
1554
1555 if (chrblk != DEVFS_CHAR && chrblk != DEVFS_BLOCK) {
1556 goto out;
1557 }
1558
1559 type = (chrblk == DEVFS_BLOCK ? DEV_BDEV : DEV_CDEV);
1560
1561 va_start(ap, fmt);
1562 new_dev = devfs_make_node_internal(dev, type, uid, gid, perms, NULL, fmt, ap);
1563 va_end(ap);
1564
1565 out:
1566 return new_dev;
1567 }
1568
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)
1572 {
1573 devdirent_t * new_dev = NULL;
1574 devnode_t * dnp;
1575 devnode_type_t typeinfo;
1576
1577 char *name, buf[256]; /* XXX */
1578 const char *path;
1579 #if CONFIG_MACF
1580 char buff[sizeof(buf)];
1581 #endif
1582 size_t i;
1583 uint32_t log_count;
1584 struct devfs_event_log event_log;
1585 struct devfs_vnode_event stackbuf[NUM_STACK_ENTRIES];
1586 int need_free = 0;
1587
1588 vsnprintf(buf, sizeof(buf), fmt, ap);
1589
1590 #if CONFIG_MACF
1591 bcopy(buf, buff, sizeof(buff));
1592 buff[sizeof(buff) - 1] = 0;
1593 #endif
1594 name = NULL;
1595
1596 for (i = strlen(buf); i > 0; i--) {
1597 if (buf[i] == '/') {
1598 name = &buf[i];
1599 buf[i] = 0;
1600 break;
1601 }
1602 }
1603
1604 if (name) {
1605 *name++ = '\0';
1606 path = buf;
1607 } else {
1608 name = buf;
1609 path = "/";
1610 }
1611
1612 log_count = devfs_nmountplanes;
1613 if (log_count > NUM_STACK_ENTRIES) {
1614 wrongsize:
1615 need_free = 1;
1616 if (devfs_init_event_log(&event_log, log_count, NULL) != 0) {
1617 return NULL;
1618 }
1619 } else {
1620 need_free = 0;
1621 log_count = NUM_STACK_ENTRIES;
1622 if (devfs_init_event_log(&event_log, log_count, &stackbuf[0]) != 0) {
1623 return NULL;
1624 }
1625 }
1626
1627 DEVFS_LOCK();
1628 if (log_count < devfs_nmountplanes) {
1629 DEVFS_UNLOCK();
1630 devfs_release_event_log(&event_log, need_free);
1631 log_count = log_count * 2;
1632 goto wrongsize;
1633 }
1634
1635 if (!devfs_ready) {
1636 printf("devfs_make_node: not ready for devices!\n");
1637 goto out;
1638 }
1639
1640 /* find/create directory path ie. mkdir -p */
1641 if (dev_finddir(path, NULL, DEVFS_CREATE, &dnp, &event_log) == 0) {
1642 typeinfo.dev = dev;
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;
1648 #if CONFIG_MACF
1649 mac_devfs_label_associate_device(dev, new_dev->de_dnp, buff);
1650 #endif
1651 devfs_propogate(dnp->dn_typeinfo.Dir.myname, new_dev, &event_log);
1652 }
1653 }
1654
1655 out:
1656 DEVFS_UNLOCK();
1657
1658 devfs_bulk_notify(&event_log);
1659 devfs_release_event_log(&event_log, need_free);
1660 return new_dev;
1661 }
1662
1663 /*
1664 * Function: devfs_make_link
1665 *
1666 * Purpose:
1667 * Create a link to a previously created device node.
1668 *
1669 * Returns:
1670 * 0 if successful, -1 if failed
1671 */
1672 int
1673 devfs_make_link(void *original, char *fmt, ...)
1674 {
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;
1679 uint32_t log_count;
1680
1681 va_list ap;
1682 char *p, buf[256]; /* XXX */
1683 size_t i;
1684
1685 DEVFS_LOCK();
1686
1687 if (!devfs_ready) {
1688 DEVFS_UNLOCK();
1689 printf("devfs_make_link: not ready for devices!\n");
1690 return -1;
1691 }
1692 DEVFS_UNLOCK();
1693
1694 va_start(ap, fmt);
1695 vsnprintf(buf, sizeof(buf), fmt, ap);
1696 va_end(ap);
1697
1698 p = NULL;
1699
1700 for (i = strlen(buf); i > 0; i--) {
1701 if (buf[i] == '/') {
1702 p = &buf[i];
1703 buf[i] = 0;
1704 break;
1705 }
1706 }
1707
1708 /*
1709 * One slot for each directory, one for each devnode
1710 * whose link count changes
1711 */
1712 log_count = devfs_nmountplanes * 2;
1713 wrongsize:
1714 if (devfs_init_event_log(&event_log, log_count, NULL) != 0) {
1715 /* No lock held, no allocations done, can just return */
1716 return -1;
1717 }
1718
1719 DEVFS_LOCK();
1720
1721 if (log_count < devfs_nmountplanes) {
1722 DEVFS_UNLOCK();
1723 devfs_release_event_log(&event_log, 1);
1724 log_count = log_count * 2;
1725 goto wrongsize;
1726 }
1727
1728 if (p) {
1729 *p++ = '\0';
1730
1731 if (dev_finddir(buf, NULL, DEVFS_CREATE, &dirnode, &event_log)
1732 || dev_add_name(p, dirnode, NULL, orig->de_dnp, &new_dev)) {
1733 goto fail;
1734 }
1735 } else {
1736 if (dev_finddir("", NULL, DEVFS_CREATE, &dirnode, &event_log)
1737 || dev_add_name(buf, dirnode, NULL, orig->de_dnp, &new_dev)) {
1738 goto fail;
1739 }
1740 }
1741 devfs_propogate(dirnode->dn_typeinfo.Dir.myname, new_dev, &event_log);
1742 fail:
1743 DEVFS_UNLOCK();
1744 devfs_bulk_notify(&event_log);
1745 devfs_release_event_log(&event_log, 1);
1746
1747 return (new_dev != NULL) ? 0 : -1;
1748 }