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