|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: /*
24: * Copyright 1997,1998 Julian Elischer. All rights reserved.
25: * [email protected]
26: *
27: * Redistribution and use in source and binary forms, with or without
28: * modification, are permitted provided that the following conditions are
29: * met:
30: * 1. Redistributions of source code must retain the above copyright
31: * notice, this list of conditions and the following disclaimer.
32: * 2. Redistributions in binary form must reproduce the above copyright notice,
33: * this list of conditions and the following disclaimer in the documentation
34: * and/or other materials provided with the distribution.
35: *
36: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
37: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39: * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
40: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46: * SUCH DAMAGE.
47: *
48: * devfs_tree.c
49: */
50:
51: /*
52: * HISTORY
53: * Dieter Siegmund ([email protected]) Thu Apr 8 14:08:19 PDT 1999
54: * - removed mounting of "hidden" mountpoint
55: * - fixed problem in which devnode->dn_vn pointer was not
56: * updated with the vnode returned from checkalias()
57: * - replaced devfs_vntodn() with a macro VTODN()
58: * - rewrote dev_finddir() to not use recursion
59: * - added locking to avoid data structure corruption (DEVFS_(UN)LOCK())
60: * Dieter Siegmund ([email protected]) Wed Jul 14 13:37:59 PDT 1999
61: * - fixed problem with devfs_dntovn() checking the v_id against the
62: * value cached in the device node; a union mount on top of us causes
63: * the v_id to get incremented thus, we would end up returning a new
64: * vnode instead of the existing one that has the mounted_here
65: * field filled in; the net effect was that the filesystem mounted
66: * on top of us would never show up
67: * - added devfs_stats to store how many data structures are actually
68: * allocated
69: */
70:
71: /* SPLIT_DEVS means each devfs uses a different devnode for the same device */
72: /* Otherwise the same device always ends up at the same vnode even if */
73: /* reached througgh a different devfs instance. The practical difference */
74: /* is that with the same vnode, chmods and chowns show up on all instances of */
75: /* a device. (etc) */
76:
77: #define SPLIT_DEVS 1 /* maybe make this an option */
78: /*#define SPLIT_DEVS 1*/
79:
80: #include <sys/param.h>
81: #include <sys/systm.h>
82: #include <sys/kernel.h>
83: #include <sys/conf.h>
84: #include <sys/malloc.h>
85: #include <sys/mount.h>
86: #include <sys/proc.h>
87: #include <sys/vnode.h>
88: #include <stdarg.h>
89:
90: #include "devfs.h"
91: #include "devfsdefs.h"
92:
93: struct lock__bsd__ devfs_lock; /* the "big switch" */
94: devdirent_t * dev_root = NULL; /* root of backing tree */
95: struct devfs_stats devfs_stats; /* hold stats */
96:
97: #ifdef HIDDEN_MOUNTPOINT
98: static struct mount *devfs_hidden_mount;
99: #endif HIDDEN_MOINTPOINT
100:
101: static int devfs_ready = 0;
102:
103: #define NOCREATE FALSE
104: #define CREATE TRUE
105:
106: /*
107: * Set up the root directory node in the backing plane
108: * This is happenning before the vfs system has been
109: * set up yet, so be careful about what we reference..
110: * Notice that the ops are by indirection.. as they haven't
111: * been set up yet!
112: * DEVFS has a hidden mountpoint that is used as the anchor point
113: * for the internal 'blueprint' version of the dev filesystem tree.
114: */
115: /*proto*/
116: int
117: devfs_sinit(void)
118: {
119: lockinit(&devfs_lock, PINOD, "devfs", 0, 0);
120: if (dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL,
121: &dev_root)) {
122: printf("devfs_sinit: dev_add_entry failed ");
123: return (EOPNOTSUPP);
124: }
125: #ifdef HIDDEN_MOUNTPOINT
126: MALLOC(devfs_hidden_mount, struct mount *, sizeof(struct mount),
127: M_MOUNT, M_NOWAIT);
128: bzero(devfs_hidden_mount,sizeof(struct mount));
129: devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL);
130: dev_root->de_dnp->dn_dvm
131: = (struct devfsmount *)devfs_hidden_mount->mnt_data;
132: #endif HIDDEN_MOUNTPOINT
133: devfs_ready = 1;
134: return (0);
135: }
136:
137: /***********************************************************************\
138: *************************************************************************
139: * Routines used to find our way to a point in the tree *
140: *************************************************************************
141: \***********************************************************************/
142:
143:
144: /***************************************************************\
145: * Search down the linked list off a dir to find "name" *
146: * return the devnode_t * for that node.
147: \***************************************************************/
148: /*proto*/
149: devdirent_t *
150: dev_findname(devnode_t * dir,char *name)
151: {
152: devdirent_t * newfp;
153: if (dir->dn_type != DEV_DIR) return 0;/*XXX*/ /* printf?*/
154:
155: if (name[0] == '.')
156: {
157: if(name[1] == 0)
158: {
159: return dir->dn_typeinfo.Dir.myname;
160: }
161: if((name[1] == '.') && (name[2] == 0))
162: {
163: /* for root, .. == . */
164: return dir->dn_typeinfo.Dir.parent->dn_typeinfo.Dir.myname;
165: }
166: }
167: newfp = dir->dn_typeinfo.Dir.dirlist;
168: while(newfp)
169: {
170: if(!(strcmp(name,newfp->de_name)))
171: return newfp;
172: newfp = newfp->de_next;
173: }
174: return NULL;
175: }
176:
177: #if 0
178: /***********************************************************************\
179: * Given a starting node (0 for root) and a pathname, return the node *
180: * for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE' *
181: * option is true, then create any missing nodes in the path and create *
182: * and return the final node as well. *
183: * This is used to set up a directory, before making nodes in it.. *
184: * *
185: * Warning: This function is RECURSIVE. *
186: \***********************************************************************/
187: int
188: dev_finddir(char * orig_path, /* find this dir (err if not dir) */
189: devnode_t * dirnode, /* starting point */
190: int create, /* create path? */
191: devnode_t * * dn_pp) /* returned */
192: {
193: devdirent_t * dirent_p;
194: devnode_t * dnp = NULL;
195: char pathbuf[DEVMAXPATHSIZE];
196: char *path;
197: char *name;
198: register char *cp;
199: int retval;
200:
201:
202: /***************************************\
203: * If no parent directory is given *
204: * then start at the root of the tree *
205: \***************************************/
206: if(!dirnode) dirnode = dev_root->de_dnp;
207:
208: /***************************************\
209: * Sanity Checks *
210: \***************************************/
211: if (dirnode->dn_type != DEV_DIR) return ENOTDIR;
212: if(strlen(orig_path) > (DEVMAXPATHSIZE - 1)) return ENAMETOOLONG;
213:
214:
215: path = pathbuf;
216: strcpy(path,orig_path);
217:
218: /***************************************\
219: * always absolute, skip leading / *
220: * get rid of / or // or /// etc. *
221: \***************************************/
222: while(*path == '/') path++;
223:
224: /***************************************\
225: * If nothing left, then parent was it.. *
226: \***************************************/
227: if ( *path == '\0' ) {
228: *dn_pp = dirnode;
229: return 0;
230: }
231:
232: /***************************************\
233: * find the next segment of the name *
234: \***************************************/
235: cp = name = path;
236: while((*cp != '/') && (*cp != 0)) {
237: cp++;
238: }
239:
240: /***********************************************\
241: * Check to see if it's the last component *
242: \***********************************************/
243: if(*cp) {
244: path = cp + 1; /* path refers to the rest */
245: *cp = 0; /* name is now a separate string */
246: if(!(*path)) {
247: path = (char *)0; /* was trailing slash */
248: }
249: } else {
250: path = NULL; /* no more to do */
251: }
252:
253: /***************************************\
254: * Start scanning along the linked list *
255: \***************************************/
256: dirent_p = dev_findname(dirnode,name);
257: if(dirent_p) { /* check it's a directory */
258: dnp = dirent_p->de_dnp;
259: if(dnp->dn_type != DEV_DIR) return ENOTDIR;
260: } else {
261: /***************************************\
262: * The required element does not exist *
263: * So we will add it if asked to. *
264: \***************************************/
265: if(!create) return ENOENT;
266:
267: if((retval = dev_add_entry(name, dirnode,
268: DEV_DIR, NULL, NULL, NULL,
269: &dirent_p)) != 0) {
270: return retval;
271: }
272: dnp = dirent_p->de_dnp;
273: devfs_propogate(dirnode->dn_typeinfo.Dir.myname,dirent_p);
274: }
275: if(path != NULL) { /* decide whether to recurse more or return */
276: return (dev_finddir(path,dnp,create,dn_pp));
277: } else {
278: *dn_pp = dnp;
279: return 0;
280: }
281: }
282: #endif 0
283: /***********************************************************************\
284: * Given a starting node (0 for root) and a pathname, return the node *
285: * for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE' *
286: * option is true, then create any missing nodes in the path and create *
287: * and return the final node as well. *
288: * This is used to set up a directory, before making nodes in it.. *
289: \***********************************************************************/
290: /* proto */
291: int
292: dev_finddir(char * path,
293: devnode_t * dirnode,
294: int create,
295: devnode_t * * dn_pp)
296: {
297: devnode_t * dnp = NULL;
298: int error = 0;
299: char * scan;
300:
301:
302: if (!dirnode) /* dirnode == NULL means start at root */
303: dirnode = dev_root->de_dnp;
304:
305: if (dirnode->dn_type != DEV_DIR)
306: return ENOTDIR;
307:
308: if (strlen(path) > (DEVMAXPATHSIZE - 1))
309: return ENAMETOOLONG;
310:
311: scan = path;
312:
313: while (*scan == '/')
314: scan++;
315:
316: *dn_pp = NULL;
317:
318: while (1) {
319: char component[DEVMAXPATHSIZE];
320: devdirent_t * dirent_p;
321: char * start;
322:
323: if (*scan == 0) {
324: /* we hit the end of the string, we're done */
325: *dn_pp = dirnode;
326: break;
327: }
328: start = scan;
329: while (*scan != '/' && *scan)
330: scan++;
331:
332: strncpy(component, start, scan - start);
333: if (*scan == '/')
334: scan++;
335:
336: dirent_p = dev_findname(dirnode, component);
337: if (dirent_p) {
338: dnp = dirent_p->de_dnp;
339: if (dnp->dn_type != DEV_DIR) {
340: error = ENOTDIR;
341: break;
342: }
343: }
344: else {
345: if (!create) {
346: error = ENOENT;
347: break;
348: }
349: error = dev_add_entry(component, dirnode,
350: DEV_DIR, NULL, NULL, NULL, &dirent_p);
351: if (error)
352: break;
353: dnp = dirent_p->de_dnp;
354: devfs_propogate(dirnode->dn_typeinfo.Dir.myname, dirent_p);
355: }
356: dirnode = dnp; /* continue relative to this directory */
357: }
358: return (error);
359: }
360:
361:
362: /***********************************************************************\
363: * Add a new NAME element to the devfs *
364: * If we're creating a root node, then dirname is NULL *
365: * Basically this creates a new namespace entry for the device node *
366: * *
367: * Creates a name node, and links it to the supplied node *
368: \***********************************************************************/
369: /*proto*/
370: int
371: dev_add_name(char * name, devnode_t * dirnode, devdirent_t * back,
372: devnode_t * dnp, devdirent_t * *dirent_pp)
373: {
374: devdirent_t * dirent_p = NULL;
375:
376: if(dirnode != NULL ) {
377: if(dirnode->dn_type != DEV_DIR) return(ENOTDIR);
378:
379: if( dev_findname(dirnode,name))
380: return(EEXIST);
381: }
382: /*
383: * make sure the name is legal
384: * slightly misleading in the case of NULL
385: */
386: if (!name || (strlen(name) > (DEVMAXNAMESIZE - 1)))
387: return (ENAMETOOLONG);
388:
389: /*
390: * Allocate and fill out a new directory entry
391: */
392: MALLOC(dirent_p, devdirent_t *, sizeof(devdirent_t),
393: M_DEVFSNAME, M_NOWAIT);
394: if (!dirent_p) {
395: return ENOMEM;
396: }
397: bzero(dirent_p,sizeof(devdirent_t));
398:
399: /* inherrit our parent's mount info */ /*XXX*/
400: /* a kludge but.... */
401: if(dirnode && ( dnp->dn_dvm == NULL)) {
402: dnp->dn_dvm = dirnode->dn_dvm;
403: /* if(!dnp->dn_dvm) printf("parent had null dvm "); */
404: }
405:
406: /*
407: * Link the two together
408: * include the implicit link in the count of links to the devnode..
409: * this stops it from being accidentally freed later.
410: */
411: dirent_p->de_dnp = dnp;
412: dnp->dn_links++ ; /* implicit from our own name-node */
413:
414: /*
415: * Make sure that we can find all the links that reference a node
416: * so that we can get them all if we need to zap the node.
417: */
418: if(dnp->dn_linklist) {
419: dirent_p->de_nextlink = dnp->dn_linklist;
420: dirent_p->de_prevlinkp = dirent_p->de_nextlink->de_prevlinkp;
421: dirent_p->de_nextlink->de_prevlinkp = &(dirent_p->de_nextlink);
422: *dirent_p->de_prevlinkp = dirent_p;
423: } else {
424: dirent_p->de_nextlink = dirent_p;
425: dirent_p->de_prevlinkp = &(dirent_p->de_nextlink);
426: }
427: dnp->dn_linklist = dirent_p;
428:
429: /*
430: * If the node is a directory, then we need to handle the
431: * creation of the .. link.
432: * A NULL dirnode indicates a root node, so point to ourself.
433: */
434: if(dnp->dn_type == DEV_DIR) {
435: dnp->dn_typeinfo.Dir.myname = dirent_p;
436: /*
437: * If we are unlinking from an old dir, decrement its links
438: * as we point our '..' elsewhere
439: * Note: it's up to the calling code to remove the
440: * us from the original directory's list
441: */
442: if(dnp->dn_typeinfo.Dir.parent) {
443: dnp->dn_typeinfo.Dir.parent->dn_links--;
444: }
445: if(dirnode) {
446: dnp->dn_typeinfo.Dir.parent = dirnode;
447: } else {
448: dnp->dn_typeinfo.Dir.parent = dnp;
449: }
450: dnp->dn_typeinfo.Dir.parent->dn_links++; /* account for the new '..' */
451: }
452:
453: /*
454: * put the name into the directory entry.
455: */
456: strcpy(dirent_p->de_name, name);
457:
458:
459: /*
460: * Check if we are not making a root node..
461: * (i.e. have parent)
462: */
463: if(dirnode) {
464: /*
465: * Put it on the END of the linked list of directory entries
466: */
467: int len;
468:
469: dirent_p->de_parent = dirnode; /* null for root */
470: dirent_p->de_prevp = dirnode->dn_typeinfo.Dir.dirlast;
471: dirent_p->de_next = *(dirent_p->de_prevp); /* should be NULL */
472: /*right?*/
473: *(dirent_p->de_prevp) = dirent_p;
474: dirnode->dn_typeinfo.Dir.dirlast = &(dirent_p->de_next);
475: dirnode->dn_typeinfo.Dir.entrycount++;
476: dirnode->dn_len += strlen(name) + 8;/*ok, ok?*/
477: }
478:
479: *dirent_pp = dirent_p;
480: DEVFS_INCR_ENTRIES();
481: return 0 ;
482: }
483:
484:
485: /***********************************************************************\
486: * Add a new element to the devfs plane. *
487: * *
488: * Creates a new dev_node to go with it if the prototype should not be *
489: * reused. (Is a DIR, or we select SPLIT_DEVS at compile time) *
490: * typeinfo gives us info to make our node if we don't have a prototype. *
491: * If typeinfo is null and proto exists, then the typeinfo field of *
492: * the proto is used intead in the CREATE case. *
493: * note the 'links' count is 0 (except if a dir) *
494: * but it is only cleared on a transition *
495: * so this is ok till we link it to something *
496: * Even in SPLIT_DEVS mode, *
497: * if the node already exists on the wanted plane, just return it *
498: \***********************************************************************/
499: /*proto*/
500: int
501: dev_add_node(int entrytype, devnode_type_t * typeinfo, devnode_t * proto,
502: devnode_t * *dn_pp, struct devfsmount *dvm)
503: {
504: devnode_t * dnp = NULL;
505:
506: #if defined SPLIT_DEVS
507: /*
508: * If we have a prototype, then check if there is already a sibling
509: * on the mount plane we are looking at, if so, just return it.
510: */
511: if (proto) {
512: dnp = proto->dn_nextsibling;
513: while( dnp != proto) {
514: if (dnp->dn_dvm == dvm) {
515: *dn_pp = dnp;
516: return (0);
517: }
518: dnp = dnp->dn_nextsibling;
519: }
520: if (typeinfo == NULL)
521: typeinfo = &(proto->dn_typeinfo);
522: }
523: #else /* SPLIT_DEVS */
524: if ( proto ) {
525: switch (proto->type) {
526: case DEV_BDEV:
527: case DEV_CDEV:
528: *dn_pp = proto;
529: return 0;
530: }
531: }
532: #endif /* SPLIT_DEVS */
533: MALLOC(dnp, devnode_t *, sizeof(devnode_t), M_DEVFSNODE, M_NOWAIT);
534: if (!dnp) {
535: return ENOMEM;
536: }
537:
538: /*
539: * If we have a proto, that means that we are duplicating some
540: * other device, which can only happen if we are not at the back plane
541: */
542: if(proto) {
543: bcopy(proto, dnp, sizeof(devnode_t));
544: dnp->dn_links = 0;
545: dnp->dn_linklist = NULL;
546: dnp->dn_vn = NULL;
547: dnp->dn_len = 0;
548: /* add to END of siblings list */
549: dnp->dn_prevsiblingp = proto->dn_prevsiblingp;
550: *(dnp->dn_prevsiblingp) = dnp;
551: dnp->dn_nextsibling = proto;
552: proto->dn_prevsiblingp = &(dnp->dn_nextsibling);
553: } else {
554: struct timeval tv;
555:
556: /*
557: * We have no prototype, so start off with a clean slate
558: */
559: tv = time;
560: bzero(dnp,sizeof(devnode_t));
561: dnp->dn_type = entrytype;
562: dnp->dn_nextsibling = dnp;
563: dnp->dn_prevsiblingp = &(dnp->dn_nextsibling);
564: dnp->dn_atime.tv_sec = tv.tv_sec;
565: dnp->dn_mtime.tv_sec = tv.tv_sec;
566: dnp->dn_ctime.tv_sec = tv.tv_sec;
567: }
568: dnp->dn_dvm = dvm;
569:
570: /*
571: * fill out the dev node according to type
572: */
573: switch(entrytype) {
574: case DEV_DIR:
575: /*
576: * As it's a directory, make sure
577: * it has a null entries list
578: */
579: dnp->dn_typeinfo.Dir.dirlast = &(dnp->dn_typeinfo.Dir.dirlist);
580: dnp->dn_typeinfo.Dir.dirlist = (devdirent_t *)0;
581: dnp->dn_typeinfo.Dir.entrycount = 0;
582: /* until we know better, it has a null parent pointer*/
583: dnp->dn_typeinfo.Dir.parent = NULL;
584: dnp->dn_links++; /* for .*/
585: dnp->dn_typeinfo.Dir.myname = NULL;
586: /*
587: * make sure that the ops associated with it are the ops
588: * that we use (by default) for directories
589: */
590: dnp->dn_ops = &devfs_vnodeop_p;
591: dnp->dn_mode |= 0555; /* default perms */
592: break;
593: case DEV_SLNK:
594: /*
595: * As it's a symlink allocate and store the link info
596: * Symlinks should only ever be created by the user,
597: * so they are not on the back plane and should not be
598: * propogated forward.. a bit like directories in that way..
599: * A symlink only exists on one plane and has its own
600: * node.. therefore we might be on any random plane.
601: */
602: MALLOC(dnp->dn_typeinfo.Slnk.name, char *,
603: typeinfo->Slnk.namelen+1,
604: M_DEVFSNODE, M_NOWAIT);
605: if (!dnp->dn_typeinfo.Slnk.name) {
606: FREE(dnp,M_DEVFSNODE);
607: return ENOMEM;
608: }
609: strncpy(dnp->dn_typeinfo.Slnk.name, typeinfo->Slnk.name,
610: typeinfo->Slnk.namelen);
611: dnp->dn_typeinfo.Slnk.name[typeinfo->Slnk.namelen] = '\0';
612: dnp->dn_typeinfo.Slnk.namelen = typeinfo->Slnk.namelen;
613: DEVFS_INCR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1);
614: dnp->dn_ops = &devfs_vnodeop_p;
615: dnp->dn_mode |= 0555; /* default perms */
616: break;
617: case DEV_CDEV:
618: case DEV_BDEV:
619: /*
620: * Make sure it has DEVICE type ops
621: * and device specific fields are correct
622: */
623: dnp->dn_ops = &devfs_spec_vnodeop_p;
624: dnp->dn_typeinfo.dev = typeinfo->dev;
625: break;
626: default:
627: return EINVAL;
628: }
629:
630: *dn_pp = dnp;
631: DEVFS_INCR_NODES();
632: return 0 ;
633: }
634:
635:
636: /*proto*/
637: void
638: devnode_free(devnode_t * dnp)
639: {
640: if (dnp->dn_type == DEV_SLNK) {
641: DEVFS_DECR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1);
642: FREE(dnp->dn_typeinfo.Slnk.name,M_DEVFSNODE);
643: }
644: FREE(dnp, M_DEVFSNODE);
645: DEVFS_DECR_NODES();
646: return;
647: }
648:
649: /*proto*/
650: void
651: devfs_dn_free(devnode_t * dnp)
652: {
653: if(--dnp->dn_links <= 0 ) /* can be -1 for initial free, on error */
654: {
655: /*probably need to do other cleanups XXX */
656: if (dnp->dn_nextsibling != dnp) {
657: devnode_t * * prevp = dnp->dn_prevsiblingp;
658: *prevp = dnp->dn_nextsibling;
659: dnp->dn_nextsibling->dn_prevsiblingp = prevp;
660:
661: }
662: if (dnp->dn_vn == NULL) {
663: #if 0
664: printf("devfs_dn_free: free'ing %x\n", (unsigned int)dnp);
665: #endif 0
666: devnode_free(dnp); /* no accesses/references */
667: }
668: else {
669: #if 0
670: printf("devfs_dn_free: marking %x for deletion\n",
671: (unsigned int)dnp);
672: #endif 0
673: dnp->dn_delete = TRUE;
674: }
675: }
676: }
677:
678: /***********************************************************************\
679: * Front Node Operations *
680: * Add or delete a chain of front nodes *
681: \***********************************************************************/
682:
683: /***********************************************************************\
684: * Given a directory backing node, and a child backing node, add the *
685: * appropriate front nodes to the front nodes of the directory to *
686: * represent the child node to the user *
687: * *
688: * on failure, front nodes will either be correct or not exist for each *
689: * front dir, however dirs completed will not be stripped of completed *
690: * frontnodes on failure of a later frontnode *
691: * *
692: * This allows a new node to be propogated through all mounted planes *
693: * *
694: \***********************************************************************/
695: /*proto*/
696: int
697: devfs_propogate(devdirent_t * parent,devdirent_t * child)
698: {
699: int error;
700: devdirent_t * newnmp;
701: devnode_t * dnp = child->de_dnp;
702: devnode_t * pdnp = parent->de_dnp;
703: devnode_t * adnp = parent->de_dnp;
704: int type = child->de_dnp->dn_type;
705:
706: /***********************************************\
707: * Find the other instances of the parent node *
708: \***********************************************/
709: for (adnp = pdnp->dn_nextsibling;
710: adnp != pdnp;
711: adnp = adnp->dn_nextsibling)
712: {
713: /*
714: * Make the node, using the original as a prototype)
715: * if the node already exists on that plane it won't be
716: * re-made..
717: */
718: if ((error = dev_add_entry(child->de_name, adnp, type,
719: NULL, dnp, adnp->dn_dvm,
720: &newnmp)) != 0) {
721: printf("duplicating %s failed\n",child->de_name);
722: }
723: }
724: return 0; /* for now always succeed */
725: }
726:
727: /***********************************************************************
728: * remove all instances of this devicename [for backing nodes..]
729: * note.. if there is another link to the node (non dir nodes only)
730: * then the devfs_node will still exist as the ref count will be non-0
731: * removing a directory node will remove all sup-nodes on all planes (ZAP)
732: *
733: * Used by device drivers to remove nodes that are no longer relevant
734: * The argument is the 'cookie' they were given when they created the node
735: * this function is exported.. see devfs.h
736: ***********************************************************************/
737: void
738: devfs_remove(void *dirent_p)
739: {
740: devnode_t * dnp = ((devdirent_t *)dirent_p)->de_dnp;
741: devnode_t * dnp2;
742:
743: if (!devfs_ready)
744: printf("devfs_remove: not ready for devices!\n");
745:
746: DEVFS_LOCK(0);
747:
748: /* keep removing the next sibling till only we exist. */
749: while((dnp2 = dnp->dn_nextsibling) != dnp) {
750:
751: /*
752: * Keep removing the next front node till no more exist
753: */
754: dnp->dn_nextsibling = dnp2->dn_nextsibling;
755: dnp->dn_nextsibling->dn_prevsiblingp = &(dnp->dn_nextsibling);
756: dnp2->dn_nextsibling = dnp2;
757: dnp2->dn_prevsiblingp = &(dnp2->dn_nextsibling);
758: while(dnp2->dn_linklist)
759: {
760: dev_free_name(dnp2->dn_linklist);
761: }
762: }
763:
764: /*
765: * then free the main node
766: * If we are not running in SPLIT_DEVS mode, then
767: * THIS is what gets rid of the propogated nodes.
768: */
769: while(dnp->dn_linklist)
770: {
771: dev_free_name(dnp->dn_linklist);
772: }
773: DEVFS_UNLOCK(0);
774: return ;
775: }
776:
777:
778: /***************************************************************
779: * duplicate the backing tree into a tree of nodes hung off the
780: * mount point given as the argument. Do this by
781: * calling dev_dup_entry which recurses all the way
782: * up the tree..
783: **************************************************************/
784: /*proto*/
785: int
786: dev_dup_plane(struct devfsmount *devfs_mp_p)
787: {
788: devdirent_t * new;
789: int error = 0;
790:
791: if ((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)))
792: return error;
793: devfs_mp_p->plane_root = new;
794: return error;
795: }
796:
797:
798:
799: /***************************************************************\
800: * Free a whole plane
801: \***************************************************************/
802: /*proto*/
803: void
804: devfs_free_plane(struct devfsmount *devfs_mp_p)
805: {
806: devdirent_t * dirent_p;
807:
808: dirent_p = devfs_mp_p->plane_root;
809: if(dirent_p) {
810: dev_free_hier(dirent_p);
811: dev_free_name(dirent_p);
812: }
813: devfs_mp_p->plane_root = NULL;
814: }
815:
816: /***************************************************************\
817: * Create and link in a new front element.. *
818: * Parent can be 0 for a root node *
819: * Not presently usable to make a symlink XXX *
820: * (Ok, symlinks don't propogate)
821: * recursively will create subnodes corresponding to equivalent *
822: * child nodes in the base level *
823: \***************************************************************/
824: /*proto*/
825: int
826: dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
827: struct devfsmount *dvm)
828: {
829: devdirent_t * entry_p;
830: devdirent_t * newback;
831: devdirent_t * newfront;
832: int error;
833: devnode_t * dnp = back->de_dnp;
834: int type = dnp->dn_type;
835:
836: /*
837: * go get the node made (if we need to)
838: * use the back one as a prototype
839: */
840: if ((error = dev_add_entry(back->de_name, parent, type,
841: NULL, dnp,
842: parent?parent->dn_dvm:dvm, &entry_p)) != 0) {
843: printf("duplicating %s failed\n",back->de_name);
844: }
845:
846: /*
847: * If we have just made the root, then insert the pointer to the
848: * mount information
849: */
850: if(dvm) {
851: entry_p->de_dnp->dn_dvm = dvm;
852: }
853:
854: /*
855: * If it is a directory, then recurse down all the other
856: * subnodes in it....
857: * note that this time we don't pass on the mount info..
858: */
859: if (type == DEV_DIR)
860: {
861: for(newback = back->de_dnp->dn_typeinfo.Dir.dirlist;
862: newback; newback = newback->de_next)
863: {
864: if((error = dev_dup_entry(entry_p->de_dnp,
865: newback, &newfront, NULL)) != 0)
866: {
867: break; /* back out with an error */
868: }
869: }
870: }
871: *dnm_pp = entry_p;
872: return error;
873: }
874:
875: /***************************************************************\
876: * Free a name node *
877: * remember that if there are other names pointing to the *
878: * dev_node then it may not get freed yet *
879: * can handle if there is no dnp *
880: \***************************************************************/
881: /*proto*/
882: int
883: dev_free_name(devdirent_t * dirent_p)
884: {
885: devnode_t * parent = dirent_p->de_parent;
886: devnode_t * dnp = dirent_p->de_dnp;
887:
888: if(dnp) {
889: if(dnp->dn_type == DEV_DIR)
890: {
891: devnode_t * p;
892:
893: if(dnp->dn_typeinfo.Dir.dirlist)
894: return (ENOTEMPTY);
895: p = dnp->dn_typeinfo.Dir.parent;
896: devfs_dn_free(dnp); /* account for '.' */
897: devfs_dn_free(p); /* '..' */
898: }
899: /*
900: * unlink us from the list of links for this node
901: * If we are the only link, it's easy!
902: * if we are a DIR of course there should not be any
903: * other links.
904: */
905: if(dirent_p->de_nextlink == dirent_p) {
906: dnp->dn_linklist = NULL;
907: } else {
908: if(dnp->dn_linklist == dirent_p) {
909: dnp->dn_linklist = dirent_p->de_nextlink;
910: }
911: dirent_p->de_nextlink->de_prevlinkp
912: = dirent_p->de_prevlinkp;
913: *dirent_p->de_prevlinkp = dirent_p->de_nextlink;
914: }
915: devfs_dn_free(dnp);
916: }
917:
918: /*
919: * unlink ourselves from the directory on this plane
920: */
921: if(parent) /* if not fs root */
922: {
923: if( (*dirent_p->de_prevp = dirent_p->de_next) )/* yes, assign */
924: {
925: dirent_p->de_next->de_prevp = dirent_p->de_prevp;
926: }
927: else
928: {
929: parent->dn_typeinfo.Dir.dirlast
930: = dirent_p->de_prevp;
931: }
932: parent->dn_typeinfo.Dir.entrycount--;
933: parent->dn_len -= strlen(dirent_p->de_name) + 8;
934: }
935:
936: DEVFS_DECR_ENTRIES();
937: FREE(dirent_p,M_DEVFSNAME);
938: return 0;
939: }
940:
941: /***************************************************************\
942: * Free a hierarchy starting at a directory node name *
943: * remember that if there are other names pointing to the *
944: * dev_node then it may not get freed yet *
945: * can handle if there is no dnp *
946: * leave the node itself allocated. *
947: \***************************************************************/
948: /*proto*/
949: void
950: dev_free_hier(devdirent_t * dirent_p)
951: {
952: devnode_t * dnp = dirent_p->de_dnp;
953:
954: if(dnp) {
955: if(dnp->dn_type == DEV_DIR)
956: {
957: while(dnp->dn_typeinfo.Dir.dirlist)
958: {
959: dev_free_hier(dnp->dn_typeinfo.Dir.dirlist);
960: dev_free_name(dnp->dn_typeinfo.Dir.dirlist);
961: }
962: }
963: }
964: }
965:
966: /***************************************************************\
967: * given a dev_node, find the appropriate vnode if one is already
968: * associated, or get a new one and associate it with the dev_node
969: \***************************************************************/
970: /*proto*/
971: int
972: devfs_dntovn(devnode_t * dnp, struct vnode **vn_pp, struct proc * p)
973: {
974: struct vnode *vn_p, *nvp;
975: int error = 0;
976:
977: *vn_pp = NULL;
978: vn_p = dnp->dn_vn;
979: if (vn_p) { /* already has a vnode */
980: *vn_pp = vn_p;
981: return(vget(vn_p, LK_EXCLUSIVE, p));
982: }
983: if (!(error = getnewvnode(VT_DEVFS, dnp->dn_dvm->mount,
984: *(dnp->dn_ops), &vn_p))) {
985: switch(dnp->dn_type) {
986: case DEV_SLNK:
987: vn_p->v_type = VLNK;
988: break;
989: case DEV_DIR:
990: if (dnp->dn_typeinfo.Dir.parent == dnp) {
991: vn_p->v_flag |= VROOT;
992: }
993: vn_p->v_type = VDIR;
994: break;
995: case DEV_BDEV:
996: case DEV_CDEV:
997: vn_p->v_type
998: = (dnp->dn_type == DEV_BDEV) ? VBLK : VCHR;
999: if ((nvp = checkalias(vn_p, dnp->dn_typeinfo.dev,
1000: dnp->dn_dvm->mount)) != NULL) {
1001: vput(vn_p);
1002: vn_p = nvp;
1003: }
1004: break;
1005: }
1006: vn_p->v_mount = dnp->dn_dvm->mount;/* XXX Duplicated */
1007: *vn_pp = vn_p;
1008: vn_p->v_data = (void *)dnp;
1009: dnp->dn_vn = vn_p;
1010: error = vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p);
1011: }
1012: return error;
1013: }
1014:
1015: /***********************************************************************\
1016: * add a whole device, with no prototype.. make name element and node *
1017: * Used for adding the original device entries *
1018: \***********************************************************************/
1019: /*proto*/
1020: int
1021: dev_add_entry(char *name, devnode_t * parent, int type, devnode_type_t * typeinfo,
1022: devnode_t * proto, struct devfsmount *dvm, devdirent_t * *nm_pp)
1023: {
1024: devnode_t * dnp;
1025: int error = 0;
1026:
1027: if ((error = dev_add_node(type, typeinfo, proto, &dnp,
1028: (parent?parent->dn_dvm:dvm))) != 0)
1029: {
1030: printf("devfs: %s: base node allocation failed (Errno=%d)\n",
1031: name,error);
1032: return error;
1033: }
1034: if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0)
1035: {
1036: devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */
1037: printf("devfs: %s: name slot allocation failed (Errno=%d)\n",
1038: name,error);
1039:
1040: }
1041: return error;
1042: }
1043:
1044: #include <sys/subr_prf.h>
1045:
1046: /*
1047: * Function: devfs_make_node
1048: *
1049: * Purpose
1050: * Create a device node with the given pathname in the devfs namespace.
1051: *
1052: * Parameters:
1053: * dev - the dev_t value to associate
1054: * chrblk - block or character device (DEVFS_CHAR or DEVFS_BLOCK)
1055: * uid, gid - ownership
1056: * perms - permissions
1057: * fmt, ... - path format string with printf args to format the path name
1058: * Returns:
1059: * A handle to a device node if successful, NULL otherwise.
1060: */
1061: void *
1062: devfs_make_node(dev_t dev, int chrblk, uid_t uid,
1063: gid_t gid, int perms, char *fmt, ...)
1064: {
1065: devdirent_t * new_dev = NULL;
1066: devnode_t * dnp; /* devnode for parent directory */
1067: devnode_type_t typeinfo;
1068:
1069: char *name, *path, buf[256]; /* XXX */
1070: char * b_ptr = buf;
1071: int i;
1072: va_list ap;
1073:
1074: if (!devfs_ready) {
1075: printf("devfs_make_node: not ready for devices!\n");
1076: return (NULL);
1077: }
1078:
1079: if (chrblk != DEVFS_CHAR && chrblk != DEVFS_BLOCK)
1080: return (NULL);
1081:
1082: va_start(ap, fmt);
1083: prf(fmt, ap, TOSTR, (struct tty *)&b_ptr);
1084: va_end(ap);
1085: *b_ptr = 0;
1086:
1087: name = NULL;
1088:
1089: for(i=strlen(buf); i>0; i--)
1090: if(buf[i] == '/') {
1091: name=&buf[i];
1092: buf[i]=0;
1093: break;
1094: }
1095:
1096: if (name) {
1097: *name++ = '\0';
1098: path = buf;
1099: } else {
1100: name = buf;
1101: path = "/";
1102: }
1103:
1104: DEVFS_LOCK(0);
1105: /* find/create directory path ie. mkdir -p */
1106: if (dev_finddir(path, NULL, CREATE, &dnp) == 0) {
1107: typeinfo.dev = dev;
1108: if (dev_add_entry(name, dnp,
1109: (chrblk == DEVFS_CHAR) ? DEV_CDEV : DEV_BDEV,
1110: &typeinfo, NULL, NULL, &new_dev) == 0) {
1111: new_dev->de_dnp->dn_gid = gid;
1112: new_dev->de_dnp->dn_uid = uid;
1113: new_dev->de_dnp->dn_mode |= perms;
1114: devfs_propogate(dnp->dn_typeinfo.Dir.myname, new_dev);
1115: }
1116: }
1117: DEVFS_UNLOCK(0);
1118: return new_dev;
1119: }
1120:
1121: /*
1122: * Function: devfs_make_link
1123: *
1124: * Purpose:
1125: * Create a link to a previously created device node.
1126: *
1127: * Returns:
1128: * 0 if successful, -1 if failed
1129: */
1130: int
1131: devfs_make_link(void *original, char *fmt, ...)
1132: {
1133: devdirent_t * new_dev = NULL;
1134: devdirent_t * orig = (devdirent_t *) original;
1135: devnode_t * dirnode; /* devnode for parent directory */
1136:
1137: va_list ap;
1138: char *p, buf[256]; /* XXX */
1139: char * b_ptr = buf;
1140: int i;
1141:
1142: if (!devfs_ready) {
1143: printf("devfs_make_link: not ready for devices!\n");
1144: return (-1);
1145: }
1146:
1147: va_start(ap, fmt);
1148: prf(fmt, ap, TOSTR, (struct tty *)&b_ptr);
1149: va_end(ap);
1150: *b_ptr = 0;
1151:
1152: p = NULL;
1153:
1154: for(i=strlen(buf); i>0; i--)
1155: if(buf[i] == '/') {
1156: p=&buf[i];
1157: buf[i]=0;
1158: break;
1159: }
1160: DEVFS_LOCK(0);
1161: if (p) {
1162: *p++ = '\0';
1163: if (dev_finddir(buf, NULL, CREATE, &dirnode)
1164: || dev_add_name(p, dirnode, NULL, orig->de_dnp, &new_dev))
1165: goto fail;
1166: } else {
1167: if (dev_finddir("", NULL, CREATE, &dirnode)
1168: || dev_add_name(buf, dirnode, NULL, orig->de_dnp, &new_dev))
1169: goto fail;
1170: }
1171: devfs_propogate(dirnode->dn_typeinfo.Dir.myname, new_dev);
1172: fail:
1173: DEVFS_UNLOCK(0);
1174: return ((new_dev != NULL) ? 0 : -1);
1175: }
1176:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.