1 /*- 2 * Copyright (c) 2000,2004 3 * Poul-Henning Kamp. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Neither the name of the University nor the names of its contributors 11 * may be used to endorse or promote products derived from this software 12 * without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 27 * 28 * $FreeBSD$ 29 */ 30 31 #include "opt_devfs.h" 32 #include "opt_mac.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/dirent.h> 38 #include <sys/kernel.h> 39 #include <sys/lock.h> 40 #include <sys/mac.h> 41 #include <sys/malloc.h> 42 #include <sys/proc.h> 43 #include <sys/sysctl.h> 44 #include <sys/vnode.h> 45 46 #include <machine/atomic.h> 47 48 #include <fs/devfs/devfs.h> 49 #include <fs/devfs/devfs_int.h> 50 51 static struct cdev *devfs_inot[NDEVFSINO]; 52 static struct cdev **devfs_overflow; 53 static int devfs_ref[NDEVFSINO]; 54 static int *devfs_refoverflow; 55 static int devfs_nextino = 3; 56 static int devfs_numino; 57 static int devfs_topino; 58 static int devfs_noverflowwant = NDEVFSOVERFLOW; 59 static int devfs_noverflow; 60 static unsigned devfs_generation; 61 62 static struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen); 63 64 static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem"); 65 SYSCTL_UINT(_vfs_devfs, OID_AUTO, noverflow, CTLFLAG_RW, 66 &devfs_noverflowwant, 0, "Size of DEVFS overflow table"); 67 SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD, 68 &devfs_generation, 0, "DEVFS generation number"); 69 SYSCTL_UINT(_vfs_devfs, OID_AUTO, inodes, CTLFLAG_RD, 70 &devfs_numino, 0, "DEVFS inodes"); 71 SYSCTL_UINT(_vfs_devfs, OID_AUTO, topinode, CTLFLAG_RD, 72 &devfs_topino, 0, "DEVFS highest inode#"); 73 74 /* 75 * Helper sysctl for devname(3). We're given a struct cdev * and return 76 * the name, if any, registered by the device driver. 77 */ 78 static int 79 sysctl_devname(SYSCTL_HANDLER_ARGS) 80 { 81 int error; 82 dev_t ud; 83 struct cdev *dev, **dp; 84 85 error = SYSCTL_IN(req, &ud, sizeof (ud)); 86 if (error) 87 return (error); 88 if (ud == NODEV) 89 return(EINVAL); 90 dp = devfs_itod(ud); 91 if (dp == NULL) 92 return(ENOENT); 93 dev = *dp; 94 if (dev == NULL) 95 return(ENOENT); 96 return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1)); 97 return (error); 98 } 99 100 SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 101 NULL, 0, sysctl_devname, "", "devname(3) handler"); 102 103 SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD, 104 0, sizeof(struct cdev), "sizeof(struct cdev)"); 105 106 static int * 107 devfs_itor(int inode) 108 { 109 if (inode < NDEVFSINO) 110 return (&devfs_ref[inode]); 111 else if (inode < NDEVFSINO + devfs_noverflow) 112 return (&devfs_refoverflow[inode - NDEVFSINO]); 113 else 114 panic ("YRK!"); 115 } 116 117 static void 118 devfs_dropref(int inode) 119 { 120 int *ip; 121 122 ip = devfs_itor(inode); 123 atomic_add_int(ip, -1); 124 } 125 126 static int 127 devfs_getref(int inode) 128 { 129 int *ip, i, j; 130 struct cdev **dp; 131 132 ip = devfs_itor(inode); 133 dp = devfs_itod(inode); 134 for (;;) { 135 i = *ip; 136 j = i + 1; 137 if (!atomic_cmpset_int(ip, i, j)) 138 continue; 139 if (*dp != NULL) 140 return (1); 141 atomic_add_int(ip, -1); 142 return(0); 143 } 144 } 145 146 struct devfs_dirent ** 147 devfs_itode (struct devfs_mount *dm, int inode) 148 { 149 150 if (inode < 0) 151 return (NULL); 152 if (inode < NDEVFSINO) 153 return (&dm->dm_dirent[inode]); 154 if (devfs_overflow == NULL) 155 return (NULL); 156 if (inode < NDEVFSINO + devfs_noverflow) 157 return (&dm->dm_overflow[inode - NDEVFSINO]); 158 return (NULL); 159 } 160 161 struct cdev ** 162 devfs_itod (int inode) 163 { 164 165 if (inode < 0) 166 return (NULL); 167 if (inode < NDEVFSINO) 168 return (&devfs_inot[inode]); 169 if (devfs_overflow == NULL) 170 return (NULL); 171 if (inode < NDEVFSINO + devfs_noverflow) 172 return (&devfs_overflow[inode - NDEVFSINO]); 173 return (NULL); 174 } 175 176 static struct devfs_dirent * 177 devfs_find(struct devfs_dirent *dd, const char *name, int namelen) 178 { 179 struct devfs_dirent *de; 180 181 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 182 if (namelen != de->de_dirent->d_namlen) 183 continue; 184 if (bcmp(name, de->de_dirent->d_name, namelen) != 0) 185 continue; 186 break; 187 } 188 return (de); 189 } 190 191 struct devfs_dirent * 192 devfs_newdirent(char *name, int namelen) 193 { 194 int i; 195 struct devfs_dirent *de; 196 struct dirent d; 197 198 d.d_namlen = namelen; 199 i = sizeof (*de) + GENERIC_DIRSIZ(&d); 200 MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK | M_ZERO); 201 de->de_dirent = (struct dirent *)(de + 1); 202 de->de_dirent->d_namlen = namelen; 203 de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d); 204 bcopy(name, de->de_dirent->d_name, namelen); 205 de->de_dirent->d_name[namelen] = '\0'; 206 vfs_timestamp(&de->de_ctime); 207 de->de_mtime = de->de_atime = de->de_ctime; 208 de->de_links = 1; 209 #ifdef MAC 210 mac_init_devfsdirent(de); 211 #endif 212 return (de); 213 } 214 215 struct devfs_dirent * 216 devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot) 217 { 218 struct devfs_dirent *dd; 219 struct devfs_dirent *de; 220 221 dd = devfs_newdirent(name, namelen); 222 223 TAILQ_INIT(&dd->de_dlist); 224 225 dd->de_dirent->d_type = DT_DIR; 226 dd->de_mode = 0555; 227 dd->de_links = 2; 228 dd->de_dir = dd; 229 230 de = devfs_newdirent(".", 1); 231 de->de_dirent->d_type = DT_DIR; 232 de->de_dir = dd; 233 de->de_flags |= DE_DOT; 234 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 235 236 de = devfs_newdirent("..", 2); 237 de->de_dirent->d_type = DT_DIR; 238 if (dotdot == NULL) 239 de->de_dir = dd; 240 else 241 de->de_dir = dotdot; 242 de->de_flags |= DE_DOTDOT; 243 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 244 245 return (dd); 246 } 247 248 static void 249 devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de) 250 { 251 252 if (de->de_symlink) { 253 FREE(de->de_symlink, M_DEVFS); 254 de->de_symlink = NULL; 255 } 256 if (de->de_vnode) 257 de->de_vnode->v_data = NULL; 258 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 259 #ifdef MAC 260 mac_destroy_devfsdirent(de); 261 #endif 262 FREE(de, M_DEVFS); 263 } 264 265 void 266 devfs_purge(struct devfs_dirent *dd) 267 { 268 struct devfs_dirent *de; 269 270 for (;;) { 271 de = TAILQ_FIRST(&dd->de_dlist); 272 if (de == NULL) 273 break; 274 devfs_delete(dd, de); 275 } 276 FREE(dd, M_DEVFS); 277 } 278 279 280 int 281 devfs_populate(struct devfs_mount *dm) 282 { 283 int i, j; 284 struct cdev *dev, *pdev; 285 struct devfs_dirent *dd; 286 struct devfs_dirent *de, **dep; 287 char *q, *s; 288 289 if (dm->dm_generation == devfs_generation) 290 return (0); 291 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, curthread); 292 if (devfs_noverflow && dm->dm_overflow == NULL) { 293 i = devfs_noverflow * sizeof (struct devfs_dirent *); 294 MALLOC(dm->dm_overflow, struct devfs_dirent **, i, 295 M_DEVFS, M_WAITOK | M_ZERO); 296 } 297 while (dm->dm_generation != devfs_generation) { 298 dm->dm_generation = devfs_generation; 299 for (i = 0; i <= devfs_topino; i++) { 300 dev = *devfs_itod(i); 301 dep = devfs_itode(dm, i); 302 de = *dep; 303 if (dev == NULL && de == DE_DELETED) { 304 *dep = NULL; 305 continue; 306 } 307 if (dev == NULL && de != NULL) { 308 dd = de->de_dir; 309 *dep = NULL; 310 devfs_delete(dd, de); 311 devfs_dropref(i); 312 continue; 313 } 314 if (dev == NULL) 315 continue; 316 if (de != NULL) 317 continue; 318 if (!devfs_getref(i)) 319 continue; 320 dd = dm->dm_rootdir; 321 s = dev->si_name; 322 for (;;) { 323 for (q = s; *q != '/' && *q != '\0'; q++) 324 continue; 325 if (*q != '/') 326 break; 327 de = devfs_find(dd, s, q - s); 328 if (de == NULL) { 329 de = devfs_vmkdir(s, q - s, dd); 330 #ifdef MAC 331 mac_create_devfs_directory( 332 dm->dm_mount, s, q - s, de); 333 #endif 334 de->de_inode = dm->dm_inode++; 335 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 336 dd->de_links++; 337 } 338 s = q + 1; 339 dd = de; 340 } 341 de = devfs_newdirent(s, q - s); 342 if (dev->si_flags & SI_ALIAS) { 343 de->de_inode = dm->dm_inode++; 344 de->de_uid = 0; 345 de->de_gid = 0; 346 de->de_mode = 0755; 347 de->de_dirent->d_type = DT_LNK; 348 pdev = dev->si_parent; 349 j = strlen(pdev->si_name) + 1; 350 MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK); 351 bcopy(pdev->si_name, de->de_symlink, j); 352 } else { 353 de->de_inode = i; 354 de->de_uid = dev->si_uid; 355 de->de_gid = dev->si_gid; 356 de->de_mode = dev->si_mode; 357 de->de_dirent->d_type = DT_CHR; 358 } 359 #ifdef MAC 360 mac_create_devfs_device(dev->si_cred, dm->dm_mount, 361 dev, de); 362 #endif 363 *dep = de; 364 de->de_dir = dd; 365 devfs_rules_apply(dm, de); 366 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 367 } 368 } 369 lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, curthread); 370 return (0); 371 } 372 373 /* 374 * devfs_create() and devfs_destroy() are called from kern_conf.c and 375 * in both cases the devlock() mutex is held, so no further locking 376 * is necesary and no sleeping allowed. 377 */ 378 379 void 380 devfs_create(struct cdev *dev) 381 { 382 int ino, i, *ip; 383 struct cdev **dp; 384 struct cdev **ot; 385 int *or; 386 int n; 387 388 for (;;) { 389 /* Grab the next inode number */ 390 ino = devfs_nextino; 391 i = ino + 1; 392 /* wrap around when we reach the end */ 393 if (i >= NDEVFSINO + devfs_noverflow) 394 i = 3; 395 devfs_nextino = i; 396 397 /* see if it was occupied */ 398 dp = devfs_itod(ino); 399 KASSERT(dp != NULL, ("DEVFS: No devptr inode %d", ino)); 400 if (*dp != NULL) 401 continue; 402 ip = devfs_itor(ino); 403 KASSERT(ip != NULL, ("DEVFS: No iptr inode %d", ino)); 404 if (*ip != 0) 405 continue; 406 break; 407 } 408 409 *dp = dev; 410 dev->si_inode = ino; 411 if (i > devfs_topino) 412 devfs_topino = i; 413 414 devfs_numino++; 415 devfs_generation++; 416 417 if (devfs_overflow != NULL || devfs_numino + 100 < NDEVFSINO) 418 return; 419 420 /* 421 * Try to allocate overflow table 422 * XXX: we can probably be less panicy these days and a linked 423 * XXX: list of PAGESIZE/PTRSIZE entries might be a better idea. 424 * 425 * XXX: we may be into witness unlove here. 426 */ 427 n = devfs_noverflowwant; 428 ot = malloc(sizeof(*ot) * n, M_DEVFS, M_NOWAIT | M_ZERO); 429 if (ot == NULL) 430 return; 431 or = malloc(sizeof(*or) * n, M_DEVFS, M_NOWAIT | M_ZERO); 432 if (or == NULL) { 433 free(ot, M_DEVFS); 434 return; 435 } 436 devfs_overflow = ot; 437 devfs_refoverflow = or; 438 devfs_noverflow = n; 439 printf("DEVFS Overflow table with %d entries allocated\n", n); 440 return; 441 } 442 443 void 444 devfs_destroy(struct cdev *dev) 445 { 446 int ino; 447 struct cdev **dp; 448 449 ino = dev->si_inode; 450 dev->si_inode = 0; 451 if (ino == 0) 452 return; 453 dp = devfs_itod(ino); 454 KASSERT(*dp == dev, 455 ("DEVFS: destroying wrong cdev ino %d", ino)); 456 *dp = NULL; 457 devfs_numino--; 458 devfs_generation++; 459 if (ino < devfs_nextino) 460 devfs_nextino = ino; 461 } 462