1 #define DEBUG 1 2 /* 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 2000 6 * Poul-Henning Kamp. All rights reserved. 7 * 8 * This code is derived from software donated to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 33 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 34 * 35 * $FreeBSD$ 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/time.h> 42 #include <sys/conf.h> 43 #include <sys/vnode.h> 44 #include <sys/malloc.h> 45 #include <sys/proc.h> 46 #include <sys/stat.h> 47 #include <sys/mount.h> 48 #include <sys/namei.h> 49 #include <sys/dirent.h> 50 #include <sys/eventhandler.h> 51 52 #define DEVFS_INTERN 53 #include <fs/devfs/devfs.h> 54 55 static int devfs_access __P((struct vop_access_args *ap)); 56 static int devfs_badop __P((void)); 57 static int devfs_getattr __P((struct vop_getattr_args *ap)); 58 static int devfs_lookup __P((struct vop_lookup_args *ap)); 59 static int devfs_print __P((struct vop_print_args *ap)); 60 static int devfs_read __P((struct vop_read_args *ap)); 61 static int devfs_readdir __P((struct vop_readdir_args *ap)); 62 static int devfs_readlink __P((struct vop_readlink_args *ap)); 63 static int devfs_reclaim __P((struct vop_reclaim_args *ap)); 64 static int devfs_remove __P((struct vop_remove_args *ap)); 65 static int devfs_revoke __P((struct vop_revoke_args *ap)); 66 static int devfs_setattr __P((struct vop_setattr_args *ap)); 67 static int devfs_symlink __P((struct vop_symlink_args *ap)); 68 69 70 int 71 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p) 72 { 73 int error; 74 struct vnode *vp; 75 76 if (p == NULL) 77 p = curproc; /* XXX */ 78 loop: 79 vp = de->de_vnode; 80 if (vp != NULL) { 81 if (vget(vp, LK_EXCLUSIVE, p ? p : curproc)) 82 goto loop; 83 *vpp = vp; 84 return (0); 85 } 86 error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp); 87 if (error != 0) { 88 printf("devfs_allocv: failed to allocate new vnode\n"); 89 return (error); 90 } 91 92 if (de->de_dirent->d_type == DT_CHR) { 93 vp->v_type = VCHR; 94 vp = addaliasu(vp, devfs_inot[de->de_inode]->si_udev); 95 vp->v_op = devfs_specop_p; 96 } else if (de->de_dirent->d_type == DT_DIR) { 97 vp->v_type = VDIR; 98 } else if (de->de_dirent->d_type == DT_LNK) { 99 vp->v_type = VLNK; 100 } else { 101 vp->v_type = VBAD; 102 } 103 vp->v_data = de; 104 de->de_vnode = vp; 105 vhold(vp); 106 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 107 *vpp = vp; 108 return (0); 109 } 110 111 static int 112 devfs_access(ap) 113 struct vop_access_args /* { 114 struct vnode *a_vp; 115 int a_mode; 116 struct ucred *a_cred; 117 struct proc *a_p; 118 } */ *ap; 119 { 120 struct vnode *vp = ap->a_vp; 121 struct devfs_dirent *de; 122 123 de = vp->v_data; 124 if (vp->v_type == VDIR) 125 de = de->de_dir; 126 127 return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 128 ap->a_mode, ap->a_cred, NULL)); 129 } 130 131 static int 132 devfs_getattr(ap) 133 struct vop_getattr_args /* { 134 struct vnode *a_vp; 135 struct vattr *a_vap; 136 struct ucred *a_cred; 137 struct proc *a_p; 138 } */ *ap; 139 { 140 struct vnode *vp = ap->a_vp; 141 struct vattr *vap = ap->a_vap; 142 int error = 0; 143 struct devfs_dirent *de; 144 dev_t dev; 145 146 de = vp->v_data; 147 if (vp->v_type == VDIR) 148 de = de->de_dir; 149 bzero((caddr_t) vap, sizeof(*vap)); 150 vattr_null(vap); 151 vap->va_uid = de->de_uid; 152 vap->va_gid = de->de_gid; 153 vap->va_mode = de->de_mode; 154 vap->va_size = 0; 155 vap->va_blocksize = DEV_BSIZE; 156 if (vp->v_type != VCHR) { 157 vap->va_atime = de->de_atime; 158 vap->va_mtime = de->de_mtime; 159 vap->va_ctime = de->de_ctime; 160 } else { 161 dev = vp->v_rdev; 162 vap->va_atime = dev->si_atime; 163 vap->va_mtime = dev->si_mtime; 164 vap->va_ctime = dev->si_ctime; 165 } 166 vap->va_gen = 0; 167 vap->va_flags = 0; 168 vap->va_rdev = 0; 169 vap->va_bytes = 0; 170 vap->va_nlink = de->de_links; 171 vap->va_fileid = de->de_inode; 172 173 if (de->de_dirent->d_type == DT_DIR) { 174 vap->va_type = VDIR; 175 } else if (de->de_dirent->d_type == DT_LNK) { 176 vap->va_type = VLNK; 177 } else if (de->de_dirent->d_type == DT_CHR) { 178 vap->va_type = VCHR; 179 vap->va_rdev = devfs_inot[de->de_inode]->si_udev; 180 } 181 182 #ifdef DEBUG 183 if (error) 184 printf("devfs_getattr: return error %d\n", error); 185 #endif 186 return (error); 187 } 188 189 static int 190 devfs_lookup(ap) 191 struct vop_lookup_args /* { 192 struct vnode * a_dvp; 193 struct vnode ** a_vpp; 194 struct componentname * a_cnp; 195 } */ *ap; 196 { 197 struct componentname *cnp; 198 struct vnode *dvp, **vpp; 199 struct proc *p; 200 struct devfs_dirent *de, *dd; 201 struct devfs_mount *dmp; 202 dev_t cdev; 203 int error, cloned, i, flags, nameiop; 204 char specname[SPECNAMELEN + 1], *pname; 205 206 cnp = ap->a_cnp; 207 vpp = ap->a_vpp; 208 dvp = ap->a_dvp; 209 pname = cnp->cn_nameptr; 210 p = cnp->cn_proc; 211 flags = cnp->cn_flags; 212 nameiop = cnp->cn_nameiop; 213 dmp = VFSTODEVFS(dvp->v_mount); 214 cloned = 0; 215 dd = dvp->v_data; 216 217 *vpp = NULLVP; 218 219 if (nameiop == RENAME) 220 return (EOPNOTSUPP); 221 222 if (dvp->v_type != VDIR) 223 return (ENOTDIR); 224 225 if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) 226 return (EIO); 227 228 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); 229 if (error) 230 return (error); 231 232 if (cnp->cn_namelen == 1 && *pname == '.') { 233 if (nameiop != LOOKUP) 234 return (EINVAL); 235 *vpp = dvp; 236 VREF(dvp); 237 return (0); 238 } 239 240 if (flags & ISDOTDOT) { 241 if (nameiop != LOOKUP) 242 return (EINVAL); 243 VOP_UNLOCK(dvp, 0, p); 244 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 245 de = TAILQ_NEXT(de, de_list); /* ".." */ 246 de = de->de_dir; 247 error = devfs_allocv(de, dvp->v_mount, vpp, p); 248 if (error) { 249 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 250 return (error); 251 } 252 if ((flags & LOCKPARENT) && (flags & ISLASTCN)) 253 error = vn_lock(dvp, LK_EXCLUSIVE, p); 254 if (error) 255 vput(*vpp); 256 return (error); 257 } 258 259 devfs_populate(dmp); 260 dd = dvp->v_data; 261 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 262 if (cnp->cn_namelen != de->de_dirent->d_namlen) 263 continue; 264 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 265 de->de_dirent->d_namlen) != 0) 266 continue; 267 goto found; 268 } 269 270 /* 271 * OK, we didn't have an entry for the name we were asked for 272 * so we try to see if anybody can create it on demand. 273 * We need to construct the full "devname" for this device 274 * relative to "basedir" or the clone functions would not 275 * be able to tell "/dev/foo" from "/dev/bar/foo" 276 */ 277 i = SPECNAMELEN; 278 specname[i] = '\0'; 279 i -= cnp->cn_namelen; 280 if (i < 0) 281 goto notfound; 282 bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); 283 de = dd; 284 while (de != dmp->dm_basedir) { 285 i--; 286 if (i < 0) 287 goto notfound; 288 specname[i] = '/'; 289 i -= de->de_dirent->d_namlen; 290 if (i < 0) 291 goto notfound; 292 bcopy(de->de_dirent->d_name, specname + i, 293 de->de_dirent->d_namlen); 294 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 295 de = TAILQ_NEXT(de, de_list); /* ".." */ 296 de = de->de_dir; 297 } 298 299 #if 0 300 printf("Finished specname: %d \"%s\"\n", i, specname + i); 301 #endif 302 cdev = NODEV; 303 EVENTHANDLER_INVOKE(dev_clone, specname + i, 304 strlen(specname + i), &cdev); 305 #if 0 306 printf("cloned %s -> %p %s\n", specname + i, cdev, 307 cdev == NODEV ? "NODEV" : cdev->si_name); 308 #endif 309 if (cdev == NODEV) 310 goto notfound; 311 312 devfs_populate(dmp); 313 dd = dvp->v_data; 314 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 315 if (cnp->cn_namelen != de->de_dirent->d_namlen) 316 continue; 317 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 318 de->de_dirent->d_namlen) != 0) 319 continue; 320 goto found; 321 } 322 323 notfound: 324 325 if ((nameiop == CREATE || nameiop == RENAME) && 326 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 327 cnp->cn_flags |= SAVENAME; 328 if (!(flags & LOCKPARENT)) 329 VOP_UNLOCK(dvp, 0, p); 330 return (EJUSTRETURN); 331 } 332 return (ENOENT); 333 334 335 found: 336 337 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 338 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 339 if (error) 340 return (error); 341 if (*vpp == dvp) { 342 VREF(dvp); 343 *vpp = dvp; 344 return (0); 345 } 346 error = devfs_allocv(de, dvp->v_mount, vpp, p); 347 if (error) 348 return (error); 349 if (!(flags & LOCKPARENT)) 350 VOP_UNLOCK(dvp, 0, p); 351 return (0); 352 } 353 error = devfs_allocv(de, dvp->v_mount, vpp, p); 354 if (error) 355 return (error); 356 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) 357 VOP_UNLOCK(dvp, 0, p); 358 return (0); 359 } 360 361 /* ARGSUSED */ 362 static int 363 devfs_print(ap) 364 struct vop_print_args /* { 365 struct vnode *a_vp; 366 } */ *ap; 367 { 368 369 printf("tag VT_DEVFS, devfs vnode\n"); 370 return (0); 371 } 372 373 static int 374 devfs_read(ap) 375 struct vop_read_args /* { 376 struct vnode *a_vp; 377 struct uio *a_uio; 378 int a_ioflag; 379 struct ucred *a_cred; 380 } */ *ap; 381 { 382 383 if (ap->a_vp->v_type != VDIR) 384 return (EINVAL); 385 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 386 } 387 388 static int 389 devfs_readdir(ap) 390 struct vop_readdir_args /* { 391 struct vnode *a_vp; 392 struct uio *a_uio; 393 struct ucred *a_cred; 394 int *a_eofflag; 395 int *a_ncookies; 396 u_long **a_cookies; 397 } */ *ap; 398 { 399 int error; 400 struct uio *uio; 401 struct dirent *dp; 402 struct devfs_dirent *dd; 403 struct devfs_dirent *de; 404 struct devfs_mount *dmp; 405 off_t off; 406 407 if (ap->a_vp->v_type != VDIR) 408 return (ENOTDIR); 409 410 if (ap->a_ncookies) 411 return (EOPNOTSUPP); 412 413 uio = ap->a_uio; 414 if (uio->uio_offset < 0) 415 return (EINVAL); 416 417 dmp = VFSTODEVFS(ap->a_vp->v_mount); 418 devfs_populate(dmp); 419 error = 0; 420 de = ap->a_vp->v_data; 421 dd = TAILQ_FIRST(&de->de_dlist); 422 off = 0; 423 while (dd != NULL) { 424 if (dd->de_dirent->d_type == DT_DIR) 425 de = dd->de_dir; 426 else 427 de = dd; 428 dp = dd->de_dirent; 429 if (dp->d_reclen > uio->uio_resid) 430 break; 431 dp->d_fileno = de->de_inode; 432 if (off >= uio->uio_offset) { 433 error = uiomove((caddr_t)dp, dp->d_reclen, uio); 434 if (error) 435 break; 436 } 437 off += dp->d_reclen; 438 dd = TAILQ_NEXT(dd, de_list); 439 } 440 uio->uio_offset = off; 441 return (error); 442 } 443 444 static int 445 devfs_readlink(ap) 446 struct vop_readlink_args /* { 447 struct vnode *a_vp; 448 struct uio *a_uio; 449 struct ucred *a_cead; 450 } */ *ap; 451 { 452 int error; 453 struct devfs_dirent *de; 454 455 de = ap->a_vp->v_data; 456 error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio); 457 return (error); 458 } 459 460 static int 461 devfs_reclaim(ap) 462 struct vop_reclaim_args /* { 463 struct vnode *a_vp; 464 } */ *ap; 465 { 466 struct vnode *vp = ap->a_vp; 467 struct devfs_dirent *de; 468 469 de = vp->v_data; 470 if (de != NULL && de->de_flags & DE_ORPHAN) { 471 if (de->de_symlink) 472 FREE(de->de_symlink, M_DEVFS); 473 FREE(de, M_DEVFS); 474 } 475 vp->v_data = NULL; 476 return (0); 477 } 478 479 static int 480 devfs_remove(ap) 481 struct vop_remove_args /* { 482 struct vnode *a_dvp; 483 struct vnode *a_vp; 484 struct componentname *a_cnp; 485 } */ *ap; 486 { 487 struct vnode *vp = ap->a_vp; 488 struct devfs_dirent *dd; 489 struct devfs_dirent *de; 490 struct devfs_mount *dm = VFSTODEVFS(vp->v_mount); 491 492 dd = ap->a_dvp->v_data; 493 de = vp->v_data; 494 de->de_flags |= DE_ORPHAN; 495 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 496 if (de->de_inode < NDEVINO) 497 dm->dm_dirent[de->de_inode] = DE_DELETED; 498 vdrop(de->de_vnode); 499 return (0); 500 } 501 502 /* 503 * Revoke is called on a tty when a terminal session ends. The vnode 504 * is orphaned by setting v_op to deadfs so we need to let go of it 505 * as well so that we create a new one next time around. 506 */ 507 static int 508 devfs_revoke(ap) 509 struct vop_revoke_args /* { 510 struct vnode *a_vp; 511 int a_flags; 512 } */ *ap; 513 { 514 struct vnode *vp = ap->a_vp; 515 struct devfs_dirent *de; 516 517 de = vp->v_data; 518 if (!(de->de_flags & DE_ORPHAN)) 519 vdrop(de->de_vnode); 520 de->de_vnode = NULL; 521 vop_revoke(ap); 522 return (0); 523 } 524 525 static int 526 devfs_setattr(ap) 527 struct vop_setattr_args /* { 528 struct vnode *a_vp; 529 struct vattr *a_vap; 530 struct ucred *a_cred; 531 struct proc *a_p; 532 } */ *ap; 533 { 534 struct devfs_dirent *de; 535 int c; 536 537 de = ap->a_vp->v_data; 538 if (ap->a_vp->v_type == VDIR) 539 de = de->de_dir; 540 541 c = 0; 542 if (ap->a_vap->va_flags != VNOVAL) 543 return (EOPNOTSUPP); 544 if (ap->a_vap->va_uid != (uid_t)VNOVAL) { 545 de->de_uid = ap->a_vap->va_uid; 546 c = 1; 547 } 548 if (ap->a_vap->va_gid != (gid_t)VNOVAL) { 549 de->de_gid = ap->a_vap->va_gid; 550 c = 1; 551 } 552 if (ap->a_vap->va_mode != (mode_t)VNOVAL) { 553 de->de_mode = ap->a_vap->va_mode; 554 c = 1; 555 } 556 if (ap->a_vap->va_atime.tv_sec != VNOVAL) 557 de->de_atime = ap->a_vap->va_atime; 558 if (ap->a_vap->va_mtime.tv_sec != VNOVAL) 559 de->de_mtime = ap->a_vap->va_mtime; 560 561 if (c) 562 getnanotime(&de->de_ctime); 563 return (0); 564 } 565 566 static int 567 devfs_symlink(ap) 568 struct vop_symlink_args /* { 569 struct vnode *a_dvp; 570 struct vnode **a_vpp; 571 struct componentname *a_cnp; 572 struct vattr *a_vap; 573 char *a_target; 574 } */ *ap; 575 { 576 int i; 577 struct devfs_dirent *dd; 578 struct devfs_dirent *de; 579 struct devfs_mount *dmp; 580 581 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 582 dd = ap->a_dvp->v_data; 583 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 584 de->de_uid = 0; 585 de->de_gid = 0; 586 de->de_mode = 0642; 587 de->de_inode = dmp->dm_inode++; 588 de->de_dirent->d_type = DT_LNK; 589 i = strlen(ap->a_target) + 1; 590 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 591 bcopy(ap->a_target, de->de_symlink, i); 592 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 593 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 594 return (0); 595 } 596 597 /* 598 * DEVFS "should never get here" operation 599 */ 600 static int 601 devfs_badop() 602 { 603 return (EIO); 604 } 605 606 vop_t **devfs_vnodeop_p; 607 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 608 { &vop_default_desc, (vop_t *) vop_defaultop }, 609 { &vop_access_desc, (vop_t *) devfs_access }, 610 { &vop_bmap_desc, (vop_t *) devfs_badop }, 611 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 612 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 613 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, 614 { &vop_print_desc, (vop_t *) devfs_print }, 615 { &vop_read_desc, (vop_t *) devfs_read }, 616 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 617 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 618 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 619 { &vop_remove_desc, (vop_t *) devfs_remove }, 620 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 621 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 622 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 623 { NULL, NULL } 624 }; 625 static struct vnodeopv_desc devfs_vnodeop_opv_desc = 626 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 627 628 VNODEOP_SET(devfs_vnodeop_opv_desc); 629 630 #if 0 631 int 632 foo(ap) 633 struct vop_generic_args *ap; 634 { 635 int i; 636 637 i = spec_vnoperate(ap); 638 printf("foo(%s) = %d\n", ap->a_desc->vdesc_name, i); 639 return (i); 640 } 641 #endif 642 643 vop_t **devfs_specop_p; 644 static struct vnodeopv_entry_desc devfs_specop_entries[] = { 645 #if 1 646 { &vop_default_desc, (vop_t *) spec_vnoperate }, 647 #else 648 { &vop_default_desc, (vop_t *) foo }, 649 { &vop_lock_desc, (vop_t *) spec_vnoperate }, 650 { &vop_unlock_desc, (vop_t *) spec_vnoperate }, 651 { &vop_lease_desc, (vop_t *) spec_vnoperate }, 652 { &vop_strategy_desc, (vop_t *) spec_vnoperate }, 653 { &vop_bmap_desc, (vop_t *) spec_vnoperate }, 654 #endif 655 { &vop_access_desc, (vop_t *) devfs_access }, 656 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 657 { &vop_print_desc, (vop_t *) devfs_print }, 658 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 659 { &vop_remove_desc, (vop_t *) devfs_remove }, 660 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 661 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 662 { NULL, NULL } 663 }; 664 static struct vnodeopv_desc devfs_specop_opv_desc = 665 { &devfs_specop_p, devfs_specop_entries }; 666 667 VNODEOP_SET(devfs_specop_opv_desc); 668