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