1 /* 2 * Copyright (c) 2013 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Antonio Huete Jimenez <tuxillo@quantumachine.net> 6 * by Matthew Dillon <dillon@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37 /* 38 * See below a small table with the vnode operation and syscall correspondence 39 * where it applies: 40 * 41 * VNODE OP SCALL SCALL_AT FD PATH COMMENTS 42 * dirfs_ncreate Y Y Y Y open(2), openat(2) 43 * dirfs_nresolve - - - Y no syscall needed 44 * dirfs_nlookupdot - - - - - 45 * dirfs_nmknod Y Y Y Y mknod(2), mknodat(2) 46 * dirfs_open Y Y Y Y open(2), openat(2) 47 * dirfs_close Y Y Y Y close(2) 48 * dirfs_access - - - - data from stat(2) 49 * dirfs_getattr Y Y Y Y lstat(2), fstatat(2) 50 * dirfs_setattr - - - - - 51 * dirfs_read Y - Y - read(2). 52 * dirfs_write Y - Y - write(2). 53 * dirfs_fsync Y - Y - fsync(2) 54 * dirfs_mountctl - - - - - 55 * dirfs_nremove Y - - Y unlink(2) 56 * dirfs_nlink - - - - - 57 * dirfs_nrename Y Y Y Y rename(2), renameat(2) 58 * dirfs_nmkdir Y Y Y Y mkdir(2), mkdirat(2) 59 * dirfs_nrmdir Y - - Y rmdir(2) 60 * dirfs_nsymlink Y Y Y Y symlink(2), symlinkat(2) 61 * dirfs_readdir Y - Y - getdirentries(2) 62 * dirfs_readlink Y Y Y Y readlinkat(2) 63 * dirfs_inactive - - - - - 64 * dirfs_reclaim - - - - - 65 * dirfs_print - - - - - 66 * dirfs_pathconf - - - - - 67 * dirfs_bmap - - - - - 68 * dirfs_strategy Y - Y - pwrite(2), pread(2) 69 * dirfs_advlock - - - - - 70 * dirfs_kqfilter - - - - - 71 */ 72 73 #include <stdio.h> 74 #include <errno.h> 75 #include <strings.h> 76 #include <unistd.h> 77 78 #include <sys/vfsops.h> 79 #include <sys/vnode.h> 80 #include <sys/stat.h> 81 #include <sys/namecache.h> 82 #include <sys/queue.h> 83 #include <sys/systm.h> 84 #include <sys/dirent.h> 85 #include <sys/mount.h> 86 #include <sys/signalvar.h> 87 #include <sys/resource.h> 88 #include <sys/buf2.h> 89 #include <sys/kern_syscall.h> 90 #include <sys/ktr.h> 91 92 #include "dirfs.h" 93 94 /* 95 * Kernel tracing facilities 96 */ 97 KTR_INFO_MASTER_EXTERN(dirfs); 98 99 KTR_INFO(KTR_DIRFS, dirfs, unsupported, 0, 100 "DIRFS(func=%s)", 101 const char *func); 102 103 KTR_INFO(KTR_DIRFS, dirfs, nresolve, 0, 104 "DIRFS(dnp=%p ncp_name=%s parent=%p pfd=%d error=%d)", 105 dirfs_node_t dnp, char *name, dirfs_node_t pdnp, int pfd, int error); 106 107 KTR_INFO(KTR_DIRFS, dirfs, ncreate, 1, 108 "DIRFS(dnp=%p ncp_name=%s parent=%p pfd=%d error=%d)", 109 dirfs_node_t dnp, char *name, dirfs_node_t pdnp, int pfd, int error); 110 111 KTR_INFO(KTR_DIRFS, dirfs, open, 2, 112 "DIRFS(dnp=%p dn_name=%s nfd=%d)", 113 dirfs_node_t dnp, char *name, int fd); 114 115 KTR_INFO(KTR_DIRFS, dirfs, close, 3, 116 "DIRFS(dnp=%p fd=%d opencount=%d writecount=%d vfsync error=%d)", 117 dirfs_node_t dnp, int fd, int oc, int wc, int error); 118 119 KTR_INFO(KTR_DIRFS, dirfs, readdir, 4, 120 "DIRFS(dnp=%p fd=%d startoff=%jd uio_offset=%jd)", 121 dirfs_node_t dnp, int fd, off_t startoff, off_t uoff); 122 123 KTR_INFO(KTR_DIRFS, dirfs, access, 5, 124 "DIRFS(dnp=%p error=%d)", 125 dirfs_node_t dnp, int error); 126 127 KTR_INFO(KTR_DIRFS, dirfs, getattr, 6, 128 "DIRFS(dnp=%p error=%d)", 129 dirfs_node_t dnp, int error); 130 131 KTR_INFO(KTR_DIRFS, dirfs, setattr, 7, 132 "DIRFS(dnp=%p action=%s error=%d)", 133 dirfs_node_t dnp, const char *action, int error); 134 135 KTR_INFO(KTR_DIRFS, dirfs, fsync, 8, 136 "DIRFS(dnp=%p error=%d)", 137 dirfs_node_t dnp, int error); 138 139 KTR_INFO(KTR_DIRFS, dirfs, read, 9, 140 "DIRFS(dnp=%p size=%jd error=%d)", 141 dirfs_node_t dnp, size_t size, int error); 142 143 KTR_INFO(KTR_DIRFS, dirfs, write, 10, 144 "DIRFS(dnp=%p size=%jd boff=%jd uio_resid=%jd error=%d)", 145 dirfs_node_t dnp, off_t boff, size_t resid, size_t size, int error); 146 147 KTR_INFO(KTR_DIRFS, dirfs, strategy, 11, 148 "DIRFS(dnp=%p dnp_size=%jd iosize=%jd b_cmd=%d b_error=%d " 149 "b_resid=%d bio_off=%jd error=%d)", 150 dirfs_node_t dnp, size_t size, size_t iosize, int cmd, int berror, 151 int bresid, off_t biooff, int error); 152 153 KTR_INFO(KTR_DIRFS, dirfs, nremove, 12, 154 "DIRFS(dnp=%p pdnp=%p error=%d)", 155 dirfs_node_t dnp, dirfs_node_t pdnp, int error); 156 157 KTR_INFO(KTR_DIRFS, dirfs, nmkdir, 13, 158 "DIRFS(pdnp=%p dnp=%p nc_name=%p error=%d)", 159 dirfs_node_t dnp, dirfs_node_t pdnp, char *n, int error); 160 161 KTR_INFO(KTR_DIRFS, dirfs, nrmdir, 13, 162 "DIRFS(pdnp=%p dnp=%p error=%d)", 163 dirfs_node_t dnp, dirfs_node_t pdnp, int error); 164 165 KTR_INFO(KTR_DIRFS, dirfs, nsymlink, 14, 166 "DIRFS(dnp=%p target=%s symlink=%s error=%d)", 167 dirfs_node_t dnp, char *tgt, char *lnk, int error); 168 169 /* Needed prototypes */ 170 int dirfs_access(struct vop_access_args *); 171 int dirfs_getattr(struct vop_getattr_args *); 172 int dirfs_setattr(struct vop_setattr_args *); 173 int dirfs_reclaim(struct vop_reclaim_args *); 174 175 static int 176 dirfs_nresolve(struct vop_nresolve_args *ap) 177 { 178 dirfs_node_t pdnp, dnp, d1, d2; 179 dirfs_mount_t dmp; 180 struct namecache *ncp; 181 struct nchandle *nch; 182 struct vnode *dvp; 183 struct vnode *vp; 184 struct mount *mp; 185 int error; 186 187 debug_called(); 188 189 error = 0; 190 nch = ap->a_nch; 191 ncp = nch->ncp; 192 mp = nch->mount; 193 dvp = ap->a_dvp; 194 vp = NULL; 195 dnp = d1 = d2 = NULL; 196 pdnp = VP_TO_NODE(dvp); 197 dmp = VFS_TO_DIRFS(mp); 198 199 dirfs_node_lock(pdnp); 200 TAILQ_FOREACH_MUTABLE(d1, &dmp->dm_fdlist, dn_fdentry, d2) { 201 if (d1->dn_parent == pdnp && 202 (strcmp(d1->dn_name, ncp->nc_name) == 0)) { 203 dnp = d1; 204 dirfs_node_ref(dnp); 205 passive_fd_list_hits++; 206 break; 207 } 208 } 209 dirfs_node_unlock(pdnp); 210 211 if (dnp) { 212 dirfs_alloc_vp(mp, &vp, LK_CANRECURSE, dnp); 213 dirfs_node_drop(dmp, dnp); 214 } else { 215 passive_fd_list_miss++; 216 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, &vp, NULL, 0); 217 } 218 219 if (vp) { 220 if ((vp->v_refcnt & VREF_FINALIZE) == 0) 221 atomic_set_int(&vp->v_refcnt, VREF_FINALIZE); 222 223 if (error && error == ENOENT) { 224 cache_setvp(nch, NULL); 225 } else { 226 vn_unlock(vp); 227 cache_setvp(nch, vp); 228 vrele(vp); 229 } 230 } 231 232 KTR_LOG(dirfs_nresolve, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error); 233 234 return error; 235 } 236 237 static int 238 dirfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap) 239 { 240 debug_called(); 241 242 KTR_LOG(dirfs_unsupported, __func__); 243 244 return EOPNOTSUPP; 245 } 246 247 static int 248 dirfs_ncreate(struct vop_ncreate_args *ap) 249 { 250 dirfs_node_t pdnp; 251 dirfs_node_t dnp; 252 dirfs_mount_t dmp; 253 struct namecache *ncp; 254 struct vnode *dvp; 255 struct vnode **vpp; 256 struct vattr *vap; 257 int perms = 0; 258 int error; 259 260 debug_called(); 261 262 error = 0; 263 dnp = NULL; 264 dvp = ap->a_dvp; 265 pdnp = VP_TO_NODE(dvp); 266 dmp = VFS_TO_DIRFS(dvp->v_mount); 267 vap = ap->a_vap; 268 ncp = ap->a_nch->ncp; 269 vpp = ap->a_vpp; 270 271 dirfs_mount_gettoken(dmp); 272 273 dirfs_node_getperms(pdnp, &perms); 274 if ((perms & DIRFS_NODE_WR) == 0) 275 error = EPERM; 276 277 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, vap, 278 (O_CREAT | O_RDWR)); 279 280 if (error == 0) { 281 cache_setunresolved(ap->a_nch); 282 cache_setvp(ap->a_nch, *vpp); 283 } 284 285 dirfs_mount_reltoken(dmp); 286 287 KTR_LOG(dirfs_ncreate, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error); 288 289 return error; 290 } 291 292 static int 293 dirfs_nmknod(struct vop_nmknod_args *v) 294 { 295 debug_called(); 296 297 return EOPNOTSUPP; 298 } 299 300 static int 301 dirfs_open(struct vop_open_args *ap) 302 { 303 dirfs_node_t dnp; 304 dirfs_mount_t dmp; 305 struct vnode *vp; 306 int error; 307 308 debug_called(); 309 310 vp = ap->a_vp; 311 dnp = VP_TO_NODE(vp); 312 dmp = VFS_TO_DIRFS(vp->v_mount); 313 error = 0; 314 315 /* 316 * Root inode has been allocated and opened in VFS_ROOT() so 317 * no reason to attempt to open it again. 318 */ 319 if (dmp->dm_root != dnp && dnp->dn_fd == DIRFS_NOFD) { 320 error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL); 321 if (error) 322 return error; 323 } 324 325 KTR_LOG(dirfs_open, dnp, dnp->dn_name, dnp->dn_fd); 326 327 return vop_stdopen(ap); 328 } 329 330 static int 331 dirfs_close(struct vop_close_args *ap) 332 { 333 struct vnode *vp; 334 dirfs_node_t dnp; 335 int error; 336 337 debug_called(); 338 339 error = 0; 340 vp = ap->a_vp; 341 dnp = VP_TO_NODE(vp); 342 343 if (vp->v_type == VREG) { 344 error = vfsync(vp, 0, 1, NULL, NULL); 345 if (error) 346 dbg(5, "vfsync error=%d\n", error); 347 } 348 vop_stdclose(ap); 349 350 KTR_LOG(dirfs_close, dnp, dnp->dn_fd, vp->v_opencount, 351 vp->v_writecount, error); 352 353 return 0; 354 } 355 356 int 357 dirfs_access(struct vop_access_args *ap) 358 { 359 struct vnode *vp = ap->a_vp; 360 int error; 361 dirfs_node_t dnp; 362 363 debug_called(); 364 365 dnp = VP_TO_NODE(vp); 366 367 switch (vp->v_type) { 368 case VDIR: 369 /* FALLTHROUGH */ 370 case VLNK: 371 /* FALLTHROUGH */ 372 case VREG: 373 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 374 error = EROFS; 375 goto out; 376 } 377 break; 378 case VBLK: 379 /* FALLTHROUGH */ 380 case VCHR: 381 /* FALLTHROUGH */ 382 case VSOCK: 383 /* FALLTHROUGH */ 384 case VFIFO: 385 break; 386 387 default: 388 error = EINVAL; 389 goto out; 390 } 391 392 error = vop_helper_access(ap, dnp->dn_uid, 393 dnp->dn_gid, dnp->dn_mode, 0); 394 395 out: 396 KTR_LOG(dirfs_access, dnp, error); 397 398 return error; 399 } 400 401 int 402 dirfs_getattr(struct vop_getattr_args *ap) 403 { 404 dirfs_mount_t dmp; 405 dirfs_node_t dnp; 406 dirfs_node_t pathnp; 407 struct vnode *vp; 408 struct vattr *vap; 409 char *tmp; 410 char *pathfree; 411 int error; 412 413 debug_called(); 414 415 vp = ap->a_vp; 416 vap = ap->a_vap; 417 dnp = VP_TO_NODE(vp); 418 dmp = VFS_TO_DIRFS(vp->v_mount); 419 420 KKASSERT(dnp); /* This must not happen */ 421 422 if (!dirfs_node_isroot(dnp)) { 423 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 424 425 KKASSERT(pathnp->dn_fd != DIRFS_NOFD); 426 427 error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp); 428 dirfs_dropfd(dmp, pathnp, pathfree); 429 } else { 430 error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp); 431 } 432 433 if (error == 0) { 434 dirfs_node_lock(dnp); 435 vap->va_nlink = dnp->dn_links; 436 vap->va_type = dnp->dn_type; 437 vap->va_mode = dnp->dn_mode; 438 vap->va_uid = dnp->dn_uid; 439 vap->va_gid = dnp->dn_gid; 440 vap->va_fileid = dnp->dn_ino; 441 vap->va_size = dnp->dn_size; 442 vap->va_blocksize = dnp->dn_blocksize; 443 vap->va_atime.tv_sec = dnp->dn_atime; 444 vap->va_atime.tv_nsec = dnp->dn_atimensec; 445 vap->va_mtime.tv_sec = dnp->dn_mtime; 446 vap->va_mtime.tv_nsec = dnp->dn_mtimensec; 447 vap->va_ctime.tv_sec = dnp->dn_ctime; 448 vap->va_ctime.tv_nsec = dnp->dn_ctimensec; 449 vap->va_bytes = dnp->dn_size; 450 vap->va_gen = dnp->dn_gen; 451 vap->va_flags = dnp->dn_flags; 452 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 453 dirfs_node_unlock(dnp); 454 } 455 456 KTR_LOG(dirfs_getattr, dnp, error); 457 458 return 0; 459 } 460 461 int 462 dirfs_setattr(struct vop_setattr_args *ap) 463 { 464 dirfs_mount_t dmp; 465 dirfs_node_t dnp; 466 struct vnode *vp; 467 struct vattr *vap; 468 struct ucred *cred; 469 int error; 470 #ifdef KTR 471 const char *msg[6] = { 472 "invalid", 473 "chflags", 474 "chsize", 475 "chown", 476 "chmod", 477 "chtimes" 478 }; 479 #endif 480 int msgno; 481 482 debug_called(); 483 484 error = msgno = 0; 485 vp = ap->a_vp; 486 vap = ap->a_vap; 487 cred = ap->a_cred; 488 dnp = VP_TO_NODE(vp); 489 dmp = VFS_TO_DIRFS(vp->v_mount); 490 491 dirfs_mount_gettoken(dmp); 492 493 /* 494 * Check for unsettable attributes. 495 */ 496 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 497 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 498 (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) || 499 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 500 msgno = 0; 501 error = EINVAL; 502 goto out; 503 } 504 505 /* 506 * Change file flags 507 */ 508 if (error == 0 && (vap->va_flags != VNOVAL)) { 509 if (vp->v_mount->mnt_flag & MNT_RDONLY) 510 error = EROFS; 511 else 512 error = dirfs_node_chflags(dnp, vap->va_flags, cred); 513 msgno = 1; 514 goto out; 515 } 516 517 /* 518 * Extend or truncate a file 519 */ 520 if (error == 0 && (vap->va_size != VNOVAL)) { 521 if (vp->v_mount->mnt_flag & MNT_RDONLY) 522 error = EROFS; 523 else 524 error = dirfs_node_chsize(dnp, vap->va_size); 525 dbg(2, "dnp size=%jd vap size=%jd\n", dnp->dn_size, vap->va_size); 526 msgno = 2; 527 goto out; 528 } 529 530 /* 531 * Change file owner or group 532 */ 533 if (error == 0 && (vap->va_uid != (uid_t)VNOVAL || 534 vap->va_gid != (gid_t)VNOVAL)) { 535 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 536 error = EROFS; 537 } else { 538 mode_t cur_mode = dnp->dn_mode; 539 uid_t cur_uid = dnp->dn_uid; 540 gid_t cur_gid = dnp->dn_gid; 541 542 error = vop_helper_chown(ap->a_vp, vap->va_uid, 543 vap->va_gid, ap->a_cred, 544 &cur_uid, &cur_gid, &cur_mode); 545 if (error == 0 && 546 (cur_mode != dnp->dn_mode || 547 cur_uid != dnp->dn_uid || 548 cur_gid != dnp->dn_gid)) { 549 error = dirfs_node_chown(dmp, dnp, cur_uid, 550 cur_gid, cur_mode); 551 } 552 } 553 msgno = 3; 554 goto out; 555 } 556 557 /* 558 * Change file mode 559 */ 560 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) { 561 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 562 error = EROFS; 563 } else { 564 mode_t cur_mode = dnp->dn_mode; 565 uid_t cur_uid = dnp->dn_uid; 566 gid_t cur_gid = dnp->dn_gid; 567 568 error = vop_helper_chmod(ap->a_vp, vap->va_mode, 569 ap->a_cred, 570 cur_uid, cur_gid, &cur_mode); 571 if (error == 0 && cur_mode != dnp->dn_mode) { 572 error = dirfs_node_chmod(dmp, dnp, cur_mode); 573 } 574 } 575 msgno = 4; 576 goto out; 577 } 578 579 /* 580 * Change file times 581 */ 582 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 583 vap->va_atime.tv_nsec != VNOVAL) || 584 (vap->va_mtime.tv_sec != VNOVAL && 585 vap->va_mtime.tv_nsec != VNOVAL) )) { 586 if (vp->v_mount->mnt_flag & MNT_RDONLY) 587 error = EROFS; 588 else 589 error = dirfs_node_chtimes(dnp); 590 msgno = 5; 591 goto out; 592 593 } 594 out: 595 dirfs_mount_reltoken(dmp); 596 597 KTR_LOG(dirfs_setattr, dnp, msg[msgno], error); 598 599 return error; 600 } 601 602 static int 603 dirfs_fsync(struct vop_fsync_args *ap) 604 { 605 dirfs_node_t dnp = VP_TO_NODE(ap->a_vp); 606 int error = 0; 607 608 debug_called(); 609 610 vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL); 611 612 if (dnp->dn_fd != DIRFS_NOFD) { 613 if (fsync(dnp->dn_fd) == -1) 614 error = fsync(dnp->dn_fd); 615 } 616 617 KTR_LOG(dirfs_fsync, dnp, error); 618 619 return 0; 620 } 621 622 static int 623 dirfs_read(struct vop_read_args *ap) 624 { 625 struct buf *bp; 626 struct vnode *vp = ap->a_vp; 627 struct uio *uio = ap->a_uio; 628 dirfs_node_t dnp; 629 off_t base_offset; 630 size_t offset; 631 size_t len; 632 int error; 633 634 debug_called(); 635 636 error = 0; 637 if (uio->uio_resid == 0) { 638 dbg(5, "zero len uio->uio_resid\n"); 639 return error; 640 } 641 642 dnp = VP_TO_NODE(vp); 643 644 if (uio->uio_offset < 0) 645 return (EINVAL); 646 if (vp->v_type != VREG) 647 return (EINVAL); 648 649 while (uio->uio_resid > 0 && uio->uio_offset < dnp->dn_size) { 650 /* 651 * Use buffer cache I/O (via dirfs_strategy) 652 */ 653 offset = (size_t)uio->uio_offset & BMASK; 654 base_offset = (off_t)uio->uio_offset - offset; 655 bp = getcacheblk(vp, base_offset, BSIZE, 0); 656 if (bp == NULL) { 657 lwkt_gettoken(&vp->v_mount->mnt_token); 658 error = bread(vp, base_offset, BSIZE, &bp); 659 if (error) { 660 brelse(bp); 661 lwkt_reltoken(&vp->v_mount->mnt_token); 662 dbg(5, "dirfs_read bread error %d\n", error); 663 break; 664 } 665 lwkt_reltoken(&vp->v_mount->mnt_token); 666 } 667 668 /* 669 * Figure out how many bytes we can actually copy this loop. 670 */ 671 len = BSIZE - offset; 672 if (len > uio->uio_resid) 673 len = uio->uio_resid; 674 if (len > dnp->dn_size - uio->uio_offset) 675 len = (size_t)(dnp->dn_size - uio->uio_offset); 676 677 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); 678 bqrelse(bp); 679 if (error) { 680 dbg(5, "dirfs_read uiomove error %d\n", error); 681 break; 682 } 683 } 684 685 KTR_LOG(dirfs_read, dnp, dnp->dn_size, error); 686 687 return(error); 688 } 689 690 static int 691 dirfs_write (struct vop_write_args *ap) 692 { 693 dirfs_node_t dnp; 694 dirfs_mount_t dmp; 695 struct buf *bp; 696 struct vnode *vp = ap->a_vp; 697 struct uio *uio = ap->a_uio; 698 struct thread *td = uio->uio_td; 699 int error; 700 off_t osize; 701 off_t nsize; 702 off_t base_offset; 703 size_t offset; 704 size_t len; 705 struct rlimit limit; 706 707 debug_called(); 708 709 error = 0; 710 if (uio->uio_resid == 0) { 711 dbg(5, "zero-length uio->uio_resid\n"); 712 return error; 713 } 714 715 dnp = VP_TO_NODE(vp); 716 dmp = VFS_TO_DIRFS(vp->v_mount); 717 718 if (vp->v_type != VREG) 719 return (EINVAL); 720 721 if (vp->v_type == VREG && td != NULL) { 722 error = kern_getrlimit(RLIMIT_FSIZE, &limit); 723 if (error != 0) { 724 dbg(5, "rlimit failure\n"); 725 return error; 726 } 727 if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) { 728 dbg(5, "file too big\n"); 729 ksignal(td->td_proc, SIGXFSZ); 730 return (EFBIG); 731 } 732 } 733 734 if (ap->a_ioflag & IO_APPEND) 735 uio->uio_offset = dnp->dn_size; 736 737 /* 738 * buffer cache operations may be deferred, make sure 739 * the file is correctly sized right now. 740 */ 741 osize = dnp->dn_size; 742 nsize = uio->uio_offset + uio->uio_resid; 743 if (nsize > osize && uio->uio_resid) { 744 KKASSERT(dnp->dn_fd >= 0); 745 dnp->dn_size = nsize; 746 ftruncate(dnp->dn_fd, nsize); 747 nvextendbuf(vp, osize, nsize, 748 BSIZE, BSIZE, -1, -1, 0); 749 } /* else nsize = osize; NOT USED */ 750 751 while (uio->uio_resid > 0) { 752 /* 753 * Use buffer cache I/O (via dirfs_strategy) 754 */ 755 offset = (size_t)uio->uio_offset & BMASK; 756 base_offset = (off_t)uio->uio_offset - offset; 757 len = BSIZE - offset; 758 759 if (len > uio->uio_resid) 760 len = uio->uio_resid; 761 762 error = bread(vp, base_offset, BSIZE, &bp); 763 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); 764 if (error) { 765 brelse(bp); 766 dbg(2, "WRITE uiomove failed\n"); 767 break; 768 } 769 770 // dbg(2, "WRITE dn_size=%jd uio_offset=%jd uio_resid=%jd base_offset=%jd\n", 771 // dnp->dn_size, uio->uio_offset, uio->uio_resid, base_offset); 772 773 if (ap->a_ioflag & IO_SYNC) 774 bwrite(bp); 775 else 776 bdwrite(bp); 777 } 778 779 KTR_LOG(dirfs_write, dnp, base_offset, uio->uio_resid, 780 dnp->dn_size, error); 781 782 return error; 783 } 784 785 static int 786 dirfs_advlock (struct vop_advlock_args *ap) 787 { 788 struct vnode *vp = ap->a_vp; 789 dirfs_node_t dnp = VP_TO_NODE(vp); 790 791 debug_called(); 792 793 return (lf_advlock(ap, &dnp->dn_advlock, dnp->dn_size)); 794 } 795 796 static int 797 dirfs_strategy(struct vop_strategy_args *ap) 798 { 799 dirfs_node_t dnp; 800 dirfs_mount_t dmp; 801 struct bio *bio = ap->a_bio; 802 struct buf *bp = bio->bio_buf; 803 struct vnode *vp = ap->a_vp; 804 int error; 805 size_t iosize; 806 char *tmp; 807 char *pathfree; 808 809 debug_called(); 810 811 dnp = VP_TO_NODE(vp); 812 dmp = VFS_TO_DIRFS(vp->v_mount); 813 814 error = 0; 815 816 if (vp->v_type != VREG) { 817 dbg(5, "not VREG\n"); 818 bp->b_resid = bp->b_bcount; 819 bp->b_flags |= B_ERROR | B_INVAL; 820 bp->b_error = EINVAL; 821 biodone(bio); 822 return(0); 823 } 824 825 if (dnp->dn_fd == DIRFS_NOFD) { 826 print_backtrace(-1); 827 panic("Meh, no fd to write to. dnp=%p\n", dnp); 828 } 829 830 if (bio->bio_offset + bp->b_bcount > dnp->dn_size) 831 iosize = dnp->dn_size - bio->bio_offset; 832 else 833 iosize = bp->b_bcount; 834 KKASSERT((ssize_t)iosize >= 0); 835 836 switch (bp->b_cmd) { 837 case BUF_CMD_WRITE: 838 error = pwrite(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset); 839 break; 840 case BUF_CMD_READ: 841 error = pread(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset); 842 break; 843 default: 844 bp->b_error = error = EINVAL; 845 bp->b_flags |= B_ERROR; 846 break; 847 } 848 849 if (error >= 0 && error < bp->b_bcount) 850 bzero(bp->b_data + error, bp->b_bcount - error); 851 852 if (error < 0 && errno != EINTR) { 853 dbg(5, "error=%d dnp=%p dnp->dn_fd=%d " 854 "bio->bio_offset=%ld bcount=%d resid=%d iosize=%zd\n", 855 errno, dnp, dnp->dn_fd, bio->bio_offset, bp->b_bcount, 856 bp->b_resid, iosize); 857 bp->b_error = errno; 858 bp->b_resid = bp->b_bcount; 859 bp->b_flags |= B_ERROR; 860 } else { 861 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree); 862 dirfs_node_stat(DIRFS_NOFD, tmp, dnp); 863 dirfs_dropfd(dmp, NULL, pathfree); 864 } 865 866 KTR_LOG(dirfs_strategy, dnp, dnp->dn_size, iosize, bp->b_cmd, 867 bp->b_error, bp->b_resid, bio->bio_offset, error); 868 869 biodone(bio); 870 871 return 0; 872 } 873 874 static int 875 dirfs_bmap(struct vop_bmap_args *ap) 876 { 877 debug_called(); 878 879 if (ap->a_doffsetp != NULL) 880 *ap->a_doffsetp = ap->a_loffset; 881 if (ap->a_runp != NULL) 882 *ap->a_runp = 0; 883 if (ap->a_runb != NULL) 884 *ap->a_runb = 0; 885 886 return 0; 887 } 888 889 static int 890 dirfs_nremove(struct vop_nremove_args *ap) 891 { 892 dirfs_node_t dnp, pdnp; 893 dirfs_node_t pathnp; 894 dirfs_mount_t dmp; 895 struct vnode *dvp; 896 struct nchandle *nch; 897 struct namecache *ncp; 898 struct mount *mp; 899 struct vnode *vp; 900 int error; 901 char *tmp; 902 char *pathfree; 903 debug_called(); 904 905 error = 0; 906 tmp = NULL; 907 vp = NULL; 908 dvp = ap->a_dvp; 909 nch = ap->a_nch; 910 ncp = nch->ncp; 911 912 mp = dvp->v_mount; 913 dmp = VFS_TO_DIRFS(mp); 914 915 lwkt_gettoken(&mp->mnt_token); 916 cache_vget(nch, ap->a_cred, LK_SHARED, &vp); 917 vn_unlock(vp); 918 919 pdnp = VP_TO_NODE(dvp); 920 dnp = VP_TO_NODE(vp); 921 922 if (vp->v_type == VDIR) { 923 error = EISDIR; 924 } else { 925 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 926 dirfs_node_lock(pdnp); 927 error = unlinkat(pathnp->dn_fd, tmp, 0); 928 if (error == 0) { 929 cache_unlink(nch); 930 dirfs_node_setpassive(dmp, dnp, 0); 931 if (dnp->dn_parent) { 932 dirfs_node_drop(dmp, dnp->dn_parent); 933 dnp->dn_parent = NULL; 934 } 935 } else { 936 error = errno; 937 } 938 dirfs_node_unlock(pdnp); 939 dirfs_dropfd(dmp, pathnp, pathfree); 940 } 941 vrele(vp); 942 lwkt_reltoken(&mp->mnt_token); 943 944 KTR_LOG(dirfs_nremove, dnp, pdnp, error); 945 946 return error; 947 } 948 949 static int 950 dirfs_nlink(struct vop_nlink_args *ap) 951 { 952 debug_called(); 953 954 KTR_LOG(dirfs_unsupported, __func__); 955 956 return EOPNOTSUPP; 957 } 958 959 static int 960 dirfs_nrename(struct vop_nrename_args *ap) 961 { 962 dirfs_node_t dnp, fdnp, tdnp; 963 dirfs_mount_t dmp; 964 struct namecache *fncp, *tncp; 965 struct vnode *fdvp, *tdvp, *vp; 966 struct mount *mp; 967 char *fpath, *fpathfree; 968 char *tpath, *tpathfree; 969 int error; 970 971 debug_called(); 972 973 error = 0; 974 fdvp = ap->a_fdvp; 975 tdvp = ap->a_tdvp; 976 fncp = ap->a_fnch->ncp; 977 tncp = ap->a_tnch->ncp; 978 mp = fdvp->v_mount; 979 dmp = VFS_TO_DIRFS(mp); 980 fdnp = VP_TO_NODE(fdvp); 981 tdnp = VP_TO_NODE(tdvp); 982 983 dbg(5, "fdnp=%p tdnp=%p from=%s to=%s\n", fdnp, tdnp, fncp->nc_name, 984 tncp->nc_name); 985 986 if (fdvp->v_mount != tdvp->v_mount) 987 return(EXDEV); 988 if (fdvp->v_mount != fncp->nc_vp->v_mount) 989 return(EXDEV); 990 if (fdvp->v_mount->mnt_flag & MNT_RDONLY) 991 return (EROFS); 992 993 tpath = dirfs_node_absolute_path_plus(dmp, tdnp, 994 tncp->nc_name, &tpathfree); 995 fpath = dirfs_node_absolute_path_plus(dmp, fdnp, 996 fncp->nc_name, &fpathfree); 997 error = rename(fpath, tpath); 998 if (error < 0) 999 error = errno; 1000 if (error == 0) { 1001 vp = fncp->nc_vp; /* file being renamed */ 1002 dnp = VP_TO_NODE(vp); 1003 dirfs_node_setname(dnp, tncp->nc_name, tncp->nc_nlen); 1004 1005 /* 1006 * We have to mark the target file that was replaced by 1007 * the rename as having been unlinked. 1008 */ 1009 vp = tncp->nc_vp; 1010 if (vp) { 1011 dbg(5, "RENAME2\n"); 1012 dnp = VP_TO_NODE(vp); 1013 cache_unlink(ap->a_tnch); 1014 dirfs_node_setpassive(dmp, dnp, 0); 1015 if (dnp->dn_parent) { 1016 dirfs_node_drop(dmp, dnp->dn_parent); 1017 dnp->dn_parent = NULL; 1018 } 1019 1020 /* 1021 * nlinks on directories can be a bit weird. Zero 1022 * it out. 1023 */ 1024 dnp->dn_links = 0; 1025 cache_inval_vp(vp, CINV_DESTROY); 1026 } 1027 cache_rename(ap->a_fnch, ap->a_tnch); 1028 } 1029 dirfs_dropfd(dmp, NULL, fpathfree); 1030 dirfs_dropfd(dmp, NULL, tpathfree); 1031 1032 return error; 1033 } 1034 1035 static int 1036 dirfs_nmkdir(struct vop_nmkdir_args *ap) 1037 { 1038 dirfs_mount_t dmp; 1039 dirfs_node_t dnp, pdnp, dnp1; 1040 struct namecache *ncp; 1041 struct vattr *vap; 1042 struct vnode *dvp; 1043 struct vnode **vpp; 1044 char *tmp, *pathfree; 1045 char *path; 1046 int pfd, error; 1047 int extrapath; 1048 1049 debug_called(); 1050 1051 extrapath = error = 0; 1052 dvp = ap->a_dvp; 1053 vpp = ap->a_vpp; 1054 dmp = VFS_TO_DIRFS(dvp->v_mount); 1055 pdnp = VP_TO_NODE(dvp); 1056 ncp = ap->a_nch->ncp; 1057 vap = ap->a_vap; 1058 pathfree = tmp = path = NULL; 1059 dnp = NULL; 1060 1061 dirfs_node_lock(pdnp); 1062 if (pdnp->dn_fd != DIRFS_NOFD) { 1063 pfd = pdnp->dn_fd; 1064 path = ncp->nc_name; 1065 } else { 1066 dnp1 = dirfs_findfd(dmp, pdnp, &tmp, &pathfree); 1067 pfd = dnp1->dn_fd; 1068 /* XXX check there is room to copy the path */ 1069 path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK); 1070 ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name); 1071 extrapath = 1; 1072 dirfs_dropfd(dmp, dnp1, pathfree); 1073 } 1074 1075 error = mkdirat(pfd, path, vap->va_mode); 1076 if (error) { 1077 error = errno; 1078 } else { /* Directory has been made */ 1079 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, 1080 vap, O_DIRECTORY); 1081 if (error) 1082 error = errno; 1083 cache_setunresolved(ap->a_nch); 1084 cache_setvp(ap->a_nch, *vpp); 1085 } 1086 dirfs_node_unlock(pdnp); 1087 1088 if (extrapath) 1089 kfree(path, M_DIRFS_MISC); 1090 1091 KTR_LOG(dirfs_nmkdir, pdnp, dnp, ncp->nc_name, error); 1092 1093 return error; 1094 } 1095 1096 static int 1097 dirfs_nrmdir(struct vop_nrmdir_args *ap) 1098 { 1099 dirfs_node_t dnp, pdnp; 1100 dirfs_mount_t dmp; 1101 struct vnode *dvp; 1102 struct nchandle *nch; 1103 struct namecache *ncp; 1104 struct mount *mp; 1105 struct vnode *vp; 1106 int error; 1107 char *tmp; 1108 char *pathfree; 1109 1110 debug_called(); 1111 1112 error = 0; 1113 tmp = NULL; 1114 vp = NULL; 1115 dvp = ap->a_dvp; 1116 nch = ap->a_nch; 1117 ncp = nch->ncp; 1118 1119 mp = dvp->v_mount; 1120 dmp = VFS_TO_DIRFS(mp); 1121 1122 lwkt_gettoken(&mp->mnt_token); 1123 cache_vget(nch, ap->a_cred, LK_SHARED, &vp); 1124 vn_unlock(vp); 1125 1126 pdnp = VP_TO_NODE(dvp); 1127 dnp = VP_TO_NODE(vp); 1128 1129 if (vp->v_type != VDIR) { 1130 error = ENOTDIR; 1131 } else { 1132 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree); 1133 dirfs_node_lock(pdnp); 1134 error = rmdir(tmp); 1135 if (error == 0) { 1136 cache_unlink(nch); 1137 dirfs_node_setpassive(dmp, dnp, 0); 1138 if (dnp->dn_parent) { 1139 dirfs_node_drop(dmp, dnp->dn_parent); 1140 dnp->dn_parent = NULL; 1141 } 1142 1143 /* 1144 * nlinks on directories can be a bit weird. Zero 1145 * it out. 1146 */ 1147 dnp->dn_links = 0; 1148 cache_inval_vp(vp, CINV_DESTROY); 1149 } else { 1150 error = errno; 1151 } 1152 dirfs_node_unlock(pdnp); 1153 dirfs_dropfd(dmp, NULL, pathfree); 1154 } 1155 vrele(vp); 1156 lwkt_reltoken(&mp->mnt_token); 1157 1158 KTR_LOG(dirfs_nrmdir, dnp, pdnp, error); 1159 1160 return error; 1161 } 1162 1163 static int 1164 dirfs_nsymlink(struct vop_nsymlink_args *ap) 1165 { 1166 dirfs_mount_t dmp; 1167 dirfs_node_t dnp, pdnp; 1168 struct mount *mp; 1169 struct namecache *ncp; 1170 struct vattr *vap; 1171 struct vnode *dvp; 1172 struct vnode **vpp; 1173 char *tmp, *pathfree; 1174 char *path; 1175 int error; 1176 1177 debug_called(); 1178 1179 error = 0; 1180 dvp = ap->a_dvp; 1181 vpp = ap->a_vpp; 1182 mp = dvp->v_mount; 1183 dmp = VFS_TO_DIRFS(dvp->v_mount); 1184 pdnp = VP_TO_NODE(dvp); 1185 ncp = ap->a_nch->ncp; 1186 vap = ap->a_vap; 1187 pathfree = tmp = path = NULL; 1188 dnp = NULL; 1189 1190 lwkt_gettoken(&mp->mnt_token); 1191 vap->va_type = VLNK; 1192 1193 /* Find out the whole path of our new symbolic link */ 1194 tmp = dirfs_node_absolute_path(dmp, pdnp, &pathfree); 1195 /* XXX check there is room to copy the path */ 1196 path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK); 1197 ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name); 1198 dirfs_dropfd(dmp, NULL, pathfree); 1199 1200 error = symlink(ap->a_target, path); 1201 if (error) { 1202 error = errno; 1203 } else { /* Symlink has been made */ 1204 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, 1205 NULL, 0); 1206 if (error) 1207 error = errno; 1208 cache_setunresolved(ap->a_nch); 1209 cache_setvp(ap->a_nch, *vpp); 1210 } 1211 dbg(5, "path=%s a_target=%s\n", path, ap->a_target); 1212 1213 KTR_LOG(dirfs_nsymlink, dnp, ap->a_target, path, error); 1214 kfree(path, M_DIRFS_MISC); 1215 lwkt_reltoken(&mp->mnt_token); 1216 1217 return error; 1218 1219 } 1220 1221 static int 1222 dirfs_readdir(struct vop_readdir_args *ap) 1223 { 1224 1225 struct dirent *dp, *dpn; 1226 off_t __unused **cookies = ap->a_cookies; 1227 int *ncookies = ap->a_ncookies; 1228 int bytes; 1229 char *buf; 1230 long base; 1231 struct vnode *vp = ap->a_vp; 1232 struct uio *uio; 1233 dirfs_node_t dnp; 1234 off_t startoff; 1235 off_t cnt; 1236 int error, r; 1237 size_t bufsiz; 1238 off_t curoff; 1239 1240 debug_called(); 1241 1242 if (ncookies) 1243 debug(1, "ncookies=%d\n", *ncookies); 1244 1245 dnp = VP_TO_NODE(vp); 1246 uio = ap->a_uio; 1247 startoff = uio->uio_offset; 1248 cnt = 0; 1249 error = 0; 1250 base = 0; 1251 bytes = 0; 1252 1253 if (vp->v_type != VDIR) 1254 return ENOTDIR; 1255 if (uio->uio_resid < 0) 1256 return EINVAL; 1257 if ((bufsiz = uio->uio_resid) > 4096) 1258 bufsiz = 4096; 1259 buf = kmalloc(bufsiz, M_DIRFS_MISC, M_WAITOK | M_ZERO); 1260 1261 /* 1262 * Generally speaking we have to be able to process ALL the 1263 * entries returned by getdirentries() in order for the seek 1264 * position to be correct. For now try to size the buffer 1265 * to make this happen. A smaller buffer always works. For 1266 * now just use an appropriate size. 1267 */ 1268 dirfs_node_lock(dnp); 1269 lseek(dnp->dn_fd, startoff, SEEK_SET); 1270 bytes = getdirentries(dnp->dn_fd, buf, bufsiz, &base); 1271 dbg(5, "seek %016jx %016jx %016jx\n", 1272 (intmax_t)startoff, (intmax_t)base, 1273 (intmax_t)lseek(dnp->dn_fd, 0, SEEK_CUR)); 1274 if (bytes < 0) { 1275 if (errno == EINVAL) 1276 panic("EINVAL on readdir\n"); 1277 error = errno; 1278 curoff = startoff; 1279 goto out; 1280 } else if (bytes == 0) { 1281 *ap->a_eofflag = 1; 1282 curoff = startoff; 1283 goto out; 1284 } 1285 1286 for (dp = (struct dirent *)buf; bytes > 0 && uio->uio_resid > 0; 1287 bytes -= _DIRENT_DIRSIZ(dp), dp = dpn) { 1288 r = vop_write_dirent(&error, uio, dp->d_ino, dp->d_type, 1289 dp->d_namlen, dp->d_name); 1290 if (error || r) 1291 break; 1292 dpn = _DIRENT_NEXT(dp); 1293 dp = dpn; 1294 cnt++; 1295 } 1296 curoff = lseek(dnp->dn_fd, 0, SEEK_CUR); 1297 1298 out: 1299 kfree(buf, M_DIRFS_MISC); 1300 uio->uio_offset = curoff; 1301 dirfs_node_unlock(dnp); 1302 1303 KTR_LOG(dirfs_readdir, dnp, dnp->dn_fd, startoff, uio->uio_offset); 1304 1305 return error; 1306 } 1307 1308 static int 1309 dirfs_readlink(struct vop_readlink_args *ap) 1310 { 1311 dirfs_node_t dnp, pathnp; 1312 dirfs_mount_t dmp; 1313 struct vnode *vp; 1314 struct mount *mp; 1315 struct uio *uio; 1316 char *tmp, *pathfree, *buf; 1317 ssize_t nlen; 1318 int error; 1319 1320 debug_called(); 1321 1322 vp = ap->a_vp; 1323 1324 KKASSERT(vp->v_type == VLNK); 1325 1326 error = 0; 1327 tmp = pathfree = NULL; 1328 uio = ap->a_uio; 1329 mp = vp->v_mount; 1330 dmp = VFS_TO_DIRFS(mp); 1331 dnp = VP_TO_NODE(vp); 1332 1333 lwkt_gettoken(&mp->mnt_token); 1334 1335 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 1336 1337 buf = kmalloc(uio->uio_resid, M_DIRFS_MISC, M_WAITOK | M_ZERO); 1338 nlen = readlinkat(pathnp->dn_fd, dnp->dn_name, buf, uio->uio_resid); 1339 if (nlen == -1 ) { 1340 error = errno; 1341 } else { 1342 error = uiomove(buf, nlen + 1, uio); 1343 buf[nlen] = '\0'; 1344 if (error) 1345 error = errno; 1346 } 1347 dirfs_dropfd(dmp, pathnp, pathfree); 1348 kfree(buf, M_DIRFS_MISC); 1349 1350 lwkt_reltoken(&mp->mnt_token); 1351 1352 return error; 1353 } 1354 1355 /* 1356 * Main tasks to be performed. 1357 * 1) When inode is NULL recycle the vnode 1358 * 2) When the inode has 0 links: 1359 * - Check if in the TAILQ, if so remove. 1360 * - Destroy the inode. 1361 * - Recycle the vnode. 1362 * 3) If none of the above, add the node to the TAILQ 1363 * when it has a valid fd and there is room on the 1364 * queue. 1365 * 1366 */ 1367 static int 1368 dirfs_inactive(struct vop_inactive_args *ap) 1369 { 1370 struct vnode *vp; 1371 dirfs_mount_t dmp; 1372 dirfs_node_t dnp; 1373 1374 debug_called(); 1375 1376 vp = ap->a_vp; 1377 dmp = VFS_TO_DIRFS(vp->v_mount); 1378 dnp = VP_TO_NODE(vp); 1379 1380 /* Degenerate case */ 1381 if (dnp == NULL) { 1382 dbg(5, "dnp was NULL\n"); 1383 vrecycle(vp); 1384 return 0; 1385 } 1386 1387 dirfs_mount_gettoken(dmp); 1388 1389 /* 1390 * Deal with the case the inode has 0 links which means it was unlinked. 1391 */ 1392 if (dnp->dn_links == 0) { 1393 vrecycle(vp); 1394 dbg(5, "recycled a vnode of an unlinked dnp\n"); 1395 1396 goto out; 1397 } 1398 1399 /* 1400 * Try to retain the fd in our fd cache. 1401 */ 1402 dirfs_node_setpassive(dmp, dnp, 1); 1403 out: 1404 dirfs_mount_reltoken(dmp); 1405 1406 return 0; 1407 1408 } 1409 1410 int 1411 dirfs_reclaim(struct vop_reclaim_args *ap) 1412 { 1413 struct vnode *vp; 1414 dirfs_node_t dnp; 1415 dirfs_mount_t dmp; 1416 1417 debug_called(); 1418 1419 vp = ap->a_vp; 1420 dnp = VP_TO_NODE(vp); 1421 dmp = VFS_TO_DIRFS(vp->v_mount); 1422 1423 dirfs_free_vp(dmp, dnp); 1424 /* dnp is now invalid, may have been destroyed */ 1425 1426 return 0; 1427 } 1428 1429 static int 1430 dirfs_mountctl(struct vop_mountctl_args *ap) 1431 { 1432 debug_called(); 1433 1434 KTR_LOG(dirfs_unsupported, __func__); 1435 1436 return EOPNOTSUPP; 1437 } 1438 1439 static int 1440 dirfs_print(struct vop_print_args *v) 1441 { 1442 debug_called(); 1443 1444 KTR_LOG(dirfs_unsupported, __func__); 1445 1446 return EOPNOTSUPP; 1447 } 1448 1449 static int __unused 1450 dirfs_pathconf(struct vop_pathconf_args *v) 1451 { 1452 debug_called(); 1453 1454 return EOPNOTSUPP; 1455 } 1456 1457 static int 1458 dirfs_kqfilter (struct vop_kqfilter_args *ap) 1459 { 1460 debug_called(); 1461 1462 KTR_LOG(dirfs_unsupported, __func__); 1463 1464 return EOPNOTSUPP; 1465 } 1466 1467 struct vop_ops dirfs_vnode_vops = { 1468 .vop_default = vop_defaultop, 1469 .vop_nwhiteout = vop_compat_nwhiteout, 1470 .vop_ncreate = dirfs_ncreate, 1471 .vop_nresolve = dirfs_nresolve, 1472 .vop_markatime = vop_stdmarkatime, 1473 .vop_nlookupdotdot = dirfs_nlookupdotdot, 1474 .vop_nmknod = dirfs_nmknod, 1475 .vop_open = dirfs_open, 1476 .vop_close = dirfs_close, 1477 .vop_access = dirfs_access, 1478 .vop_getattr = dirfs_getattr, 1479 .vop_setattr = dirfs_setattr, 1480 .vop_read = dirfs_read, 1481 .vop_write = dirfs_write, 1482 .vop_fsync = dirfs_fsync, 1483 .vop_mountctl = dirfs_mountctl, 1484 .vop_nremove = dirfs_nremove, 1485 .vop_nlink = dirfs_nlink, 1486 .vop_nrename = dirfs_nrename, 1487 .vop_nmkdir = dirfs_nmkdir, 1488 .vop_nrmdir = dirfs_nrmdir, 1489 .vop_nsymlink = dirfs_nsymlink, 1490 .vop_readdir = dirfs_readdir, 1491 .vop_readlink = dirfs_readlink, 1492 .vop_inactive = dirfs_inactive, 1493 .vop_reclaim = dirfs_reclaim, 1494 .vop_print = dirfs_print, 1495 .vop_pathconf = vop_stdpathconf, 1496 .vop_bmap = dirfs_bmap, 1497 .vop_strategy = dirfs_strategy, 1498 .vop_advlock = dirfs_advlock, 1499 .vop_kqfilter = dirfs_kqfilter, 1500 .vop_getpages = vop_stdgetpages, 1501 .vop_putpages = vop_stdputpages 1502 }; 1503