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 mtx_lock_sh_quick(&->am_lock); 236 error = autofs_node_find(anp, ncp->nc_name, ncp->nc_nlen, &child); 237 mtx_unlock_sh(&->am_lock); 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 mtx_lock_ex_quick(&->am_lock); 276 error = autofs_node_new(anp, amp, ncp->nc_name, ncp->nc_nlen, &child); 277 mtx_unlock_ex(&->am_lock); 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 mtx_lock_sh_quick(&->am_lock); 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 mtx_unlock_sh(&->am_lock); 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 mtx_unlock_sh(&->am_lock); 395 goto out; 396 } 397 } 398 mtx_unlock_sh(&->am_lock); 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 mtx_lock_ex_quick(&anp->an_vnode_lock); 431 anp->an_vnode = NULL; 432 vp->v_data = NULL; 433 mtx_unlock_ex(&anp->an_vnode_lock); 434 435 return (0); 436 } 437 438 static int 439 autofs_mountctl(struct vop_mountctl_args *ap) 440 { 441 struct mount *mp; 442 int res; 443 444 mp = ap->a_head.a_ops->head.vv_mount; 445 lwkt_gettoken(&mp->mnt_token); 446 447 switch (ap->a_op) { 448 //case ...: 449 // break; 450 default: 451 res = vop_stdmountctl(ap); 452 break; 453 } 454 455 lwkt_reltoken(&mp->mnt_token); 456 return (res); 457 } 458 459 static int 460 autofs_print(struct vop_print_args *ap) 461 { 462 struct autofs_node *anp = VTOI(ap->a_vp); 463 464 kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n", 465 anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached, 466 anp->an_retries, anp->an_wildcards); 467 468 return (0); 469 } 470 471 struct vop_ops autofs_vnode_vops = { 472 .vop_default = vop_defaultop, 473 .vop_getpages = vop_stdgetpages, 474 .vop_putpages = vop_stdputpages, 475 .vop_access = autofs_access, 476 .vop_getattr = autofs_getattr, 477 .vop_nresolve = autofs_nresolve, 478 .vop_nmkdir = autofs_nmkdir, 479 .vop_readdir = autofs_readdir, 480 .vop_reclaim = autofs_reclaim, 481 .vop_mountctl = autofs_mountctl, 482 .vop_print = autofs_print, 483 }; 484 485 int 486 autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, 487 const char *name, int namelen, struct autofs_node **anpp) 488 { 489 struct autofs_node *anp; 490 491 KKASSERT(mtx_islocked_ex(&->am_lock)); 492 493 if (parent != NULL) { 494 KKASSERT(mtx_islocked_ex(&parent->an_mount->am_lock)); 495 KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT, 496 ("node \"%s\" already exists", name)); 497 } 498 499 anp = objcache_get(autofs_node_objcache, M_WAITOK); 500 if (namelen >= 0) 501 anp->an_name = kstrndup(name, namelen, M_AUTOFS); 502 else 503 anp->an_name = kstrdup(name, M_AUTOFS); 504 anp->an_ino = amp->am_last_ino++; 505 callout_init(&anp->an_callout); 506 mtx_init(&anp->an_vnode_lock, "autofsvnlk"); 507 getnanotime(&anp->an_ctime); 508 anp->an_parent = parent; 509 anp->an_mount = amp; 510 anp->an_vnode = NULL; 511 anp->an_cached = false; 512 anp->an_wildcards = false; 513 anp->an_retries = 0; 514 if (parent != NULL) 515 RB_INSERT(autofs_node_tree, &parent->an_children, anp); 516 RB_INIT(&anp->an_children); 517 518 *anpp = anp; 519 520 return (0); 521 } 522 523 int 524 autofs_node_find(struct autofs_node *parent, const char *name, 525 int namelen, struct autofs_node **anpp) 526 { 527 struct autofs_node *anp, find; 528 int error; 529 530 KKASSERT(mtx_islocked(&parent->an_mount->am_lock)); 531 532 if (namelen >= 0) 533 find.an_name = kstrndup(name, namelen, M_AUTOFS); 534 else 535 find.an_name = kstrdup(name, M_AUTOFS); 536 537 anp = RB_FIND(autofs_node_tree, &parent->an_children, &find); 538 if (anp != NULL) { 539 error = 0; 540 if (anpp != NULL) 541 *anpp = anp; 542 } else { 543 error = ENOENT; 544 } 545 546 kfree(find.an_name, M_AUTOFS); 547 548 return (error); 549 } 550 551 void 552 autofs_node_delete(struct autofs_node *anp) 553 { 554 KKASSERT(mtx_islocked_ex(&anp->an_mount->am_lock)); 555 KASSERT(RB_EMPTY(&anp->an_children), ("have children")); 556 557 callout_drain(&anp->an_callout); 558 559 if (anp->an_parent != NULL) 560 RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp); 561 562 mtx_uninit(&anp->an_vnode_lock); 563 kfree(anp->an_name, M_AUTOFS); 564 objcache_put(autofs_node_objcache, anp); 565 } 566 567 int 568 autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags, 569 struct vnode **vpp) 570 { 571 struct vnode *vp = NULL; 572 int error; 573 retry: 574 KKASSERT(mtx_notlocked(&anp->an_mount->am_lock)); 575 mtx_lock_ex_quick(&anp->an_vnode_lock); 576 577 vp = anp->an_vnode; 578 if (vp != NULL) { 579 vhold(vp); 580 mtx_unlock_ex(&anp->an_vnode_lock); 581 582 error = vget(vp, flags | LK_RETRY); 583 if (error) { 584 AUTOFS_WARN("vget failed with error %d", error); 585 vdrop(vp); 586 goto retry; 587 } 588 vdrop(vp); 589 *vpp = vp; 590 return (0); 591 } 592 593 mtx_unlock_ex(&anp->an_vnode_lock); 594 595 error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 596 if (error) 597 return (error); 598 vp->v_type = VDIR; 599 vp->v_data = anp; 600 601 KASSERT(anp->an_vnode == NULL, ("lost race")); 602 anp->an_vnode = vp; 603 *vpp = vp; 604 605 return (0); 606 } 607