devfs_devs.c revision 150147
1139776Simp/*- 2130678Sphk * Copyright (c) 2000,2004 364880Sphk * Poul-Henning Kamp. All rights reserved. 464880Sphk * 564880Sphk * Redistribution and use in source and binary forms, with or without 664880Sphk * modification, are permitted provided that the following conditions 764880Sphk * are met: 864880Sphk * 1. Redistributions of source code must retain the above copyright 964880Sphk * notice, this list of conditions and the following disclaimer. 1064880Sphk * 2. Neither the name of the University nor the names of its contributors 1164880Sphk * may be used to endorse or promote products derived from this software 1264880Sphk * without specific prior written permission. 1364880Sphk * 1464880Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1564880Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1664880Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1764880Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1864880Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1964880Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2064880Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2164880Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2264880Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2364880Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2464880Sphk * SUCH DAMAGE. 2564880Sphk * 2664880Sphk * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 2764880Sphk * 2864880Sphk * $FreeBSD: head/sys/fs/devfs/devfs_devs.c 150147 2005-09-15 06:57:28Z phk $ 2964880Sphk */ 3064880Sphk 3165515Sphk#include "opt_devfs.h" 32101069Srwatson#include "opt_mac.h" 3365515Sphk 3464880Sphk#include <sys/param.h> 3564880Sphk#include <sys/systm.h> 3676166Smarkm#include <sys/conf.h> 3764880Sphk#include <sys/dirent.h> 3876166Smarkm#include <sys/kernel.h> 3976166Smarkm#include <sys/lock.h> 40101069Srwatson#include <sys/mac.h> 4164880Sphk#include <sys/malloc.h> 4276166Smarkm#include <sys/proc.h> 4365515Sphk#include <sys/sysctl.h> 4476166Smarkm#include <sys/vnode.h> 4564880Sphk 4665515Sphk#include <machine/atomic.h> 4765515Sphk 4864880Sphk#include <fs/devfs/devfs.h> 49149144Sphk#include <fs/devfs/devfs_int.h> 5064880Sphk 51130585Sphkstatic struct cdev *devfs_inot[NDEVFSINO]; 52130585Sphkstatic struct cdev **devfs_overflow; 5365515Sphkstatic int devfs_ref[NDEVFSINO]; 5465515Sphkstatic int *devfs_refoverflow; 5565515Sphkstatic int devfs_nextino = 3; 5665515Sphkstatic int devfs_numino; 5765515Sphkstatic int devfs_topino; 5865515Sphkstatic int devfs_noverflowwant = NDEVFSOVERFLOW; 5965515Sphkstatic int devfs_noverflow; 6065515Sphkstatic unsigned devfs_generation; 6165515Sphk 6269767Sphkstatic struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen); 6369767Sphk 64141633Sphkstatic SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem"); 6565515SphkSYSCTL_UINT(_vfs_devfs, OID_AUTO, noverflow, CTLFLAG_RW, 6665515Sphk &devfs_noverflowwant, 0, "Size of DEVFS overflow table"); 6765515SphkSYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD, 6865515Sphk &devfs_generation, 0, "DEVFS generation number"); 6965515SphkSYSCTL_UINT(_vfs_devfs, OID_AUTO, inodes, CTLFLAG_RD, 7065515Sphk &devfs_numino, 0, "DEVFS inodes"); 7165515SphkSYSCTL_UINT(_vfs_devfs, OID_AUTO, topinode, CTLFLAG_RD, 7265515Sphk &devfs_topino, 0, "DEVFS highest inode#"); 7365515Sphk 74150147Sphkunsigned devfs_rule_depth = 1; 75150147SphkSYSCTL_UINT(_vfs_devfs, OID_AUTO, rule_depth, CTLFLAG_RW, 76150147Sphk &devfs_rule_depth, 0, "Max depth of ruleset include"); 77150147Sphk 78149146Sphk/* 79149146Sphk * Helper sysctl for devname(3). We're given a struct cdev * and return 80149146Sphk * the name, if any, registered by the device driver. 81149146Sphk */ 82149146Sphkstatic int 83149146Sphksysctl_devname(SYSCTL_HANDLER_ARGS) 84149146Sphk{ 85149146Sphk int error; 86149146Sphk dev_t ud; 87149146Sphk struct cdev *dev, **dp; 88149146Sphk 89149146Sphk error = SYSCTL_IN(req, &ud, sizeof (ud)); 90149146Sphk if (error) 91149146Sphk return (error); 92149146Sphk if (ud == NODEV) 93149146Sphk return(EINVAL); 94149146Sphk dp = devfs_itod(ud); 95149146Sphk if (dp == NULL) 96149146Sphk return(ENOENT); 97149146Sphk dev = *dp; 98149146Sphk if (dev == NULL) 99149146Sphk return(ENOENT); 100149146Sphk return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1)); 101149146Sphk return (error); 102149146Sphk} 103149146Sphk 104149146SphkSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 105149146Sphk NULL, 0, sysctl_devname, "", "devname(3) handler"); 106149146Sphk 107149146SphkSYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD, 108149146Sphk 0, sizeof(struct cdev), "sizeof(struct cdev)"); 109149146Sphk 11065515Sphkstatic int * 11165515Sphkdevfs_itor(int inode) 11265515Sphk{ 11365515Sphk if (inode < NDEVFSINO) 11465515Sphk return (&devfs_ref[inode]); 11565515Sphk else if (inode < NDEVFSINO + devfs_noverflow) 11665515Sphk return (&devfs_refoverflow[inode - NDEVFSINO]); 11765515Sphk else 11865515Sphk panic ("YRK!"); 11965515Sphk} 12065515Sphk 12165515Sphkstatic void 12265515Sphkdevfs_dropref(int inode) 12365515Sphk{ 12465515Sphk int *ip; 12565515Sphk 12665515Sphk ip = devfs_itor(inode); 12765515Sphk atomic_add_int(ip, -1); 12865515Sphk} 12965515Sphk 13065515Sphkstatic int 13165515Sphkdevfs_getref(int inode) 13265515Sphk{ 13365515Sphk int *ip, i, j; 134130585Sphk struct cdev **dp; 13565515Sphk 13665515Sphk ip = devfs_itor(inode); 13765515Sphk dp = devfs_itod(inode); 13865515Sphk for (;;) { 13965515Sphk i = *ip; 14065515Sphk j = i + 1; 14165515Sphk if (!atomic_cmpset_int(ip, i, j)) 14265515Sphk continue; 14365515Sphk if (*dp != NULL) 14465515Sphk return (1); 14565515Sphk atomic_add_int(ip, -1); 14665515Sphk return(0); 14765515Sphk } 14865515Sphk} 14965515Sphk 15065515Sphkstruct devfs_dirent ** 15165515Sphkdevfs_itode (struct devfs_mount *dm, int inode) 15265515Sphk{ 15365515Sphk 154143381Sphk if (inode < 0) 155143381Sphk return (NULL); 15665515Sphk if (inode < NDEVFSINO) 15765515Sphk return (&dm->dm_dirent[inode]); 15865515Sphk if (devfs_overflow == NULL) 15965515Sphk return (NULL); 16065515Sphk if (inode < NDEVFSINO + devfs_noverflow) 16165515Sphk return (&dm->dm_overflow[inode - NDEVFSINO]); 16265515Sphk return (NULL); 16365515Sphk} 16465515Sphk 165130585Sphkstruct cdev ** 16665515Sphkdevfs_itod (int inode) 16765515Sphk{ 16865515Sphk 169143381Sphk if (inode < 0) 170143381Sphk return (NULL); 17165515Sphk if (inode < NDEVFSINO) 17265515Sphk return (&devfs_inot[inode]); 17365515Sphk if (devfs_overflow == NULL) 17465515Sphk return (NULL); 17565515Sphk if (inode < NDEVFSINO + devfs_noverflow) 17665515Sphk return (&devfs_overflow[inode - NDEVFSINO]); 17765515Sphk return (NULL); 17865515Sphk} 17965515Sphk 18069767Sphkstatic struct devfs_dirent * 18165132Sphkdevfs_find(struct devfs_dirent *dd, const char *name, int namelen) 18265132Sphk{ 18365132Sphk struct devfs_dirent *de; 18465132Sphk 18565132Sphk TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 18665132Sphk if (namelen != de->de_dirent->d_namlen) 18765132Sphk continue; 18865132Sphk if (bcmp(name, de->de_dirent->d_name, namelen) != 0) 18965132Sphk continue; 19065132Sphk break; 19165132Sphk } 19265132Sphk return (de); 19365132Sphk} 19465132Sphk 19565132Sphkstruct devfs_dirent * 19664880Sphkdevfs_newdirent(char *name, int namelen) 19764880Sphk{ 19864880Sphk int i; 19964880Sphk struct devfs_dirent *de; 20064880Sphk struct dirent d; 20164880Sphk 20264880Sphk d.d_namlen = namelen; 20364880Sphk i = sizeof (*de) + GENERIC_DIRSIZ(&d); 204111119Simp MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK | M_ZERO); 20564880Sphk de->de_dirent = (struct dirent *)(de + 1); 20664880Sphk de->de_dirent->d_namlen = namelen; 20764880Sphk de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d); 20871822Sphk bcopy(name, de->de_dirent->d_name, namelen); 20971822Sphk de->de_dirent->d_name[namelen] = '\0'; 21085979Sphk vfs_timestamp(&de->de_ctime); 21165051Sphk de->de_mtime = de->de_atime = de->de_ctime; 21265051Sphk de->de_links = 1; 213101069Srwatson#ifdef MAC 214101069Srwatson mac_init_devfsdirent(de); 215101069Srwatson#endif 21664880Sphk return (de); 21764880Sphk} 21864880Sphk 21965051Sphkstruct devfs_dirent * 22065051Sphkdevfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot) 22164880Sphk{ 22265051Sphk struct devfs_dirent *dd; 22364880Sphk struct devfs_dirent *de; 22464880Sphk 22565051Sphk dd = devfs_newdirent(name, namelen); 22664880Sphk 22765051Sphk TAILQ_INIT(&dd->de_dlist); 22865051Sphk 22965051Sphk dd->de_dirent->d_type = DT_DIR; 23085979Sphk dd->de_mode = 0555; 23165051Sphk dd->de_links = 2; 23265051Sphk dd->de_dir = dd; 23365051Sphk 23464880Sphk de = devfs_newdirent(".", 1); 23564880Sphk de->de_dirent->d_type = DT_DIR; 23665051Sphk de->de_dir = dd; 23765051Sphk de->de_flags |= DE_DOT; 23865051Sphk TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 23965051Sphk 24065051Sphk de = devfs_newdirent("..", 2); 24165051Sphk de->de_dirent->d_type = DT_DIR; 24265051Sphk if (dotdot == NULL) 24365051Sphk de->de_dir = dd; 24465051Sphk else 24565051Sphk de->de_dir = dotdot; 24665051Sphk de->de_flags |= DE_DOTDOT; 24765051Sphk TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 24865051Sphk 24964880Sphk return (dd); 25064880Sphk} 25164880Sphk 25265051Sphkstatic void 25365051Sphkdevfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de) 25464880Sphk{ 25564880Sphk 25664880Sphk if (de->de_symlink) { 25764880Sphk FREE(de->de_symlink, M_DEVFS); 25864880Sphk de->de_symlink = NULL; 25964880Sphk } 26066877Sphk if (de->de_vnode) 26164880Sphk de->de_vnode->v_data = NULL; 26265051Sphk TAILQ_REMOVE(&dd->de_dlist, de, de_list); 263101069Srwatson#ifdef MAC 264101069Srwatson mac_destroy_devfsdirent(de); 265101069Srwatson#endif 26664880Sphk FREE(de, M_DEVFS); 26764880Sphk} 26864880Sphk 26964880Sphkvoid 27065051Sphkdevfs_purge(struct devfs_dirent *dd) 27164880Sphk{ 27264880Sphk struct devfs_dirent *de; 27364880Sphk 27464880Sphk for (;;) { 27565051Sphk de = TAILQ_FIRST(&dd->de_dlist); 27664880Sphk if (de == NULL) 27764880Sphk break; 27864880Sphk devfs_delete(dd, de); 27964880Sphk } 28064880Sphk FREE(dd, M_DEVFS); 28164880Sphk} 28264880Sphk 28364880Sphk 28464880Sphkint 28564880Sphkdevfs_populate(struct devfs_mount *dm) 28664880Sphk{ 28764880Sphk int i, j; 288130585Sphk struct cdev *dev, *pdev; 28965051Sphk struct devfs_dirent *dd; 29065515Sphk struct devfs_dirent *de, **dep; 29164880Sphk char *q, *s; 29264880Sphk 29366877Sphk if (dm->dm_generation == devfs_generation) 29465515Sphk return (0); 29583366Sjulian lockmgr(&dm->dm_lock, LK_UPGRADE, 0, curthread); 29665515Sphk if (devfs_noverflow && dm->dm_overflow == NULL) { 29765515Sphk i = devfs_noverflow * sizeof (struct devfs_dirent *); 29865515Sphk MALLOC(dm->dm_overflow, struct devfs_dirent **, i, 299111119Simp M_DEVFS, M_WAITOK | M_ZERO); 30065515Sphk } 30164880Sphk while (dm->dm_generation != devfs_generation) { 30264880Sphk dm->dm_generation = devfs_generation; 30365515Sphk for (i = 0; i <= devfs_topino; i++) { 30465515Sphk dev = *devfs_itod(i); 30565515Sphk dep = devfs_itode(dm, i); 30665515Sphk de = *dep; 30765051Sphk if (dev == NULL && de == DE_DELETED) { 30865515Sphk *dep = NULL; 30965051Sphk continue; 31065051Sphk } 31164880Sphk if (dev == NULL && de != NULL) { 31264880Sphk dd = de->de_dir; 31365515Sphk *dep = NULL; 314143381Sphk devfs_delete(dd, de); 31565515Sphk devfs_dropref(i); 31664880Sphk continue; 31764880Sphk } 31864880Sphk if (dev == NULL) 31964880Sphk continue; 32064880Sphk if (de != NULL) 32164880Sphk continue; 32265515Sphk if (!devfs_getref(i)) 32365515Sphk continue; 324149107Sphk dd = dm->dm_rootdir; 32564880Sphk s = dev->si_name; 32665132Sphk for (;;) { 32765132Sphk for (q = s; *q != '/' && *q != '\0'; q++) 32865132Sphk continue; 32966877Sphk if (*q != '/') 33065132Sphk break; 33165132Sphk de = devfs_find(dd, s, q - s); 33265132Sphk if (de == NULL) { 33365132Sphk de = devfs_vmkdir(s, q - s, dd); 334101069Srwatson#ifdef MAC 335107698Srwatson mac_create_devfs_directory( 336107698Srwatson dm->dm_mount, s, q - s, de); 337101069Srwatson#endif 33865132Sphk de->de_inode = dm->dm_inode++; 33965132Sphk TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 34065132Sphk dd->de_links++; 34165051Sphk } 34265051Sphk s = q + 1; 34365051Sphk dd = de; 34464880Sphk } 34564880Sphk de = devfs_newdirent(s, q - s); 34664880Sphk if (dev->si_flags & SI_ALIAS) { 34764880Sphk de->de_inode = dm->dm_inode++; 34864880Sphk de->de_uid = 0; 34964880Sphk de->de_gid = 0; 35085979Sphk de->de_mode = 0755; 35164880Sphk de->de_dirent->d_type = DT_LNK; 35277215Sphk pdev = dev->si_parent; 35364880Sphk j = strlen(pdev->si_name) + 1; 354111119Simp MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK); 35564880Sphk bcopy(pdev->si_name, de->de_symlink, j); 35664880Sphk } else { 35764880Sphk de->de_inode = i; 358144385Sphk de->de_uid = dev->si_uid; 359144385Sphk de->de_gid = dev->si_gid; 360144385Sphk de->de_mode = dev->si_mode; 36164880Sphk de->de_dirent->d_type = DT_CHR; 36264880Sphk } 363101069Srwatson#ifdef MAC 364147982Srwatson mac_create_devfs_device(dev->si_cred, dm->dm_mount, 365147982Srwatson dev, de); 366101069Srwatson#endif 36765515Sphk *dep = de; 36865132Sphk de->de_dir = dd; 369100206Sdd devfs_rules_apply(dm, de); 37065051Sphk TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 37164880Sphk } 37264880Sphk } 37383366Sjulian lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, curthread); 37464880Sphk return (0); 37564880Sphk} 37664880Sphk 377130678Sphk/* 378130678Sphk * devfs_create() and devfs_destroy() are called from kern_conf.c and 379130678Sphk * in both cases the devlock() mutex is held, so no further locking 380130678Sphk * is necesary and no sleeping allowed. 381130678Sphk */ 382130678Sphk 383111730Sphkvoid 384130585Sphkdevfs_create(struct cdev *dev) 38564880Sphk{ 38665515Sphk int ino, i, *ip; 387130585Sphk struct cdev **dp; 388130678Sphk struct cdev **ot; 389130678Sphk int *or; 390130678Sphk int n; 39165515Sphk 39265515Sphk for (;;) { 39365515Sphk /* Grab the next inode number */ 39465515Sphk ino = devfs_nextino; 39565515Sphk i = ino + 1; 39665515Sphk /* wrap around when we reach the end */ 39765515Sphk if (i >= NDEVFSINO + devfs_noverflow) 39865515Sphk i = 3; 399130678Sphk devfs_nextino = i; 40065515Sphk 40165515Sphk /* see if it was occupied */ 40265515Sphk dp = devfs_itod(ino); 403130678Sphk KASSERT(dp != NULL, ("DEVFS: No devptr inode %d", ino)); 40465515Sphk if (*dp != NULL) 40565515Sphk continue; 40665515Sphk ip = devfs_itor(ino); 407130678Sphk KASSERT(ip != NULL, ("DEVFS: No iptr inode %d", ino)); 40865515Sphk if (*ip != 0) 40965515Sphk continue; 410130678Sphk break; 411130678Sphk } 41265515Sphk 413130678Sphk *dp = dev; 414130678Sphk dev->si_inode = ino; 415130678Sphk if (i > devfs_topino) 416130678Sphk devfs_topino = i; 41765515Sphk 418130678Sphk devfs_numino++; 419130678Sphk devfs_generation++; 420130678Sphk 421130678Sphk if (devfs_overflow != NULL || devfs_numino + 100 < NDEVFSINO) 422130678Sphk return; 423130678Sphk 424130678Sphk /* 425130678Sphk * Try to allocate overflow table 426130678Sphk * XXX: we can probably be less panicy these days and a linked 427130678Sphk * XXX: list of PAGESIZE/PTRSIZE entries might be a better idea. 428130678Sphk * 429130678Sphk * XXX: we may be into witness unlove here. 430130678Sphk */ 431130678Sphk n = devfs_noverflowwant; 432130678Sphk ot = malloc(sizeof(*ot) * n, M_DEVFS, M_NOWAIT | M_ZERO); 433130678Sphk if (ot == NULL) 434130678Sphk return; 435130678Sphk or = malloc(sizeof(*or) * n, M_DEVFS, M_NOWAIT | M_ZERO); 436130678Sphk if (or == NULL) { 437130678Sphk free(ot, M_DEVFS); 438130678Sphk return; 43964880Sphk } 440130678Sphk devfs_overflow = ot; 441130678Sphk devfs_refoverflow = or; 442130678Sphk devfs_noverflow = n; 443130678Sphk printf("DEVFS Overflow table with %d entries allocated\n", n); 444130678Sphk return; 44564880Sphk} 44664880Sphk 447111730Sphkvoid 448130585Sphkdevfs_destroy(struct cdev *dev) 44964880Sphk{ 450130678Sphk int ino; 451130678Sphk struct cdev **dp; 45265515Sphk 45365515Sphk ino = dev->si_inode; 45465515Sphk dev->si_inode = 0; 45565515Sphk if (ino == 0) 45665515Sphk return; 457130678Sphk dp = devfs_itod(ino); 458130678Sphk KASSERT(*dp == dev, 459130678Sphk ("DEVFS: destroying wrong cdev ino %d", ino)); 460130678Sphk *dp = NULL; 461130678Sphk devfs_numino--; 462130678Sphk devfs_generation++; 463130678Sphk if (ino < devfs_nextino) 464130678Sphk devfs_nextino = ino; 46564880Sphk} 466