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