1 /*- 2 * Copyright (c) 2016 The DragonFly Project 3 * Copyright (c) 2014 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Edward Tomasz Napierala under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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 the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/stat.h> 35 #include <sys/dirent.h> 36 #include <sys/namei.h> 37 #include <sys/nlookup.h> 38 #include <sys/mountctl.h> 39 40 #include "autofs.h" 41 42 static int autofs_trigger_vn(struct vnode *vp, const char *path, 43 int pathlen, struct vnode **newvp); 44 45 extern struct autofs_softc *autofs_softc; 46 47 static __inline size_t 48 autofs_dirent_reclen(const char *name) 49 { 50 return (_DIRENT_RECLEN(strlen(name))); 51 } 52 53 static int 54 test_fs_root(struct vnode *vp) 55 { 56 int error; 57 58 if ((error = vget(vp, LK_SHARED)) != 0) { 59 AUTOFS_WARN("vget failed with error %d", error); 60 return (1); 61 } 62 63 if (((vp->v_flag & VROOT) == 0) || (vp->v_tag == VT_AUTOFS)) { 64 vput(vp); 65 return (1); 66 } 67 68 return (0); 69 } 70 71 static int 72 nlookup_fs_root(struct autofs_node *anp, struct vnode **vpp) 73 { 74 struct vnode *vp; 75 struct nlookupdata nd; 76 char *path; 77 int error; 78 79 path = autofs_path(anp); 80 81 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); 82 if (error == 0) { 83 error = nlookup(&nd); 84 if (error == 0) { 85 vp = nd.nl_nch.ncp->nc_vp; 86 error = test_fs_root(vp); 87 if (error == 0) 88 *vpp = vp; 89 } 90 } 91 nlookup_done(&nd); 92 kfree(path, M_AUTOFS); 93 94 return (error); 95 } 96 97 static int 98 autofs_access(struct vop_access_args *ap) 99 { 100 /* 101 * Nothing to do here; the only kind of access control 102 * needed is in autofs_mkdir(). 103 */ 104 return (0); 105 } 106 107 static int 108 autofs_getattr(struct vop_getattr_args *ap) 109 { 110 struct vnode *vp = ap->a_vp; 111 struct vattr *vap = ap->a_vap; 112 struct autofs_node *anp = VTOI(vp); 113 static bool warned = false; 114 115 KASSERT(vp->v_type == VDIR, ("!VDIR")); 116 117 /* 118 * The reason we must do this is that some tree-walking software, 119 * namely fts(3), assumes that stat(".") results will not change 120 * between chdir("subdir") and chdir(".."), and fails with ENOENT 121 * otherwise. 122 * 123 * XXX: Not supported on DragonFly. 124 * With the current trigger mechanism on DragonFly, the process 125 * will hang while in nlookup() in nlookup_fs_root(). 126 */ 127 if (autofs_mount_on_stat) { 128 if (!warned) { 129 AUTOFS_WARN("vfs.autofs.mount_on_stat not supported"); 130 warned = true; 131 } 132 } 133 134 vap->va_type = VDIR; 135 vap->va_mode = 0755; 136 vap->va_nlink = 3; /* XXX: FreeBSD had it like this */ 137 vap->va_uid = 0; 138 vap->va_gid = 0; 139 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 140 vap->va_fileid = anp->an_ino; 141 vap->va_size = S_BLKSIZE; 142 vap->va_blocksize = S_BLKSIZE; 143 vap->va_mtime = anp->an_ctime; 144 vap->va_atime = anp->an_ctime; 145 vap->va_ctime = anp->an_ctime; 146 vap->va_gen = 0; 147 vap->va_flags = 0; 148 vap->va_rmajor = 0; 149 vap->va_rminor = 0; 150 vap->va_bytes = S_BLKSIZE; 151 vap->va_filerev = 0; 152 vap->va_spare = 0; 153 154 return (0); 155 } 156 157 static int 158 autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen, 159 struct vnode **newvp) 160 { 161 struct autofs_node *anp = VTOI(vp); 162 struct vnode *nvp = NULL; 163 int error; 164 165 KKASSERT(!vn_islocked(vp)); 166 167 if (test_fs_root(vp) == 0) 168 goto mounted; 169 170 /* 171 * Don't remove this. Without having this extra nlookup, 172 * automountd tries to mount the target filesystem twice 173 * and the second attempt to mount returns an error. 174 */ 175 if (nlookup_fs_root(anp, &nvp) == 0) 176 goto mounted; 177 178 lockmgr(&autofs_softc->sc_lock, LK_EXCLUSIVE); 179 error = autofs_trigger(anp, path, pathlen); 180 lockmgr(&autofs_softc->sc_lock, LK_RELEASE); 181 182 if (error) 183 return (error); 184 185 if (nlookup_fs_root(anp, &nvp)) 186 return (0); 187 188 /* 189 * If the operation that succeeded was mount, then mark 190 * the node as non-cached. Otherwise, if someone unmounts 191 * the filesystem before the cache times out, we will fail 192 * to trigger. 193 */ 194 autofs_node_uncache(anp); 195 mounted: 196 *newvp = nvp; 197 KKASSERT(vn_islocked(*newvp)); 198 199 return (0); 200 } 201 202 static int 203 autofs_nresolve(struct vop_nresolve_args *ap) 204 { 205 struct vnode *vp = NULL; 206 struct vnode *dvp = ap->a_dvp; 207 struct nchandle *nch = ap->a_nch; 208 struct namecache *ncp = nch->ncp; 209 struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 210 struct autofs_node *anp = VTOI(dvp); 211 struct autofs_node *child = NULL; 212 int error; 213 214 if (autofs_cached(anp, ncp->nc_name, ncp->nc_nlen) == false && 215 autofs_ignore_thread() == false) { 216 struct vnode *newvp = NULL; 217 218 cache_hold(nch); 219 cache_unlock(nch); 220 error = autofs_trigger_vn(dvp, 221 ncp->nc_name, ncp->nc_nlen, &newvp); 222 cache_lock(nch); 223 cache_drop(nch); 224 225 if (error) 226 return (error); 227 if (newvp != NULL) { 228 KKASSERT(newvp->v_tag != VT_AUTOFS); 229 vput(newvp); 230 return (ESTALE); 231 } 232 return (0); 233 } 234 235 lockmgr(&->am_lock, LK_SHARED); 236 error = autofs_node_find(anp, ncp->nc_name, ncp->nc_nlen, &child); 237 lockmgr(&->am_lock, LK_RELEASE); 238 239 if (error) { 240 cache_setvp(nch, NULL); 241 return (0); 242 } 243 244 error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 245 if (error == 0) { 246 KKASSERT(vn_islocked(vp)); 247 vn_unlock(vp); 248 cache_setvp(nch, vp); 249 vrele(vp); 250 return (0); 251 } 252 253 return (error); 254 } 255 256 static int 257 autofs_nmkdir(struct vop_nmkdir_args *ap) 258 { 259 struct vnode *vp = NULL; 260 struct vnode *dvp = ap->a_dvp; 261 struct nchandle *nch = ap->a_nch; 262 struct namecache *ncp = nch->ncp; 263 struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount); 264 struct autofs_node *anp = VTOI(dvp); 265 struct autofs_node *child = NULL; 266 int error; 267 268 /* 269 * Do not allow mkdir() if the calling thread is not 270 * automountd(8) descendant. 271 */ 272 if (autofs_ignore_thread() == false) 273 return (EPERM); 274 275 lockmgr(&->am_lock, LK_EXCLUSIVE); 276 error = autofs_node_new(anp, amp, ncp->nc_name, ncp->nc_nlen, &child); 277 lockmgr(&->am_lock, LK_RELEASE); 278 KKASSERT(error == 0); 279 280 error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp); 281 if (error == 0) { 282 KKASSERT(vn_islocked(vp)); 283 cache_setunresolved(nch); 284 cache_setvp(nch, vp); 285 *(ap->a_vpp) = vp; 286 return (0); 287 } 288 289 return (error); 290 } 291 292 static int 293 autofs_readdir_one(struct uio *uio, const char *name, ino_t ino, 294 size_t *reclenp) 295 { 296 int error = 0; 297 298 if (reclenp != NULL) 299 *reclenp = autofs_dirent_reclen(name); 300 301 if (vop_write_dirent(&error, uio, ino, DT_DIR, strlen(name), name)) 302 return (EINVAL); 303 304 return (error); 305 } 306 307 static int 308 autofs_readdir(struct vop_readdir_args *ap) 309 { 310 struct vnode *vp = ap->a_vp; 311 struct autofs_mount *amp = VFSTOAUTOFS(vp->v_mount); 312 struct autofs_node *anp = VTOI(vp); 313 struct autofs_node *child; 314 struct uio *uio = ap->a_uio; 315 ssize_t initial_resid = ap->a_uio->uio_resid; 316 size_t reclen, reclens; 317 int error; 318 319 KASSERT(vp->v_type == VDIR, ("!VDIR")); 320 321 if (autofs_cached(anp, NULL, 0) == false && 322 autofs_ignore_thread() == false) { 323 struct vnode *newvp = NULL; 324 error = autofs_trigger_vn(vp, "", 0, &newvp); 325 if (error) 326 return (error); 327 if (newvp != NULL) { 328 KKASSERT(newvp->v_tag != VT_AUTOFS); 329 vn_unlock(newvp); 330 error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred, 331 ap->a_eofflag, ap->a_ncookies, ap->a_cookies); 332 vrele(newvp); 333 return (error); 334 } 335 /* FALLTHROUGH */ 336 } 337 338 if (uio->uio_offset < 0) 339 return (EINVAL); 340 341 if (ap->a_eofflag != NULL) 342 *ap->a_eofflag = FALSE; 343 344 /* 345 * Write out the directory entry for ".". 346 */ 347 if (uio->uio_offset == 0) { 348 error = autofs_readdir_one(uio, ".", anp->an_ino, &reclen); 349 if (error) 350 goto out; 351 } 352 reclens = autofs_dirent_reclen("."); 353 354 /* 355 * Write out the directory entry for "..". 356 */ 357 if (uio->uio_offset <= reclens) { 358 if (uio->uio_offset != reclens) 359 return (EINVAL); 360 error = autofs_readdir_one(uio, "..", 361 (anp->an_parent ? anp->an_parent->an_ino : anp->an_ino), 362 &reclen); 363 if (error) 364 goto out; 365 } 366 reclens += autofs_dirent_reclen(".."); 367 368 /* 369 * Write out the directory entries for subdirectories. 370 */ 371 lockmgr(&->am_lock, LK_SHARED); 372 RB_FOREACH(child, autofs_node_tree, &anp->an_children) { 373 /* 374 * Check the offset to skip entries returned by previous 375 * calls to getdents(). 376 */ 377 if (uio->uio_offset > reclens) { 378 reclens += autofs_dirent_reclen(child->an_name); 379 continue; 380 } 381 382 /* 383 * Prevent seeking into the middle of dirent. 384 */ 385 if (uio->uio_offset != reclens) { 386 lockmgr(&->am_lock, LK_RELEASE); 387 return (EINVAL); 388 } 389 390 error = autofs_readdir_one(uio, child->an_name, 391 child->an_ino, &reclen); 392 reclens += reclen; 393 if (error) { 394 lockmgr(&->am_lock, LK_RELEASE); 395 goto out; 396 } 397 } 398 lockmgr(&->am_lock, LK_RELEASE); 399 400 if (ap->a_eofflag != NULL) 401 *ap->a_eofflag = TRUE; 402 403 return (0); 404 out: 405 /* 406 * Return error if the initial buffer was too small to do anything. 407 */ 408 if (uio->uio_resid == initial_resid) 409 return (error); 410 411 /* 412 * Don't return an error if we managed to copy out some entries. 413 */ 414 if (uio->uio_resid < reclen) 415 return (0); 416 417 return (error); 418 } 419 420 static int 421 autofs_reclaim(struct vop_reclaim_args *ap) 422 { 423 struct vnode *vp = ap->a_vp; 424 struct autofs_node *anp = VTOI(vp); 425 426 /* 427 * We do not free autofs_node here; instead we are 428 * destroying them in autofs_node_delete(). 429 */ 430 lockmgr(&anp->an_vnode_lock, LK_EXCLUSIVE); 431 anp->an_vnode = NULL; 432 vp->v_data = NULL; 433 lockmgr(&anp->an_vnode_lock, LK_RELEASE); 434 435 return (0); 436 } 437 438 static int 439 autofs_mountctl(struct vop_mountctl_args *ap) 440 { 441 struct mount *mp; 442 #if 0 443 struct autofs_mount *amp; 444 #endif 445 int res; 446 447 mp = ap->a_head.a_ops->head.vv_mount; 448 lwkt_gettoken(&mp->mnt_token); 449 450 switch (ap->a_op) { 451 #if 0 452 case MOUNTCTL_SET_EXPORT: 453 amp = (struct autofs_mount*)mp->mnt_data; 454 if (ap->a_ctllen != sizeof(struct export_args)) 455 res = (EINVAL); 456 else 457 res = vfs_export(mp, &->am_export, 458 (const struct export_args*)ap->a_ctl); 459 break; 460 #endif 461 default: 462 res = vop_stdmountctl(ap); 463 break; 464 } 465 466 lwkt_reltoken(&mp->mnt_token); 467 return (res); 468 } 469 470 static int 471 autofs_print(struct vop_print_args *ap) 472 { 473 struct autofs_node *anp = VTOI(ap->a_vp); 474 475 kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n", 476 anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached, anp->an_retries, anp->an_wildcards); 477 478 return (0); 479 } 480 481 struct vop_ops autofs_vnode_vops = { 482 .vop_default = vop_defaultop, 483 .vop_getpages = vop_stdgetpages, 484 .vop_putpages = vop_stdputpages, 485 .vop_access = autofs_access, 486 .vop_getattr = autofs_getattr, 487 .vop_nresolve = autofs_nresolve, 488 .vop_nmkdir = autofs_nmkdir, 489 .vop_readdir = autofs_readdir, 490 .vop_reclaim = autofs_reclaim, 491 .vop_mountctl = autofs_mountctl, 492 .vop_print = autofs_print, 493 #if 0 494 .vop_nlookupdotdot = NULL, 495 #endif 496 }; 497 498 int 499 autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, 500 const char *name, int namelen, struct autofs_node **anpp) 501 { 502 struct autofs_node *anp; 503 504 AUTOFS_ASSERT_XLOCKED(amp); 505 506 if (parent != NULL) { 507 AUTOFS_ASSERT_XLOCKED(parent->an_mount); 508 KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT, 509 ("node \"%s\" already exists", name)); 510 } 511 512 anp = objcache_get(autofs_node_objcache, M_WAITOK); 513 if (namelen >= 0) 514 anp->an_name = kstrndup(name, namelen, M_AUTOFS); 515 else 516 anp->an_name = kstrdup(name, M_AUTOFS); 517 anp->an_ino = amp->am_last_ino++; 518 callout_init(&anp->an_callout); 519 lockinit(&anp->an_vnode_lock, "autofsvnlk", 0, 0); 520 getnanotime(&anp->an_ctime); 521 anp->an_parent = parent; 522 anp->an_mount = amp; 523 anp->an_vnode = NULL; 524 anp->an_cached = false; 525 anp->an_wildcards = false; 526 anp->an_retries = 0; 527 if (parent != NULL) 528 RB_INSERT(autofs_node_tree, &parent->an_children, anp); 529 RB_INIT(&anp->an_children); 530 531 *anpp = anp; 532 533 return (0); 534 } 535 536 int 537 autofs_node_find(struct autofs_node *parent, const char *name, 538 int namelen, struct autofs_node **anpp) 539 { 540 struct autofs_node *anp, find; 541 int error; 542 543 AUTOFS_ASSERT_LOCKED(parent->an_mount); 544 545 if (namelen >= 0) 546 find.an_name = kstrndup(name, namelen, M_AUTOFS); 547 else 548 find.an_name = kstrdup(name, M_AUTOFS); 549 550 anp = RB_FIND(autofs_node_tree, &parent->an_children, &find); 551 if (anp != NULL) { 552 error = 0; 553 if (anpp != NULL) 554 *anpp = anp; 555 } else { 556 error = ENOENT; 557 } 558 559 kfree(find.an_name, M_AUTOFS); 560 561 return (error); 562 } 563 564 void 565 autofs_node_delete(struct autofs_node *anp) 566 { 567 AUTOFS_ASSERT_XLOCKED(anp->an_mount); 568 KASSERT(RB_EMPTY(&anp->an_children), ("have children")); 569 570 callout_drain(&anp->an_callout); 571 572 if (anp->an_parent != NULL) 573 RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp); 574 575 lockuninit(&anp->an_vnode_lock); 576 kfree(anp->an_name, M_AUTOFS); 577 objcache_put(autofs_node_objcache, anp); 578 } 579 580 int 581 autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags, 582 struct vnode **vpp) 583 { 584 struct vnode *vp = NULL; 585 int error; 586 retry: 587 AUTOFS_ASSERT_UNLOCKED(anp->an_mount); 588 lockmgr(&anp->an_vnode_lock, LK_EXCLUSIVE); 589 590 vp = anp->an_vnode; 591 if (vp != NULL) { 592 vhold(vp); 593 lockmgr(&anp->an_vnode_lock, LK_RELEASE); 594 595 error = vget(vp, flags | LK_RETRY); 596 if (error) { 597 AUTOFS_WARN("vget failed with error %d", error); 598 vdrop(vp); 599 goto retry; 600 } 601 vdrop(vp); 602 *vpp = vp; 603 return (0); 604 } 605 606 lockmgr(&anp->an_vnode_lock, LK_RELEASE); 607 608 error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 609 if (error) 610 return (error); 611 vp->v_type = VDIR; 612 vp->v_data = anp; 613 614 KASSERT(anp->an_vnode == NULL, ("lost race")); 615 anp->an_vnode = vp; 616 *vpp = vp; 617 618 return (0); 619 } 620