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 (EINVAL); 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 goto out; 340 } 341 reclens = autofs_dirent_reclen("."); 342 343 /* 344 * Write out the directory entry for "..". 345 */ 346 if (uio->uio_offset <= reclens) { 347 if (uio->uio_offset != reclens) 348 return (EINVAL); 349 error = autofs_write_dirent(uio, "..", 350 anp->an_parent ? anp->an_parent->an_ino : anp->an_ino); 351 if (error) 352 goto out; 353 } 354 reclens += autofs_dirent_reclen(".."); 355 356 /* 357 * Write out the directory entries for subdirectories. 358 */ 359 mtx_lock_sh_quick(&->am_lock); 360 RB_FOREACH(child, autofs_node_tree, &anp->an_children) { 361 /* 362 * Check the offset to skip entries returned by previous 363 * calls to getdents(). 364 */ 365 if (uio->uio_offset > reclens) { 366 reclens += autofs_dirent_reclen(child->an_name); 367 continue; 368 } 369 370 /* 371 * Prevent seeking into the middle of dirent. 372 */ 373 if (uio->uio_offset != reclens) { 374 mtx_unlock_sh(&->am_lock); 375 return (EINVAL); 376 } 377 378 error = autofs_write_dirent(uio, child->an_name, child->an_ino); 379 reclens += autofs_dirent_reclen(child->an_name); 380 if (error) { 381 mtx_unlock_sh(&->am_lock); 382 goto out; 383 } 384 } 385 mtx_unlock_sh(&->am_lock); 386 387 if (ap->a_eofflag != NULL) 388 *ap->a_eofflag = TRUE; 389 390 return (0); 391 out: 392 /* 393 * Return error if the initial buffer was too small to do anything. 394 */ 395 if (uio->uio_resid == initial_resid) 396 return (error); 397 398 /* 399 * Don't return an error if we managed to copy out some entries. 400 */ 401 if (uio->uio_resid < initial_resid) 402 return (0); 403 404 return (error); 405 } 406 407 static int 408 autofs_reclaim(struct vop_reclaim_args *ap) 409 { 410 struct vnode *vp = ap->a_vp; 411 struct autofs_node *anp = VTOI(vp); 412 413 /* 414 * We do not free autofs_node here; instead we are 415 * destroying them in autofs_node_delete(). 416 */ 417 mtx_lock_ex_quick(&anp->an_vnode_lock); 418 anp->an_vnode = NULL; 419 vp->v_data = NULL; 420 mtx_unlock_ex(&anp->an_vnode_lock); 421 422 return (0); 423 } 424 425 static int 426 autofs_mountctl(struct vop_mountctl_args *ap) 427 { 428 struct mount *mp; 429 int res = 0; 430 431 mp = ap->a_head.a_ops->head.vv_mount; 432 lwkt_gettoken(&mp->mnt_token); 433 434 switch (ap->a_op) { 435 //case ...: 436 // break; 437 default: 438 res = vop_stdmountctl(ap); 439 break; 440 } 441 442 lwkt_reltoken(&mp->mnt_token); 443 return (res); 444 } 445 446 static int 447 autofs_print(struct vop_print_args *ap) 448 { 449 struct autofs_node *anp = VTOI(ap->a_vp); 450 451 kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n", 452 anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached, 453 anp->an_retries, anp->an_wildcards); 454 455 return (0); 456 } 457 458 struct vop_ops autofs_vnode_vops = { 459 .vop_default = vop_defaultop, 460 .vop_access = autofs_access, 461 .vop_getattr = autofs_getattr, 462 .vop_nresolve = autofs_nresolve, 463 .vop_nmkdir = autofs_nmkdir, 464 .vop_readdir = autofs_readdir, 465 .vop_reclaim = autofs_reclaim, 466 .vop_mountctl = autofs_mountctl, 467 .vop_print = autofs_print, 468 }; 469 470 int 471 autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, 472 const char *name, int namelen, struct autofs_node **anpp) 473 { 474 struct autofs_node *anp; 475 476 KKASSERT(mtx_islocked_ex(&->am_lock)); 477 478 if (parent != NULL) { 479 KKASSERT(mtx_islocked_ex(&parent->an_mount->am_lock)); 480 KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT, 481 ("node \"%s\" already exists", name)); 482 } 483 484 /* 485 * All struct fields must be initialized. 486 */ 487 anp = objcache_get(autofs_node_objcache, M_WAITOK); 488 if (namelen >= 0) 489 anp->an_name = kstrndup(name, namelen, M_AUTOFS); 490 else 491 anp->an_name = kstrdup(name, M_AUTOFS); 492 anp->an_ino = amp->am_last_ino++; 493 callout_init(&anp->an_callout); 494 mtx_init(&anp->an_vnode_lock, "autofsvnlk"); 495 getnanotime(&anp->an_ctime); 496 anp->an_parent = parent; 497 anp->an_mount = amp; 498 anp->an_vnode = NULL; 499 anp->an_cached = false; 500 anp->an_wildcards = false; 501 anp->an_retries = 0; 502 if (parent != NULL) 503 RB_INSERT(autofs_node_tree, &parent->an_children, anp); 504 RB_INIT(&anp->an_children); 505 506 *anpp = anp; 507 508 return (0); 509 } 510 511 int 512 autofs_node_find(struct autofs_node *parent, const char *name, int namelen, 513 struct autofs_node **anpp) 514 { 515 struct autofs_node *anp, find; 516 int error; 517 518 KKASSERT(mtx_islocked(&parent->an_mount->am_lock)); 519 520 if (namelen >= 0) 521 find.an_name = kstrndup(name, namelen, M_AUTOFS); 522 else 523 find.an_name = kstrdup(name, M_AUTOFS); 524 525 anp = RB_FIND(autofs_node_tree, &parent->an_children, &find); 526 if (anp != NULL) { 527 error = 0; 528 if (anpp != NULL) 529 *anpp = anp; 530 } else { 531 error = ENOENT; 532 } 533 534 kfree(find.an_name, M_AUTOFS); 535 536 return (error); 537 } 538 539 void 540 autofs_node_delete(struct autofs_node *anp) 541 { 542 KKASSERT(mtx_islocked_ex(&anp->an_mount->am_lock)); 543 KASSERT(RB_EMPTY(&anp->an_children), ("have children")); 544 545 callout_drain(&anp->an_callout); 546 547 if (anp->an_parent != NULL) 548 RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp); 549 550 mtx_uninit(&anp->an_vnode_lock); 551 kfree(anp->an_name, M_AUTOFS); 552 objcache_put(autofs_node_objcache, anp); 553 } 554 555 int 556 autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags, 557 struct vnode **vpp) 558 { 559 struct vnode *vp = NULL; 560 int error; 561 retry: 562 KKASSERT(mtx_notlocked(&anp->an_mount->am_lock)); 563 mtx_lock_ex_quick(&anp->an_vnode_lock); 564 565 vp = anp->an_vnode; 566 if (vp != NULL) { 567 vhold(vp); 568 mtx_unlock_ex(&anp->an_vnode_lock); 569 570 error = vget(vp, flags | LK_RETRY); 571 if (error) { 572 AUTOFS_WARN("vget failed with error %d", error); 573 vdrop(vp); 574 goto retry; 575 } 576 vdrop(vp); 577 *vpp = vp; 578 return (0); 579 } 580 581 mtx_unlock_ex(&anp->an_vnode_lock); 582 583 error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE); 584 if (error) 585 return (error); 586 vp->v_type = VDIR; 587 vp->v_data = anp; 588 589 KASSERT(anp->an_vnode == NULL, ("lost race")); 590 anp->an_vnode = vp; 591 vx_downgrade(vp); /* downgrade VX lock to VN lock */ 592 *vpp = vp; 593 594 return (0); 595 } 596