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.4 2018/01/14 22:43:18 christos 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 46 MODULE(MODULE_CLASS_VFS, autofs, NULL); 47 48 static int autofs_statvfs(struct mount *, struct statvfs *); 49 static int autofs_sysctl_create(void); 50 51 static void 52 autofs_init(void) 53 { 54 55 KASSERT(!autofs_softc); 56 57 autofs_softc = kmem_zalloc(sizeof(*autofs_softc), KM_SLEEP); 58 59 pool_init(&autofs_request_pool, sizeof(struct autofs_request), 0, 0, 0, 60 "autofs_request", &pool_allocator_nointr, IPL_NONE); 61 pool_init(&autofs_node_pool, sizeof(struct autofs_node), 0, 0, 0, 62 "autofs_node", &pool_allocator_nointr, IPL_NONE); 63 64 TAILQ_INIT(&autofs_softc->sc_requests); 65 cv_init(&autofs_softc->sc_cv, "autofscv"); 66 mutex_init(&autofs_softc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 67 autofs_softc->sc_dev_opened = false; 68 69 autofs_sysctl_create(); 70 workqueue_create(&autofs_tmo_wq, "autofstmo", 71 autofs_timeout_wq, NULL, 0, 0, WQ_MPSAFE); 72 } 73 74 static void 75 autofs_done(void) 76 { 77 KASSERT(autofs_softc); 78 KASSERT(!autofs_softc->sc_dev_opened); 79 80 workqueue_destroy(autofs_tmo_wq); 81 82 struct autofs_softc *sc = autofs_softc; 83 autofs_softc = NULL; 84 85 cv_destroy(&sc->sc_cv); 86 mutex_destroy(&sc->sc_lock); 87 88 pool_destroy(&autofs_request_pool); 89 pool_destroy(&autofs_node_pool); 90 91 kmem_free(sc, sizeof(*sc)); 92 } 93 94 static int 95 autofs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 96 { 97 struct autofs_args *args = data; 98 struct autofs_mount *amp = VFSTOAUTOFS(mp); 99 struct statvfs *sbp = &mp->mnt_stat; 100 int error; 101 102 if (mp->mnt_flag & MNT_UPDATE) { 103 if (amp == NULL) 104 return EIO; 105 autofs_flush(amp); 106 return 0; 107 } 108 109 if (!args) 110 return EINVAL; 111 112 if (mp->mnt_flag & MNT_GETARGS) { 113 if (amp == NULL) 114 return EIO; 115 error = copyoutstr(amp->am_from, args->from, 116 sizeof(amp->am_from), NULL); 117 if (error) 118 return error; 119 error = copyoutstr(amp->am_options, args->master_options, 120 sizeof(amp->am_options), NULL); 121 if (error) 122 return error; 123 error = copyoutstr(amp->am_prefix, args->master_prefix, 124 sizeof(amp->am_prefix), NULL); 125 return error; 126 } 127 128 if (amp != NULL) 129 return EBUSY; 130 131 /* 132 * Allocate the autofs mount. 133 */ 134 amp = kmem_zalloc(sizeof(*amp), KM_SLEEP); 135 mp->mnt_data = amp; 136 amp->am_mp = mp; 137 138 /* 139 * Copy-in master_options string. 140 */ 141 error = copyinstr(args->master_options, amp->am_options, 142 sizeof(amp->am_options), NULL); 143 if (error) 144 goto fail; 145 146 /* 147 * Copy-in master_prefix string. 148 */ 149 error = copyinstr(args->master_prefix, amp->am_prefix, 150 sizeof(amp->am_prefix), NULL); 151 if (error) 152 goto fail; 153 154 /* 155 * Initialize the autofs mount. 156 */ 157 mutex_init(&->am_lock, MUTEX_DEFAULT, IPL_NONE); 158 amp->am_last_ino = AUTOFS_ROOTINO; 159 160 mutex_enter(&->am_lock); 161 error = autofs_node_new(NULL, amp, ".", -1, &->am_root); 162 mutex_exit(&->am_lock); 163 if (error) 164 goto fail1; 165 KASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO); 166 167 autofs_statvfs(mp, sbp); 168 vfs_getnewfsid(mp); 169 170 error = set_statvfs_info(path, UIO_USERSPACE, args->from, UIO_USERSPACE, 171 mp->mnt_op->vfs_name, mp, curlwp); 172 if (error) 173 goto fail1; 174 strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from)); 175 strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on)); 176 177 return 0; 178 179 fail1: 180 mutex_destroy(&->am_lock); 181 fail: 182 mp->mnt_data = NULL; 183 kmem_free(amp, sizeof(*amp)); 184 return error; 185 } 186 187 static int 188 autofs_unmount(struct mount *mp, int mntflags) 189 { 190 struct autofs_mount *amp = VFSTOAUTOFS(mp); 191 int error, flags; 192 193 flags = 0; 194 if (mntflags & MNT_FORCE) 195 flags |= FORCECLOSE; 196 error = vflush(mp, NULL, flags); 197 if (error) { 198 AUTOFS_WARN("vflush failed with error %d", error); 199 return error; 200 } 201 202 /* 203 * All vnodes are gone, and new one will not appear - so, 204 * no new triggerings. 205 */ 206 for (;;) { 207 struct autofs_request *ar; 208 int dummy; 209 bool found; 210 211 found = false; 212 mutex_enter(&autofs_softc->sc_lock); 213 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 214 if (ar->ar_mount != amp) 215 continue; 216 ar->ar_error = ENXIO; 217 ar->ar_done = true; 218 ar->ar_in_progress = false; 219 found = true; 220 } 221 if (found == false) { 222 mutex_exit(&autofs_softc->sc_lock); 223 break; 224 } 225 226 cv_broadcast(&autofs_softc->sc_cv); 227 mutex_exit(&autofs_softc->sc_lock); 228 229 tsleep(&dummy, 0, "autofs_umount", hz); 230 } 231 232 mutex_enter(&->am_lock); 233 while (!RB_EMPTY(&->am_root->an_children)) { 234 struct autofs_node *anp; 235 anp = RB_MIN(autofs_node_tree, &->am_root->an_children); 236 if (!RB_EMPTY(&anp->an_children)) { 237 AUTOFS_DEBUG("%s: %s has children", __func__, 238 anp->an_name); 239 mutex_exit(&->am_lock); 240 return EBUSY; 241 } 242 243 autofs_node_delete(anp); 244 } 245 autofs_node_delete(amp->am_root); 246 mp->mnt_data = NULL; 247 mutex_exit(&->am_lock); 248 249 mutex_destroy(&->am_lock); 250 251 kmem_free(amp, sizeof(*amp)); 252 253 return 0; 254 } 255 256 static int 257 autofs_start(struct mount *mp, int flags) 258 { 259 260 return 0; 261 } 262 263 static int 264 autofs_root(struct mount *mp, struct vnode **vpp) 265 { 266 struct autofs_node *anp = VFSTOAUTOFS(mp)->am_root; 267 int error; 268 269 error = vcache_get(mp, &anp, sizeof(anp), vpp); 270 if (error) 271 return error; 272 error = vn_lock(*vpp, LK_EXCLUSIVE); 273 if (error) { 274 vrele(*vpp); 275 *vpp = NULL; 276 return error; 277 } 278 279 return 0; 280 } 281 282 static int 283 autofs_statvfs(struct mount *mp, struct statvfs *sbp) 284 { 285 286 sbp->f_bsize = S_BLKSIZE; 287 sbp->f_frsize = S_BLKSIZE; 288 sbp->f_iosize = 0; 289 sbp->f_blocks = 0; 290 sbp->f_bfree = 0; 291 sbp->f_bavail = 0; 292 sbp->f_bresvd = 0; 293 sbp->f_files = 0; 294 sbp->f_ffree = 0; 295 sbp->f_favail = 0; 296 sbp->f_fresvd = 0; 297 298 copy_statvfs_info(sbp, mp); 299 300 return 0; 301 } 302 303 static int 304 autofs_sync(struct mount *mp, int waitfor, kauth_cred_t uc) 305 { 306 307 return 0; 308 } 309 310 static int 311 autofs_loadvnode(struct mount *mp, struct vnode *vp, 312 const void *key, size_t key_len, const void **new_key) 313 { 314 struct autofs_node *anp; 315 316 KASSERT(key_len == sizeof(anp)); 317 memcpy(&anp, key, key_len); 318 KASSERT(!anp->an_vnode); 319 320 vp->v_tag = VT_AUTOFS; 321 vp->v_type = VDIR; 322 vp->v_op = autofs_vnodeop_p; 323 vp->v_data = anp; 324 325 if (anp->an_ino == AUTOFS_ROOTINO) 326 vp->v_vflag |= VV_ROOT; 327 328 anp->an_vnode = vp; 329 uvm_vnp_setsize(vp, 0); 330 331 *new_key = &vp->v_data; 332 333 return 0; 334 } 335 336 static const struct vnodeopv_desc * const autofs_vnodeopv_descs[] = { 337 &autofs_vnodeop_opv_desc, 338 NULL, 339 }; 340 341 static struct vfsops autofs_vfsops = { 342 .vfs_name = MOUNT_AUTOFS, 343 .vfs_min_mount_data = sizeof(struct autofs_args), 344 .vfs_mount = autofs_mount, 345 .vfs_start = autofs_start, 346 .vfs_unmount = autofs_unmount, 347 .vfs_root = autofs_root, 348 .vfs_quotactl = (void *)eopnotsupp, 349 .vfs_statvfs = autofs_statvfs, 350 .vfs_sync = autofs_sync, 351 .vfs_vget = (void *)eopnotsupp, 352 .vfs_loadvnode = (void *)autofs_loadvnode, 353 .vfs_newvnode = (void *)eopnotsupp, 354 .vfs_fhtovp = (void *)eopnotsupp, 355 .vfs_vptofh = (void *)eopnotsupp, 356 .vfs_init = autofs_init, 357 .vfs_reinit = (void *)eopnotsupp, 358 .vfs_done = autofs_done, 359 .vfs_mountroot = (void *)eopnotsupp, 360 .vfs_snapshot = (void *)eopnotsupp, 361 .vfs_extattrctl = (void *)eopnotsupp, 362 .vfs_suspendctl = (void *)genfs_suspendctl, 363 .vfs_renamelock_enter = (void *)eopnotsupp, 364 .vfs_renamelock_exit = (void *)eopnotsupp, 365 .vfs_fsync = (void *)eopnotsupp, 366 .vfs_opv_descs = autofs_vnodeopv_descs 367 }; 368 369 #define AUTOFS_SYSCTL_DEBUG 1 370 #define AUTOFS_SYSCTL_MOUNT_ON_STAT 2 371 #define AUTOFS_SYSCTL_TIMEOUT 3 372 #define AUTOFS_SYSCTL_CACHE 4 373 #define AUTOFS_SYSCTL_RETRY_ATTEMPTS 5 374 #define AUTOFS_SYSCTL_RETRY_DELAY 6 375 #define AUTOFS_SYSCTL_INTERRUPTIBLE 7 376 377 static struct sysctllog *autofs_sysctl_log; 378 379 static int 380 autofs_sysctl_create(void) 381 { 382 int error; 383 384 /* 385 * XXX the "33" below could be dynamic, thereby eliminating one 386 * more instance of the "number to vfs" mapping problem, but 387 * "33" is the order as taken from sys/mount.h 388 */ 389 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 390 CTLFLAG_PERMANENT, 391 CTLTYPE_NODE, "autofs", 392 SYSCTL_DESCR("Automounter filesystem"), 393 NULL, 0, NULL, 0, 394 CTL_VFS, 33, CTL_EOL); 395 if (error) 396 goto fail; 397 398 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 399 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 400 CTLTYPE_INT, "autofs_debug", 401 SYSCTL_DESCR("Enable debug messages"), 402 NULL, 0, &autofs_debug, 0, 403 CTL_VFS, 33, AUTOFS_SYSCTL_DEBUG, CTL_EOL); 404 if (error) 405 goto fail; 406 407 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 408 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 409 CTLTYPE_INT, "autofs_mount_on_stat", 410 SYSCTL_DESCR("Trigger mount on stat(2) on mountpoint"), 411 NULL, 0, &autofs_mount_on_stat, 0, 412 CTL_VFS, 33, AUTOFS_SYSCTL_MOUNT_ON_STAT, CTL_EOL); 413 if (error) 414 goto fail; 415 416 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 417 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 418 CTLTYPE_INT, "autofs_timeout", 419 SYSCTL_DESCR("Number of seconds to wait for automountd(8)"), 420 NULL, 0, &autofs_timeout, 0, 421 CTL_VFS, 33, AUTOFS_SYSCTL_TIMEOUT, CTL_EOL); 422 if (error) 423 goto fail; 424 425 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 426 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 427 CTLTYPE_INT, "autofs_cache", 428 SYSCTL_DESCR("Number of seconds to wait before reinvoking"), 429 NULL, 0, &autofs_cache, 0, 430 CTL_VFS, 33, AUTOFS_SYSCTL_CACHE, CTL_EOL); 431 if (error) 432 goto fail; 433 434 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 435 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 436 CTLTYPE_INT, "autofs_retry_attempts", 437 SYSCTL_DESCR("Number of attempts before failing mount"), 438 NULL, 0, &autofs_retry_attempts, 0, 439 CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_ATTEMPTS, CTL_EOL); 440 if (error) 441 goto fail; 442 443 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 444 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 445 CTLTYPE_INT, "autofs_retry_delay", 446 SYSCTL_DESCR("Number of seconds before retrying"), 447 NULL, 0, &autofs_retry_delay, 0, 448 CTL_VFS, 33, AUTOFS_SYSCTL_RETRY_DELAY, CTL_EOL); 449 if (error) 450 goto fail; 451 452 error = sysctl_createv(&autofs_sysctl_log, 0, NULL, NULL, 453 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 454 CTLTYPE_INT, "autofs_interruptible", 455 SYSCTL_DESCR("Allow requests to be interrupted by signal"), 456 NULL, 0, &autofs_interruptible, 0, 457 CTL_VFS, 33, AUTOFS_SYSCTL_INTERRUPTIBLE, CTL_EOL); 458 if (error) 459 goto fail; 460 461 return 0; 462 fail: 463 AUTOFS_WARN("sysctl_createv failed with error %d", error); 464 465 return error; 466 } 467 468 extern const struct cdevsw autofs_cdevsw; 469 470 static int 471 autofs_modcmd(modcmd_t cmd, void *arg) 472 { 473 #ifdef _MODULE 474 devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 475 #endif 476 int error = 0; 477 478 switch (cmd) { 479 case MODULE_CMD_INIT: 480 error = vfs_attach(&autofs_vfsops); 481 if (error) 482 break; 483 #ifdef _MODULE 484 error = devsw_attach("autofs", NULL, &bmajor, &autofs_cdevsw, 485 &cmajor); 486 if (error) { 487 vfs_detach(&autofs_vfsops); 488 break; 489 } 490 #endif 491 break; 492 case MODULE_CMD_FINI: 493 #ifdef _MODULE 494 KASSERT(autofs_softc); 495 mutex_enter(&autofs_softc->sc_lock); 496 if (autofs_softc->sc_dev_opened) { 497 mutex_exit(&autofs_softc->sc_lock); 498 error = EBUSY; 499 break; 500 } 501 mutex_exit(&autofs_softc->sc_lock); 502 503 error = devsw_detach(NULL, &autofs_cdevsw); 504 if (error) 505 break; 506 #endif 507 error = vfs_detach(&autofs_vfsops); 508 if (error) 509 break; 510 break; 511 default: 512 error = ENOTTY; 513 break; 514 } 515 516 return error; 517 } 518