1/*- 2 * Copyright (c) 2017 The NetBSD Foundation, Inc. 3 * Copyright (c) 2016 The DragonFly Project 4 * Copyright (c) 2014 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>. 9 * 10 * This software was developed by Edward Tomasz Napierala under sponsorship 11 * from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35#include <sys/cdefs.h> 36__KERNEL_RCSID(0, "$NetBSD: autofs_vfsops.c,v 1.12 2022/03/28 12:33:22 riastradh Exp $"); 37 38 39#include "autofs.h" 40#include "autofs_mount.h" 41 42#include <sys/stat.h> 43#include <sys/sysctl.h> 44#include <miscfs/genfs/genfs.h> 45 46MODULE(MODULE_CLASS_VFS, autofs, NULL); 47 48static int autofs_statvfs(struct mount *, struct statvfs *); 49 50static void 51autofs_init(void) 52{ 53 54 KASSERT(!autofs_softc); 55 56 autofs_softc = kmem_zalloc(sizeof(*autofs_softc), KM_SLEEP); 57 58 pool_init(&autofs_request_pool, sizeof(struct autofs_request), 0, 0, 0, 59 "autofs_request", &pool_allocator_nointr, IPL_NONE); 60 pool_init(&autofs_node_pool, sizeof(struct autofs_node), 0, 0, 0, 61 "autofs_node", &pool_allocator_nointr, IPL_NONE); 62 63 TAILQ_INIT(&autofs_softc->sc_requests); 64 cv_init(&autofs_softc->sc_cv, "autofscv"); 65 mutex_init(&autofs_softc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 66 autofs_softc->sc_dev_opened = false; 67 68 workqueue_create(&autofs_tmo_wq, "autofstmo", 69 autofs_timeout_wq, NULL, 0, 0, WQ_MPSAFE); 70} 71 72static void 73autofs_done(void) 74{ 75 76 KASSERT(autofs_softc); 77 KASSERT(!autofs_softc->sc_dev_opened); 78 79 workqueue_destroy(autofs_tmo_wq); 80 81 struct autofs_softc *sc = autofs_softc; 82 autofs_softc = NULL; 83 84 cv_destroy(&sc->sc_cv); 85 mutex_destroy(&sc->sc_lock); 86 87 pool_destroy(&autofs_request_pool); 88 pool_destroy(&autofs_node_pool); 89 90 kmem_free(sc, sizeof(*sc)); 91} 92 93static int 94autofs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 95{ 96 struct autofs_args *args = data; 97 struct autofs_mount *amp = VFSTOAUTOFS(mp); 98 struct statvfs *sbp = &mp->mnt_stat; 99 int error; 100 101 if (mp->mnt_flag & MNT_UPDATE) { 102 if (amp == NULL) 103 return EIO; 104 autofs_flush(amp); 105 return 0; 106 } 107 108 if (!args) 109 return EINVAL; 110 111 if (mp->mnt_flag & MNT_GETARGS) { 112 if (amp == NULL) 113 return EIO; 114 error = copyoutstr(amp->am_from, args->from, 115 sizeof(amp->am_from), NULL); 116 if (error) 117 return error; 118 error = copyoutstr(amp->am_options, args->master_options, 119 sizeof(amp->am_options), NULL); 120 if (error) 121 return error; 122 error = copyoutstr(amp->am_prefix, args->master_prefix, 123 sizeof(amp->am_prefix), NULL); 124 return error; 125 } 126 127 if (amp != NULL) 128 return EBUSY; 129 130 /* 131 * Allocate the autofs mount. 132 */ 133 amp = kmem_zalloc(sizeof(*amp), KM_SLEEP); 134 mp->mnt_data = amp; 135 amp->am_mp = mp; 136 137 /* 138 * Copy-in master_options string. 139 */ 140 error = copyinstr(args->master_options, amp->am_options, 141 sizeof(amp->am_options), NULL); 142 if (error) 143 goto fail; 144 145 /* 146 * Copy-in master_prefix string. 147 */ 148 error = copyinstr(args->master_prefix, amp->am_prefix, 149 sizeof(amp->am_prefix), NULL); 150 if (error) 151 goto fail; 152 153 /* 154 * Initialize the autofs mount. 155 */ 156 mutex_init(&->am_lock, MUTEX_DEFAULT, IPL_NONE); 157 amp->am_last_ino = AUTOFS_ROOTINO; 158 159 mutex_enter(&->am_lock); 160 error = autofs_node_new(NULL, amp, ".", -1, &->am_root); 161 mutex_exit(&->am_lock); 162 if (error) 163 goto fail1; 164 KASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO); 165 166 autofs_statvfs(mp, sbp); 167 vfs_getnewfsid(mp); 168 169 error = set_statvfs_info(path, UIO_USERSPACE, args->from, UIO_USERSPACE, 170 mp->mnt_op->vfs_name, mp, curlwp); 171 if (error) 172 goto fail1; 173 strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from)); 174 strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on)); 175 176 return 0; 177 178fail1: 179 mutex_destroy(&->am_lock); 180fail: 181 mp->mnt_data = NULL; 182 kmem_free(amp, sizeof(*amp)); 183 return error; 184} 185 186static int 187autofs_unmount(struct mount *mp, int mntflags) 188{ 189 struct autofs_mount *amp = VFSTOAUTOFS(mp); 190 int error, flags; 191 192 flags = 0; 193 if (mntflags & MNT_FORCE) 194 flags |= FORCECLOSE; 195 error = vflush(mp, NULL, flags); 196 if (error) { 197 AUTOFS_DEBUG("vflush failed with error %d", error); 198 return error; 199 } 200 201 /* 202 * All vnodes are gone, and new one will not appear - so, 203 * no new triggerings. 204 */ 205 for (;;) { 206 struct autofs_request *ar; 207 int dummy; 208 bool found; 209 210 found = false; 211 mutex_enter(&autofs_softc->sc_lock); 212 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 213 if (ar->ar_mount != amp) 214 continue; 215 ar->ar_error = ENXIO; 216 ar->ar_done = true; 217 ar->ar_in_progress = false; 218 found = true; 219 } 220 if (found == false) { 221 mutex_exit(&autofs_softc->sc_lock); 222 break; 223 } 224 225 cv_broadcast(&autofs_softc->sc_cv); 226 mutex_exit(&autofs_softc->sc_lock); 227 228 tsleep(&dummy, 0, "autofs_umount", hz); 229 } 230 231 mutex_enter(&->am_lock); 232 while (!RB_EMPTY(&->am_root->an_children)) { 233 struct autofs_node *anp; 234 /* 235 * Force delete all nodes when more than one level of 236 * directories are created via indirect map. Autofs doesn't 237 * support rmdir(2), thus this is the only way to get out. 238 */ 239 anp = RB_MIN(autofs_node_tree, &->am_root->an_children); 240 while (!RB_EMPTY(&anp->an_children)) 241 anp = RB_MIN(autofs_node_tree, &anp->an_children); 242 autofs_node_delete(anp); 243 } 244 autofs_node_delete(amp->am_root); 245 mp->mnt_data = NULL; 246 mutex_exit(&->am_lock); 247 248 mutex_destroy(&->am_lock); 249 250 kmem_free(amp, sizeof(*amp)); 251 252 return 0; 253} 254 255static int 256autofs_start(struct mount *mp, int flags) 257{ 258 259 return 0; 260} 261 262static int 263autofs_root(struct mount *mp, int lktype, struct vnode **vpp) 264{ 265 struct autofs_node *anp = VFSTOAUTOFS(mp)->am_root; 266 int error; 267 268 error = vcache_get(mp, &anp, sizeof(anp), vpp); 269 if (error) 270 return error; 271 error = vn_lock(*vpp, lktype); 272 if (error) { 273 vrele(*vpp); 274 *vpp = NULLVP; 275 return error; 276 } 277 278 return 0; 279} 280 281static int 282autofs_statvfs(struct mount *mp, struct statvfs *sbp) 283{ 284 285 sbp->f_bsize = S_BLKSIZE; 286 sbp->f_frsize = S_BLKSIZE; 287 sbp->f_iosize = 0; 288 sbp->f_blocks = 0; 289 sbp->f_bfree = 0; 290 sbp->f_bavail = 0; 291 sbp->f_bresvd = 0; 292 sbp->f_files = 0; 293 sbp->f_ffree = 0; 294 sbp->f_favail = 0; 295 sbp->f_fresvd = 0; 296 297 copy_statvfs_info(sbp, mp); 298 299 return 0; 300} 301 302static int 303autofs_sync(struct mount *mp, int waitfor, kauth_cred_t uc) 304{ 305 306 return 0; 307} 308 309static int 310autofs_loadvnode(struct mount *mp, struct vnode *vp, 311 const void *key, size_t key_len, const void **new_key) 312{ 313 struct autofs_node *anp; 314 315 KASSERT(key_len == sizeof(anp)); 316 memcpy(&anp, key, key_len); 317 KASSERT(!anp->an_vnode); 318 319 vp->v_tag = VT_AUTOFS; 320 vp->v_type = VDIR; 321 vp->v_op = autofs_vnodeop_p; 322 vp->v_data = anp; 323 324 if (anp->an_ino == AUTOFS_ROOTINO) 325 vp->v_vflag |= VV_ROOT; 326 327 anp->an_vnode = vp; 328 uvm_vnp_setsize(vp, 0); 329 330 *new_key = &vp->v_data; 331 332 return 0; 333} 334 335static const struct vnodeopv_desc * const autofs_vnodeopv_descs[] = { 336 &autofs_vnodeop_opv_desc, 337 NULL, 338}; 339 340static struct vfsops autofs_vfsops = { 341 .vfs_name = MOUNT_AUTOFS, 342 .vfs_min_mount_data = sizeof(struct autofs_args), 343 .vfs_mount = autofs_mount, 344 .vfs_start = autofs_start, 345 .vfs_unmount = autofs_unmount, 346 .vfs_root = autofs_root, 347 .vfs_quotactl = (void *)eopnotsupp, 348 .vfs_statvfs = autofs_statvfs, 349 .vfs_sync = autofs_sync, 350 .vfs_vget = (void *)eopnotsupp, 351 .vfs_loadvnode = (void *)autofs_loadvnode, 352 .vfs_newvnode = (void *)eopnotsupp, 353 .vfs_fhtovp = (void *)eopnotsupp, 354 .vfs_vptofh = (void *)eopnotsupp, 355 .vfs_init = autofs_init, 356 .vfs_reinit = (void *)eopnotsupp, 357 .vfs_done = autofs_done, 358 .vfs_mountroot = (void *)eopnotsupp, 359 .vfs_snapshot = (void *)eopnotsupp, 360 .vfs_extattrctl = (void *)eopnotsupp, 361 .vfs_suspendctl = (void *)genfs_suspendctl, 362 .vfs_renamelock_enter = (void *)eopnotsupp, 363 .vfs_renamelock_exit = (void *)eopnotsupp, 364 .vfs_fsync = (void *)eopnotsupp, 365 .vfs_opv_descs = autofs_vnodeopv_descs 366}; 367 368#define AUTOFS_SYSCTL_DEBUG 1 369#define AUTOFS_SYSCTL_MOUNT_ON_STAT 2 370#define AUTOFS_SYSCTL_TIMEOUT 3 371#define AUTOFS_SYSCTL_CACHE 4 372#define AUTOFS_SYSCTL_RETRY_ATTEMPTS 5 373#define AUTOFS_SYSCTL_RETRY_DELAY 6 374#define AUTOFS_SYSCTL_INTERRUPTIBLE 7 375 376SYSCTL_SETUP(autofs_sysctl_create, "autofs sysctl") 377{ 378 int error; 379 380 /* 381 * XXX the "33" below could be dynamic, thereby eliminating one 382 * more instance of the "number to vfs" mapping problem, but 383 * "33" is the order as taken from sys/mount.h 384 */ 385 error = sysctl_createv(clog, 0, NULL, NULL, 386 CTLFLAG_PERMANENT, 387 CTLTYPE_NODE, "autofs", 388 SYSCTL_DESCR("Automounter filesystem"), 389 NULL, 0, NULL, 0, 390 CTL_VFS, 33, CTL_EOL); 391 if (error) 392 goto fail; 393 394 error = sysctl_createv(clog, 0, NULL, NULL, 395 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 396 CTLTYPE_INT, "autofs_debug", 397 SYSCTL_DESCR("Enable debug messages"), 398 NULL, 0, &autofs_debug, 0, 399 CTL_VFS, 33, AUTOFS_SYSCTL_DEBUG, CTL_EOL); 400 if (error) 401 goto fail; 402 403 error = sysctl_createv(clog, 0, NULL, NULL, 404 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 405 CTLTYPE_INT, "autofs_mount_on_stat", 406 SYSCTL_DESCR("Trigger mount on stat(2) on mountpoint"), 407 NULL, 0, &autofs_mount_on_stat, 0, 408 CTL_VFS, 33, AUTOFS_SYSCTL_MOUNT_ON_STAT, CTL_EOL); 409 if (error) 410 goto fail; 411 412 error = sysctl_createv(clog, 0, NULL, NULL, 413 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 414 CTLTYPE_INT, "autofs_timeout", 415 SYSCTL_DESCR("Number of seconds to wait for automountd(8)"), 416 NULL, 0, &autofs_timeout, 0, 417 CTL_VFS, 33, AUTOFS_SYSCTL_TIMEOUT, CTL_EOL); 418 if (error) 419 goto fail; 420 421 error = sysctl_createv(clog, 0, NULL, NULL, 422 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 423 CTLTYPE_INT, "autofs_cache", 424 SYSCTL_DESCR("Number of seconds to wait before reinvoking"), 425 NULL, 0, &autofs_cache, 0, 426 CTL_VFS, 33, AUTOFS_SYSCTL_CACHE, CTL_EOL); 427 if (error) 428 goto fail; 429 430 error = sysctl_createv(clog, 0, NULL, NULL, 431 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 432 CTLTYPE_INT, "autofs_retry_attempts", 433 SYSCTL_DESCR("Number of attempts before failing mount"), 434 NULL, 0, &autofs_retry_attempts, 0, 435 CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_ATTEMPTS, CTL_EOL); 436 if (error) 437 goto fail; 438 439 error = sysctl_createv(clog, 0, NULL, NULL, 440 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 441 CTLTYPE_INT, "autofs_retry_delay", 442 SYSCTL_DESCR("Number of seconds before retrying"), 443 NULL, 0, &autofs_retry_delay, 0, 444 CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_DELAY, CTL_EOL); 445 if (error) 446 goto fail; 447 448 error = sysctl_createv(clog, 0, NULL, NULL, 449 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 450 CTLTYPE_INT, "autofs_interruptible", 451 SYSCTL_DESCR("Allow requests to be interrupted by signal"), 452 NULL, 0, &autofs_interruptible, 0, 453 CTL_VFS, 33, AUTOFS_SYSCTL_INTERRUPTIBLE, CTL_EOL); 454 if (error) 455 goto fail; 456 457 return; 458fail: 459 AUTOFS_WARN("sysctl_createv failed with error %d", error); 460 461 return; 462} 463 464extern const struct cdevsw autofs_cdevsw; 465 466static int 467autofs_modcmd(modcmd_t cmd, void *arg) 468{ 469#ifdef _MODULE 470 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 471#endif 472 int error = 0; 473 474 switch (cmd) { 475 case MODULE_CMD_INIT: 476 error = vfs_attach(&autofs_vfsops); 477 if (error) 478 break; 479#ifdef _MODULE 480 error = devsw_attach("autofs", NULL, &bmajor, &autofs_cdevsw, 481 &cmajor); 482 if (error) { 483 vfs_detach(&autofs_vfsops); 484 break; 485 } 486#endif 487 break; 488 case MODULE_CMD_FINI: 489#ifdef _MODULE 490 KASSERT(autofs_softc); 491 mutex_enter(&autofs_softc->sc_lock); 492 if (autofs_softc->sc_dev_opened) { 493 mutex_exit(&autofs_softc->sc_lock); 494 error = EBUSY; 495 break; 496 } 497 mutex_exit(&autofs_softc->sc_lock); 498 499 devsw_detach(NULL, &autofs_cdevsw); 500#endif 501 error = vfs_detach(&autofs_vfsops); 502 if (error) 503 break; 504 break; 505 default: 506 error = ENOTTY; 507 break; 508 } 509 510 return error; 511} 512