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