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