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), fstat(2), fstatat(2) 50 * dirfs_setattr - - - - - 51 * dirfs_read Y - Y - read(2). relies on bufcache 52 * dirfs_write Y - Y - write(2). relies on bufcache 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 readlink(2), 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 newfd?=%s)", 113 dirfs_node_t dnp, char *isnew); 114 115 KTR_INFO(KTR_DIRFS, dirfs, close, 3, 116 "DIRFS(dnp=%p fd=%d vfsync error=%d)", 117 dirfs_node_t dnp, int fd, 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 (error && error == ENOENT) { 221 cache_setvp(nch, NULL); 222 } else { 223 vn_unlock(vp); 224 cache_setvp(nch, vp); 225 vrele(vp); 226 } 227 } 228 229 KTR_LOG(dirfs_nresolve, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error); 230 231 return error; 232 } 233 234 static int 235 dirfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap) 236 { 237 debug_called(); 238 239 KTR_LOG(dirfs_unsupported, __func__); 240 241 return EOPNOTSUPP; 242 } 243 244 static int 245 dirfs_ncreate(struct vop_ncreate_args *ap) 246 { 247 dirfs_node_t pdnp; 248 dirfs_node_t dnp; 249 dirfs_mount_t dmp; 250 struct namecache *ncp; 251 struct vnode *dvp; 252 struct vnode **vpp; 253 struct vattr *vap; 254 int canwrite = 0; 255 int error; 256 257 debug_called(); 258 259 error = 0; 260 dnp = NULL; 261 dvp = ap->a_dvp; 262 pdnp = VP_TO_NODE(dvp); 263 dmp = VFS_TO_DIRFS(dvp->v_mount); 264 vap = ap->a_vap; 265 ncp = ap->a_nch->ncp; 266 vpp = ap->a_vpp; 267 268 dirfs_mount_gettoken(dmp); 269 270 dirfs_node_getperms(pdnp, NULL, &canwrite, NULL); 271 if (!canwrite) 272 error = EPERM; 273 274 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, vap, 275 (O_CREAT | O_RDWR)); 276 277 if (error == 0) { 278 cache_setunresolved(ap->a_nch); 279 cache_setvp(ap->a_nch, *vpp); 280 } 281 282 dirfs_mount_reltoken(dmp); 283 284 KTR_LOG(dirfs_ncreate, dnp, ncp->nc_name, pdnp, pdnp->dn_fd, error); 285 286 return error; 287 } 288 289 static int 290 dirfs_nmknod(struct vop_nmknod_args *v) 291 { 292 debug_called(); 293 294 return EOPNOTSUPP; 295 } 296 297 static int 298 dirfs_open(struct vop_open_args *ap) 299 { 300 dirfs_node_t dnp; 301 dirfs_mount_t dmp; 302 struct vnode *vp; 303 int error; 304 int ofd, nfd; 305 306 debug_called(); 307 308 vp = ap->a_vp; 309 dnp = VP_TO_NODE(vp); 310 dmp = VFS_TO_DIRFS(vp->v_mount); 311 error = 0; 312 ofd = nfd = dnp->dn_fd; 313 314 /* 315 * Root inode has been allocated and opened in VFS_ROOT() so 316 * no reason to attempt to open it again. 317 */ 318 if (dmp->dm_root != dnp && dnp->dn_fd == DIRFS_NOFD) { 319 error = dirfs_open_helper(dmp, dnp, DIRFS_NOFD, NULL); 320 if (error) 321 return error; 322 nfd = dnp->dn_fd; 323 } 324 325 KTR_LOG(dirfs_open, dnp, (ofd != nfd) ? "true" : "false"); 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 349 KTR_LOG(dirfs_close, dnp, dnp->dn_fd, error); 350 351 return vop_stdclose(ap); 352 } 353 354 int 355 dirfs_access(struct vop_access_args *ap) 356 { 357 struct vnode *vp = ap->a_vp; 358 int error; 359 dirfs_node_t dnp; 360 361 debug_called(); 362 363 dnp = VP_TO_NODE(vp); 364 365 switch (vp->v_type) { 366 case VDIR: 367 /* FALLTHROUGH */ 368 case VLNK: 369 /* FALLTHROUGH */ 370 case VREG: 371 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 372 error = EROFS; 373 goto out; 374 } 375 break; 376 case VBLK: 377 /* FALLTHROUGH */ 378 case VCHR: 379 /* FALLTHROUGH */ 380 case VSOCK: 381 /* FALLTHROUGH */ 382 case VFIFO: 383 break; 384 385 default: 386 error = EINVAL; 387 goto out; 388 } 389 390 error = vop_helper_access(ap, dnp->dn_uid, 391 dnp->dn_gid, dnp->dn_mode, 0); 392 393 out: 394 KTR_LOG(dirfs_access, dnp, error); 395 396 return error; 397 } 398 399 int 400 dirfs_getattr(struct vop_getattr_args *ap) 401 { 402 dirfs_mount_t dmp; 403 dirfs_node_t dnp; 404 dirfs_node_t pathnp; 405 struct vnode *vp; 406 struct vattr *vap; 407 char *tmp; 408 char *pathfree; 409 int error; 410 411 debug_called(); 412 413 vp = ap->a_vp; 414 vap = ap->a_vap; 415 dnp = VP_TO_NODE(vp); 416 dmp = VFS_TO_DIRFS(vp->v_mount); 417 418 KKASSERT(dnp); /* This must not happen */ 419 420 if (!dirfs_node_isroot(dnp)) { 421 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 422 423 KKASSERT(pathnp->dn_fd != DIRFS_NOFD); 424 425 error = dirfs_node_stat(pathnp->dn_fd, tmp, dnp); 426 dirfs_dropfd(dmp, pathnp, pathfree); 427 } else { 428 error = dirfs_node_stat(DIRFS_NOFD, dmp->dm_path, dnp); 429 } 430 431 if (error == 0) { 432 dirfs_node_lock(dnp); 433 vap->va_nlink = dnp->dn_links; 434 vap->va_type = dnp->dn_type; 435 vap->va_mode = dnp->dn_mode; 436 vap->va_uid = dnp->dn_uid; 437 vap->va_gid = dnp->dn_gid; 438 vap->va_fileid = dnp->dn_ino; 439 vap->va_size = dnp->dn_size; 440 vap->va_blocksize = dnp->dn_blocksize; 441 vap->va_atime.tv_sec = dnp->dn_atime; 442 vap->va_atime.tv_nsec = dnp->dn_atimensec; 443 vap->va_mtime.tv_sec = dnp->dn_mtime; 444 vap->va_mtime.tv_nsec = dnp->dn_mtimensec; 445 vap->va_ctime.tv_sec = dnp->dn_ctime; 446 vap->va_ctime.tv_nsec = dnp->dn_ctimensec; 447 vap->va_bytes = dnp->dn_size; 448 vap->va_gen = dnp->dn_gen; 449 vap->va_flags = dnp->dn_flags; 450 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 451 dirfs_node_unlock(dnp); 452 } 453 454 KTR_LOG(dirfs_getattr, dnp, error); 455 456 return 0; 457 } 458 459 int 460 dirfs_setattr(struct vop_setattr_args *ap) 461 { 462 dirfs_mount_t dmp; 463 dirfs_node_t dnp; 464 struct vnode *vp; 465 struct vattr *vap; 466 struct ucred *cred; 467 int error; 468 #ifdef KTR 469 const char *msg[6] = { 470 "invalid", 471 "chflags", 472 "chsize", 473 "chown", 474 "chmod", 475 "chtimes" 476 }; 477 #endif 478 int msgno; 479 480 debug_called(); 481 482 error = msgno = 0; 483 vp = ap->a_vp; 484 vap = ap->a_vap; 485 cred = ap->a_cred; 486 dnp = VP_TO_NODE(vp); 487 dmp = VFS_TO_DIRFS(vp->v_mount); 488 489 dirfs_mount_gettoken(dmp); 490 491 /* 492 * Check for unsettable attributes. 493 */ 494 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 495 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 496 (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) || 497 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 498 msgno = 0; 499 error = EINVAL; 500 goto out; 501 } 502 503 /* 504 * Change file flags 505 */ 506 if (error == 0 && (vap->va_flags != VNOVAL)) { 507 if (vp->v_mount->mnt_flag & MNT_RDONLY) 508 error = EROFS; 509 else 510 error = dirfs_node_chflags(dnp, vap->va_flags, cred); 511 msgno = 1; 512 goto out; 513 } 514 515 /* 516 * Extend or truncate a file 517 */ 518 if (error == 0 && (vap->va_size != VNOVAL)) { 519 if (vp->v_mount->mnt_flag & MNT_RDONLY) 520 error = EROFS; 521 else 522 error = dirfs_node_chsize(dnp, vap->va_size); 523 dbg(2, "dnp size=%jd vap size=%jd\n", dnp->dn_size, vap->va_size); 524 msgno = 2; 525 goto out; 526 } 527 528 /* 529 * Change file owner or group 530 */ 531 if (error == 0 && (vap->va_uid != (uid_t)VNOVAL || 532 vap->va_gid != (gid_t)VNOVAL)) { 533 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 534 error = EROFS; 535 } else { 536 mode_t cur_mode = dnp->dn_mode; 537 uid_t cur_uid = dnp->dn_uid; 538 gid_t cur_gid = dnp->dn_gid; 539 540 error = vop_helper_chown(ap->a_vp, vap->va_uid, 541 vap->va_gid, ap->a_cred, 542 &cur_uid, &cur_gid, &cur_mode); 543 if (error == 0 && 544 (cur_mode != dnp->dn_mode || 545 cur_uid != dnp->dn_uid || 546 cur_gid != dnp->dn_gid)) { 547 error = dirfs_node_chown(dmp, dnp, cur_uid, 548 cur_gid, cur_mode); 549 } 550 } 551 msgno = 3; 552 goto out; 553 } 554 555 /* 556 * Change file mode 557 */ 558 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) { 559 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 560 error = EROFS; 561 } else { 562 mode_t cur_mode = dnp->dn_mode; 563 uid_t cur_uid = dnp->dn_uid; 564 gid_t cur_gid = dnp->dn_gid; 565 566 error = vop_helper_chmod(ap->a_vp, vap->va_mode, 567 ap->a_cred, 568 cur_uid, cur_gid, &cur_mode); 569 if (error == 0 && cur_mode != dnp->dn_mode) { 570 error = dirfs_node_chmod(dmp, dnp, cur_mode); 571 } 572 } 573 msgno = 4; 574 goto out; 575 } 576 577 /* 578 * Change file times 579 */ 580 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 581 vap->va_atime.tv_nsec != VNOVAL) || 582 (vap->va_mtime.tv_sec != VNOVAL && 583 vap->va_mtime.tv_nsec != VNOVAL) )) { 584 if (vp->v_mount->mnt_flag & MNT_RDONLY) 585 error = EROFS; 586 else 587 error = dirfs_node_chtimes(dnp); 588 msgno = 5; 589 goto out; 590 591 } 592 out: 593 dirfs_mount_reltoken(dmp); 594 595 KTR_LOG(dirfs_setattr, dnp, msg[msgno], error); 596 597 return error; 598 } 599 600 static int 601 dirfs_fsync(struct vop_fsync_args *ap) 602 { 603 dirfs_node_t dnp = VP_TO_NODE(ap->a_vp); 604 int error = 0; 605 606 debug_called(); 607 608 vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL); 609 610 if (dnp->dn_fd != DIRFS_NOFD) { 611 if (fsync(dnp->dn_fd) == -1) 612 error = fsync(dnp->dn_fd); 613 } 614 615 KTR_LOG(dirfs_fsync, dnp, error); 616 617 return 0; 618 } 619 620 static int 621 dirfs_read(struct vop_read_args *ap) 622 { 623 struct buf *bp; 624 struct vnode *vp = ap->a_vp; 625 struct uio *uio = ap->a_uio; 626 dirfs_node_t dnp; 627 off_t base_offset; 628 size_t offset; 629 size_t len; 630 int error; 631 632 debug_called(); 633 634 error = 0; 635 if (uio->uio_resid == 0) { 636 dbg(5, "zero len uio->uio_resid\n"); 637 return error; 638 } 639 640 dnp = VP_TO_NODE(vp); 641 642 if (uio->uio_offset < 0) 643 return (EINVAL); 644 if (vp->v_type != VREG) 645 return (EINVAL); 646 647 while (uio->uio_resid > 0 && uio->uio_offset < dnp->dn_size) { 648 /* 649 * Use buffer cache I/O (via dirfs_strategy) 650 */ 651 offset = (size_t)uio->uio_offset & BMASK; 652 base_offset = (off_t)uio->uio_offset - offset; 653 bp = getcacheblk(vp, base_offset, BSIZE, 0); 654 if (bp == NULL) { 655 lwkt_gettoken(&vp->v_mount->mnt_token); 656 error = bread(vp, base_offset, BSIZE, &bp); 657 if (error) { 658 brelse(bp); 659 lwkt_reltoken(&vp->v_mount->mnt_token); 660 dbg(5, "dirfs_read bread error %d\n", error); 661 break; 662 } 663 lwkt_reltoken(&vp->v_mount->mnt_token); 664 } 665 666 /* 667 * Figure out how many bytes we can actually copy this loop. 668 */ 669 len = BSIZE - offset; 670 if (len > uio->uio_resid) 671 len = uio->uio_resid; 672 if (len > dnp->dn_size - uio->uio_offset) 673 len = (size_t)(dnp->dn_size - uio->uio_offset); 674 675 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); 676 bqrelse(bp); 677 if (error) { 678 dbg(5, "dirfs_read uiomove error %d\n", error); 679 break; 680 } 681 } 682 683 KTR_LOG(dirfs_read, dnp, dnp->dn_size, error); 684 685 return(error); 686 } 687 688 static int 689 dirfs_write (struct vop_write_args *ap) 690 { 691 dirfs_node_t dnp; 692 dirfs_mount_t dmp; 693 struct buf *bp; 694 struct vnode *vp = ap->a_vp; 695 struct uio *uio = ap->a_uio; 696 struct thread *td = uio->uio_td; 697 int error; 698 off_t osize; 699 off_t nsize; 700 off_t base_offset; 701 size_t offset; 702 size_t len; 703 struct rlimit limit; 704 705 debug_called(); 706 707 error = 0; 708 if (uio->uio_resid == 0) { 709 dbg(5, "zero-length uio->uio_resid\n"); 710 return error; 711 } 712 713 dnp = VP_TO_NODE(vp); 714 dmp = VFS_TO_DIRFS(vp->v_mount); 715 716 if (vp->v_type != VREG) 717 return (EINVAL); 718 719 if (vp->v_type == VREG && td != NULL) { 720 error = kern_getrlimit(RLIMIT_FSIZE, &limit); 721 if (error != 0) { 722 dbg(5, "rlimit failure\n"); 723 return error; 724 } 725 if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) { 726 dbg(5, "file too big\n"); 727 ksignal(td->td_proc, SIGXFSZ); 728 return (EFBIG); 729 } 730 } 731 732 if (ap->a_ioflag & IO_APPEND) 733 uio->uio_offset = dnp->dn_size; 734 735 /* 736 * buffer cache operations may be deferred, make sure 737 * the file is correctly sized right now. 738 */ 739 osize = dnp->dn_size; 740 nsize = uio->uio_offset + uio->uio_resid; 741 if (nsize > osize && uio->uio_resid) { 742 KKASSERT(dnp->dn_fd >= 0); 743 dnp->dn_size = nsize; 744 ftruncate(dnp->dn_fd, nsize); 745 nvextendbuf(vp, osize, nsize, 746 BSIZE, BSIZE, -1, -1, 0); 747 } /* else nsize = osize; NOT USED */ 748 749 while (uio->uio_resid > 0) { 750 /* 751 * Use buffer cache I/O (via dirfs_strategy) 752 */ 753 offset = (size_t)uio->uio_offset & BMASK; 754 base_offset = (off_t)uio->uio_offset - offset; 755 len = BSIZE - offset; 756 757 if (len > uio->uio_resid) 758 len = uio->uio_resid; 759 760 error = bread(vp, base_offset, BSIZE, &bp); 761 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); 762 if (error) { 763 brelse(bp); 764 dbg(2, "WRITE uiomove failed\n"); 765 break; 766 } 767 768 // dbg(2, "WRITE dn_size=%jd uio_offset=%jd uio_resid=%jd base_offset=%jd\n", 769 // dnp->dn_size, uio->uio_offset, uio->uio_resid, base_offset); 770 771 if (ap->a_ioflag & IO_SYNC) 772 bwrite(bp); 773 else 774 bdwrite(bp); 775 } 776 777 KTR_LOG(dirfs_write, dnp, base_offset, uio->uio_resid, 778 dnp->dn_size, error); 779 780 return error; 781 } 782 783 static int 784 dirfs_advlock (struct vop_advlock_args *ap) 785 { 786 struct vnode *vp = ap->a_vp; 787 dirfs_node_t dnp = VP_TO_NODE(vp); 788 789 debug_called(); 790 791 return (lf_advlock(ap, &dnp->dn_advlock, dnp->dn_size)); 792 } 793 794 static int 795 dirfs_strategy(struct vop_strategy_args *ap) 796 { 797 dirfs_node_t dnp; 798 dirfs_mount_t dmp; 799 struct bio *bio = ap->a_bio; 800 struct buf *bp = bio->bio_buf; 801 struct vnode *vp = ap->a_vp; 802 int error; 803 size_t iosize; 804 char *tmp; 805 char *pathfree; 806 807 debug_called(); 808 809 dnp = VP_TO_NODE(vp); 810 dmp = VFS_TO_DIRFS(vp->v_mount); 811 812 error = 0; 813 814 if (vp->v_type != VREG) { 815 dbg(5, "not VREG\n"); 816 bp->b_resid = bp->b_bcount; 817 bp->b_flags |= B_ERROR | B_INVAL; 818 bp->b_error = EINVAL; 819 biodone(bio); 820 return(0); 821 } 822 823 if (dnp->dn_fd == DIRFS_NOFD) { 824 print_backtrace(-1); 825 panic("Meh, no fd to write to. dnp=%p\n", dnp); 826 } 827 828 if (bio->bio_offset + bp->b_bcount > dnp->dn_size) 829 iosize = dnp->dn_size - bio->bio_offset; 830 else 831 iosize = bp->b_bcount; 832 KKASSERT((ssize_t)iosize >= 0); 833 834 switch (bp->b_cmd) { 835 case BUF_CMD_WRITE: 836 error = pwrite(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset); 837 break; 838 case BUF_CMD_READ: 839 error = pread(dnp->dn_fd, bp->b_data, iosize, bio->bio_offset); 840 break; 841 default: 842 bp->b_error = error = EINVAL; 843 bp->b_flags |= B_ERROR; 844 break; 845 } 846 847 if (error >= 0 && error < bp->b_bcount) 848 bzero(bp->b_data + error, bp->b_bcount - error); 849 850 if (error < 0 && errno != EINTR) { 851 dbg(5, "error=%d dnp=%p dnp->dn_fd=%d " 852 "bio->bio_offset=%ld bcount=%d resid=%d iosize=%zd\n", 853 errno, dnp, dnp->dn_fd, bio->bio_offset, bp->b_bcount, 854 bp->b_resid, iosize); 855 bp->b_error = errno; 856 bp->b_resid = bp->b_bcount; 857 bp->b_flags |= B_ERROR; 858 } else { 859 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree); 860 dirfs_node_stat(DIRFS_NOFD, tmp, dnp); 861 dirfs_dropfd(dmp, NULL, pathfree); 862 } 863 864 KTR_LOG(dirfs_strategy, dnp, dnp->dn_size, iosize, bp->b_cmd, 865 bp->b_error, bp->b_resid, bio->bio_offset, error); 866 867 biodone(bio); 868 869 return 0; 870 } 871 872 static int 873 dirfs_bmap(struct vop_bmap_args *ap) 874 { 875 debug_called(); 876 877 if (ap->a_doffsetp != NULL) 878 *ap->a_doffsetp = ap->a_loffset; 879 if (ap->a_runp != NULL) 880 *ap->a_runp = 0; 881 if (ap->a_runb != NULL) 882 *ap->a_runb = 0; 883 884 return 0; 885 } 886 887 static int 888 dirfs_nremove(struct vop_nremove_args *ap) 889 { 890 dirfs_node_t dnp, pdnp; 891 dirfs_node_t pathnp; 892 dirfs_mount_t dmp; 893 struct vnode *dvp; 894 struct nchandle *nch; 895 struct namecache *ncp; 896 struct mount *mp; 897 struct vnode *vp; 898 int error; 899 char *tmp; 900 char *pathfree; 901 debug_called(); 902 903 error = 0; 904 tmp = NULL; 905 vp = NULL; 906 dvp = ap->a_dvp; 907 nch = ap->a_nch; 908 ncp = nch->ncp; 909 910 mp = dvp->v_mount; 911 dmp = VFS_TO_DIRFS(mp); 912 913 lwkt_gettoken(&mp->mnt_token); 914 cache_vget(nch, ap->a_cred, LK_SHARED, &vp); 915 vn_unlock(vp); 916 917 pdnp = VP_TO_NODE(dvp); 918 dnp = VP_TO_NODE(vp); 919 920 if (vp->v_type == VDIR) { 921 error = EISDIR; 922 } else { 923 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 924 dirfs_node_lock(pdnp); 925 error = unlinkat(pathnp->dn_fd, tmp, 0); 926 if (error == 0) { 927 cache_unlink(nch); 928 dirfs_node_setpassive(dmp, dnp, 0); 929 if (dnp->dn_parent) { 930 dirfs_node_drop(dmp, dnp->dn_parent); 931 dnp->dn_parent = NULL; 932 } 933 } else { 934 error = errno; 935 } 936 dirfs_node_unlock(pdnp); 937 dirfs_dropfd(dmp, pathnp, pathfree); 938 } 939 vrele(vp); 940 lwkt_reltoken(&mp->mnt_token); 941 942 KTR_LOG(dirfs_nremove, dnp, pdnp, error); 943 944 return error; 945 } 946 947 static int 948 dirfs_nlink(struct vop_nlink_args *ap) 949 { 950 debug_called(); 951 952 KTR_LOG(dirfs_unsupported, __func__); 953 954 return EOPNOTSUPP; 955 } 956 957 static int 958 dirfs_nrename(struct vop_nrename_args *ap) 959 { 960 dirfs_node_t dnp, fdnp, tdnp; 961 dirfs_mount_t dmp; 962 struct namecache *fncp, *tncp; 963 struct vnode *fdvp, *tdvp, *vp; 964 struct mount *mp; 965 char *fpath, *fpathfree; 966 char *tpath, *tpathfree; 967 int error; 968 969 debug_called(); 970 971 error = 0; 972 fdvp = ap->a_fdvp; 973 tdvp = ap->a_tdvp; 974 fncp = ap->a_fnch->ncp; 975 tncp = ap->a_tnch->ncp; 976 mp = fdvp->v_mount; 977 dmp = VFS_TO_DIRFS(mp); 978 fdnp = VP_TO_NODE(fdvp); 979 tdnp = VP_TO_NODE(tdvp); 980 981 dbg(5, "fdnp=%p tdnp=%p from=%s to=%s\n", fdnp, tdnp, fncp->nc_name, 982 tncp->nc_name); 983 984 if (fdvp->v_mount != tdvp->v_mount) 985 return(EXDEV); 986 if (fdvp->v_mount != fncp->nc_vp->v_mount) 987 return(EXDEV); 988 if (fdvp->v_mount->mnt_flag & MNT_RDONLY) 989 return (EROFS); 990 991 tpath = dirfs_node_absolute_path_plus(dmp, tdnp, 992 tncp->nc_name, &tpathfree); 993 fpath = dirfs_node_absolute_path_plus(dmp, fdnp, 994 fncp->nc_name, &fpathfree); 995 error = rename(fpath, tpath); 996 if (error < 0) 997 error = errno; 998 if (error == 0) { 999 vp = fncp->nc_vp; /* file being renamed */ 1000 dnp = VP_TO_NODE(vp); 1001 dirfs_node_setname(dnp, tncp->nc_name, tncp->nc_nlen); 1002 1003 /* 1004 * We have to mark the target file that was replaced by 1005 * the rename as having been unlinked. 1006 */ 1007 vp = tncp->nc_vp; 1008 if (vp) { 1009 dbg(5, "RENAME2\n"); 1010 dnp = VP_TO_NODE(vp); 1011 cache_unlink(ap->a_tnch); 1012 dirfs_node_setpassive(dmp, dnp, 0); 1013 if (dnp->dn_parent) { 1014 dirfs_node_drop(dmp, dnp->dn_parent); 1015 dnp->dn_parent = NULL; 1016 } 1017 1018 /* 1019 * nlinks on directories can be a bit weird. Zero 1020 * it out. 1021 */ 1022 dnp->dn_links = 0; 1023 cache_inval_vp(vp, CINV_DESTROY); 1024 } 1025 cache_rename(ap->a_fnch, ap->a_tnch); 1026 } 1027 dirfs_dropfd(dmp, NULL, fpathfree); 1028 dirfs_dropfd(dmp, NULL, tpathfree); 1029 1030 return error; 1031 } 1032 1033 static int 1034 dirfs_nmkdir(struct vop_nmkdir_args *ap) 1035 { 1036 dirfs_mount_t dmp; 1037 dirfs_node_t dnp, pdnp, dnp1; 1038 struct namecache *ncp; 1039 struct vattr *vap; 1040 struct vnode *dvp; 1041 struct vnode **vpp; 1042 char *tmp, *pathfree; 1043 char *path; 1044 int pfd, error; 1045 int extrapath; 1046 1047 debug_called(); 1048 1049 extrapath = error = 0; 1050 dvp = ap->a_dvp; 1051 vpp = ap->a_vpp; 1052 dmp = VFS_TO_DIRFS(dvp->v_mount); 1053 pdnp = VP_TO_NODE(dvp); 1054 ncp = ap->a_nch->ncp; 1055 vap = ap->a_vap; 1056 pathfree = tmp = path = NULL; 1057 dnp = NULL; 1058 1059 dirfs_node_lock(pdnp); 1060 if (pdnp->dn_fd != DIRFS_NOFD) { 1061 pfd = pdnp->dn_fd; 1062 path = ncp->nc_name; 1063 } else { 1064 dnp1 = dirfs_findfd(dmp, pdnp, &tmp, &pathfree); 1065 pfd = dnp1->dn_fd; 1066 /* XXX check there is room to copy the path */ 1067 path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK); 1068 ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name); 1069 extrapath = 1; 1070 dirfs_dropfd(dmp, dnp1, pathfree); 1071 } 1072 1073 error = mkdirat(pfd, path, vap->va_mode); 1074 if (error) { 1075 error = errno; 1076 } else { /* Directory has been made */ 1077 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, 1078 vap, O_DIRECTORY); 1079 if (error) 1080 error = errno; 1081 cache_setunresolved(ap->a_nch); 1082 cache_setvp(ap->a_nch, *vpp); 1083 } 1084 dirfs_node_unlock(pdnp); 1085 1086 if (extrapath) 1087 kfree(path, M_DIRFS_MISC); 1088 1089 KTR_LOG(dirfs_nmkdir, pdnp, dnp, ncp->nc_name, error); 1090 1091 return error; 1092 } 1093 1094 static int 1095 dirfs_nrmdir(struct vop_nrmdir_args *ap) 1096 { 1097 dirfs_node_t dnp, pdnp; 1098 dirfs_mount_t dmp; 1099 struct vnode *dvp; 1100 struct nchandle *nch; 1101 struct namecache *ncp; 1102 struct mount *mp; 1103 struct vnode *vp; 1104 int error; 1105 char *tmp; 1106 char *pathfree; 1107 1108 debug_called(); 1109 1110 error = 0; 1111 tmp = NULL; 1112 vp = NULL; 1113 dvp = ap->a_dvp; 1114 nch = ap->a_nch; 1115 ncp = nch->ncp; 1116 1117 mp = dvp->v_mount; 1118 dmp = VFS_TO_DIRFS(mp); 1119 1120 lwkt_gettoken(&mp->mnt_token); 1121 cache_vget(nch, ap->a_cred, LK_SHARED, &vp); 1122 vn_unlock(vp); 1123 1124 pdnp = VP_TO_NODE(dvp); 1125 dnp = VP_TO_NODE(vp); 1126 1127 if (vp->v_type != VDIR) { 1128 error = ENOTDIR; 1129 } else { 1130 tmp = dirfs_node_absolute_path(dmp, dnp, &pathfree); 1131 dirfs_node_lock(pdnp); 1132 error = rmdir(tmp); 1133 if (error == 0) { 1134 cache_unlink(nch); 1135 dirfs_node_setpassive(dmp, dnp, 0); 1136 if (dnp->dn_parent) { 1137 dirfs_node_drop(dmp, dnp->dn_parent); 1138 dnp->dn_parent = NULL; 1139 } 1140 1141 /* 1142 * nlinks on directories can be a bit weird. Zero 1143 * it out. 1144 */ 1145 dnp->dn_links = 0; 1146 cache_inval_vp(vp, CINV_DESTROY); 1147 } else { 1148 error = errno; 1149 } 1150 dirfs_node_unlock(pdnp); 1151 dirfs_dropfd(dmp, NULL, pathfree); 1152 } 1153 vrele(vp); 1154 lwkt_reltoken(&mp->mnt_token); 1155 1156 KTR_LOG(dirfs_nrmdir, dnp, pdnp, error); 1157 1158 return error; 1159 } 1160 1161 static int 1162 dirfs_nsymlink(struct vop_nsymlink_args *ap) 1163 { 1164 dirfs_mount_t dmp; 1165 dirfs_node_t dnp, pdnp; 1166 struct mount *mp; 1167 struct namecache *ncp; 1168 struct vattr *vap; 1169 struct vnode *dvp; 1170 struct vnode **vpp; 1171 char *tmp, *pathfree; 1172 char *path; 1173 int error; 1174 1175 debug_called(); 1176 1177 error = 0; 1178 dvp = ap->a_dvp; 1179 vpp = ap->a_vpp; 1180 mp = dvp->v_mount; 1181 dmp = VFS_TO_DIRFS(dvp->v_mount); 1182 pdnp = VP_TO_NODE(dvp); 1183 ncp = ap->a_nch->ncp; 1184 vap = ap->a_vap; 1185 pathfree = tmp = path = NULL; 1186 dnp = NULL; 1187 1188 lwkt_gettoken(&mp->mnt_token); 1189 vap->va_type = VLNK; 1190 1191 /* Find out the whole path of our new symbolic link */ 1192 tmp = dirfs_node_absolute_path(dmp, pdnp, &pathfree); 1193 /* XXX check there is room to copy the path */ 1194 path = kmalloc(MAXPATHLEN, M_DIRFS_MISC, M_ZERO | M_WAITOK); 1195 ksnprintf(path, MAXPATHLEN, "%s/%s", tmp, ncp->nc_name); 1196 dirfs_dropfd(dmp, NULL, pathfree); 1197 1198 error = symlink(ap->a_target, path); 1199 if (error) { 1200 error = errno; 1201 } else { /* Symlink has been made */ 1202 error = dirfs_alloc_file(dmp, &dnp, pdnp, ncp, vpp, 1203 NULL, 0); 1204 if (error) 1205 error = errno; 1206 cache_setunresolved(ap->a_nch); 1207 cache_setvp(ap->a_nch, *vpp); 1208 } 1209 dbg(5, "path=%s a_target=%s\n", path, ap->a_target); 1210 1211 KTR_LOG(dirfs_nsymlink, dnp, ap->a_target, path, error); 1212 kfree(path, M_DIRFS_MISC); 1213 lwkt_reltoken(&mp->mnt_token); 1214 1215 return error; 1216 1217 } 1218 1219 static int 1220 dirfs_readdir(struct vop_readdir_args *ap) 1221 { 1222 1223 struct dirent *dp, *dpn; 1224 off_t __unused **cookies = ap->a_cookies; 1225 int *ncookies = ap->a_ncookies; 1226 int bytes; 1227 char *buf; 1228 long base; 1229 struct vnode *vp = ap->a_vp; 1230 struct uio *uio; 1231 dirfs_node_t dnp; 1232 off_t startoff; 1233 off_t cnt; 1234 int error, r; 1235 size_t bufsiz; 1236 off_t curoff; 1237 1238 debug_called(); 1239 1240 if (ncookies) 1241 debug(1, "ncookies=%d\n", *ncookies); 1242 1243 dnp = VP_TO_NODE(vp); 1244 uio = ap->a_uio; 1245 startoff = uio->uio_offset; 1246 cnt = 0; 1247 error = 0; 1248 base = 0; 1249 bytes = 0; 1250 1251 if (vp->v_type != VDIR) 1252 return ENOTDIR; 1253 if (uio->uio_resid < 0) 1254 return EINVAL; 1255 if ((bufsiz = uio->uio_resid) > 4096) 1256 bufsiz = 4096; 1257 buf = kmalloc(bufsiz, M_DIRFS_MISC, M_WAITOK | M_ZERO); 1258 1259 /* 1260 * Generally speaking we have to be able to process ALL the 1261 * entries returned by getdirentries() in order for the seek 1262 * position to be correct. For now try to size the buffer 1263 * to make this happen. A smaller buffer always works. For 1264 * now just use an appropriate size. 1265 */ 1266 dirfs_node_lock(dnp); 1267 lseek(dnp->dn_fd, startoff, SEEK_SET); 1268 bytes = getdirentries(dnp->dn_fd, buf, bufsiz, &base); 1269 dbg(5, "seek %016jx %016jx %016jx\n", 1270 (intmax_t)startoff, (intmax_t)base, 1271 (intmax_t)lseek(dnp->dn_fd, 0, SEEK_CUR)); 1272 if (bytes < 0) { 1273 if (errno == EINVAL) 1274 panic("EINVAL on readdir\n"); 1275 error = errno; 1276 curoff = startoff; 1277 goto out; 1278 } else if (bytes == 0) { 1279 *ap->a_eofflag = 1; 1280 curoff = startoff; 1281 goto out; 1282 } 1283 1284 for (dp = (struct dirent *)buf; bytes > 0 && uio->uio_resid > 0; 1285 bytes -= _DIRENT_DIRSIZ(dp), dp = dpn) { 1286 r = vop_write_dirent(&error, uio, dp->d_ino, dp->d_type, 1287 dp->d_namlen, dp->d_name); 1288 if (error || r) 1289 break; 1290 dpn = _DIRENT_NEXT(dp); 1291 dp = dpn; 1292 cnt++; 1293 } 1294 curoff = lseek(dnp->dn_fd, 0, SEEK_CUR); 1295 1296 out: 1297 kfree(buf, M_DIRFS_MISC); 1298 uio->uio_offset = curoff; 1299 dirfs_node_unlock(dnp); 1300 1301 KTR_LOG(dirfs_readdir, dnp, dnp->dn_fd, startoff, uio->uio_offset); 1302 1303 return error; 1304 } 1305 1306 static int 1307 dirfs_readlink(struct vop_readlink_args *ap) 1308 { 1309 dirfs_node_t dnp, pathnp; 1310 dirfs_mount_t dmp; 1311 struct vnode *vp; 1312 struct mount *mp; 1313 struct uio *uio; 1314 char *tmp, *pathfree, *buf; 1315 ssize_t nlen; 1316 int error; 1317 1318 debug_called(); 1319 1320 vp = ap->a_vp; 1321 1322 KKASSERT(vp->v_type == VLNK); 1323 1324 error = 0; 1325 tmp = pathfree = NULL; 1326 uio = ap->a_uio; 1327 mp = vp->v_mount; 1328 dmp = VFS_TO_DIRFS(mp); 1329 dnp = VP_TO_NODE(vp); 1330 1331 lwkt_gettoken(&mp->mnt_token); 1332 1333 pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); 1334 1335 buf = kmalloc(uio->uio_resid, M_DIRFS_MISC, M_WAITOK | M_ZERO); 1336 nlen = readlinkat(pathnp->dn_fd, dnp->dn_name, buf, uio->uio_resid); 1337 if (nlen == -1 ) { 1338 error = errno; 1339 } else { 1340 error = uiomove(buf, nlen + 1, uio); 1341 buf[nlen] = '\0'; 1342 if (error) 1343 error = errno; 1344 } 1345 dirfs_dropfd(dmp, pathnp, pathfree); 1346 kfree(buf, M_DIRFS_MISC); 1347 1348 lwkt_reltoken(&mp->mnt_token); 1349 1350 return error; 1351 } 1352 1353 /* 1354 * Main tasks to be performed. 1355 * 1) When inode is NULL recycle the vnode 1356 * 2) When the inode has 0 links: 1357 * - Check if in the TAILQ, if so remove. 1358 * - Destroy the inode. 1359 * - Recycle the vnode. 1360 * 3) If none of the above, add the node to the TAILQ 1361 * when it has a valid fd and there is room on the 1362 * queue. 1363 * 1364 */ 1365 static int 1366 dirfs_inactive(struct vop_inactive_args *ap) 1367 { 1368 struct vnode *vp; 1369 dirfs_mount_t dmp; 1370 dirfs_node_t dnp; 1371 1372 debug_called(); 1373 1374 vp = ap->a_vp; 1375 dmp = VFS_TO_DIRFS(vp->v_mount); 1376 dnp = VP_TO_NODE(vp); 1377 1378 /* Degenerate case */ 1379 if (dnp == NULL) { 1380 dbg(5, "dnp was NULL\n"); 1381 vrecycle(vp); 1382 return 0; 1383 } 1384 1385 dirfs_mount_gettoken(dmp); 1386 1387 /* 1388 * Deal with the case the inode has 0 links which means it was unlinked. 1389 */ 1390 if (dnp->dn_links == 0) { 1391 vrecycle(vp); 1392 dbg(5, "recycled a vnode of an unlinked dnp\n"); 1393 1394 goto out; 1395 } 1396 1397 /* 1398 * Try to retain the fd in our fd cache. 1399 */ 1400 dirfs_node_setpassive(dmp, dnp, 1); 1401 out: 1402 dirfs_mount_reltoken(dmp); 1403 1404 return 0; 1405 1406 } 1407 1408 int 1409 dirfs_reclaim(struct vop_reclaim_args *ap) 1410 { 1411 struct vnode *vp; 1412 dirfs_node_t dnp; 1413 dirfs_mount_t dmp; 1414 1415 debug_called(); 1416 1417 vp = ap->a_vp; 1418 dnp = VP_TO_NODE(vp); 1419 dmp = VFS_TO_DIRFS(vp->v_mount); 1420 1421 dirfs_free_vp(dmp, dnp); 1422 /* dnp is now invalid, may have been destroyed */ 1423 1424 return 0; 1425 } 1426 1427 static int 1428 dirfs_mountctl(struct vop_mountctl_args *ap) 1429 { 1430 debug_called(); 1431 1432 KTR_LOG(dirfs_unsupported, __func__); 1433 1434 return EOPNOTSUPP; 1435 } 1436 1437 static int 1438 dirfs_print(struct vop_print_args *v) 1439 { 1440 debug_called(); 1441 1442 KTR_LOG(dirfs_unsupported, __func__); 1443 1444 return EOPNOTSUPP; 1445 } 1446 1447 static int __unused 1448 dirfs_pathconf(struct vop_pathconf_args *v) 1449 { 1450 debug_called(); 1451 1452 return EOPNOTSUPP; 1453 } 1454 1455 static int 1456 dirfs_kqfilter (struct vop_kqfilter_args *ap) 1457 { 1458 debug_called(); 1459 1460 KTR_LOG(dirfs_unsupported, __func__); 1461 1462 return EOPNOTSUPP; 1463 } 1464 1465 struct vop_ops dirfs_vnode_vops = { 1466 .vop_default = vop_defaultop, 1467 .vop_nwhiteout = vop_compat_nwhiteout, 1468 .vop_ncreate = dirfs_ncreate, 1469 .vop_nresolve = dirfs_nresolve, 1470 .vop_markatime = vop_stdmarkatime, 1471 .vop_nlookupdotdot = dirfs_nlookupdotdot, 1472 .vop_nmknod = dirfs_nmknod, 1473 .vop_open = dirfs_open, 1474 .vop_close = dirfs_close, 1475 .vop_access = dirfs_access, 1476 .vop_getattr = dirfs_getattr, 1477 .vop_setattr = dirfs_setattr, 1478 .vop_read = dirfs_read, 1479 .vop_write = dirfs_write, 1480 .vop_fsync = dirfs_fsync, 1481 .vop_mountctl = dirfs_mountctl, 1482 .vop_nremove = dirfs_nremove, 1483 .vop_nlink = dirfs_nlink, 1484 .vop_nrename = dirfs_nrename, 1485 .vop_nmkdir = dirfs_nmkdir, 1486 .vop_nrmdir = dirfs_nrmdir, 1487 .vop_nsymlink = dirfs_nsymlink, 1488 .vop_readdir = dirfs_readdir, 1489 .vop_readlink = dirfs_readlink, 1490 .vop_inactive = dirfs_inactive, 1491 .vop_reclaim = dirfs_reclaim, 1492 .vop_print = dirfs_print, 1493 .vop_pathconf = vop_stdpathconf, 1494 .vop_bmap = dirfs_bmap, 1495 .vop_strategy = dirfs_strategy, 1496 .vop_advlock = dirfs_advlock, 1497 .vop_kqfilter = dirfs_kqfilter, 1498 .vop_getpages = vop_stdgetpages, 1499 .vop_putpages = vop_stdputpages 1500 }; 1501