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