2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2016 Tomohiro Kusumi <tkusumi@netbsd.org>
5 * Copyright (c) 2016 The DragonFly Project
6 * Copyright (c) 2014 The FreeBSD Foundation
9 * This software was developed by Edward Tomasz Napierala under sponsorship
10 * from the FreeBSD Foundation.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/kernel.h>
36 #include <sys/module.h>
40 #include "autofs_mount.h"
42 static int autofs_statfs(struct mount
*mp
, struct statfs
*sbp
,
45 static struct objcache_malloc_args autofs_request_args
= {
46 sizeof(struct autofs_request
), M_AUTOFS
,
48 static struct objcache_malloc_args autofs_node_args
= {
49 sizeof(struct autofs_node
), M_AUTOFS
,
53 autofs_init(struct vfsconf
*vfsp
)
55 KASSERT(autofs_softc
== NULL
,
56 ("softc %p, should be NULL", autofs_softc
));
58 autofs_softc
= kmalloc(sizeof(*autofs_softc
), M_AUTOFS
,
61 autofs_request_objcache
= objcache_create("autofs_request", 0, 0,
63 objcache_malloc_alloc_zero
, objcache_malloc_free
,
64 &autofs_request_args
);
66 autofs_node_objcache
= objcache_create("autofs_node", 0, 0,
68 objcache_malloc_alloc_zero
, objcache_malloc_free
,
71 TAILQ_INIT(&autofs_softc
->sc_requests
);
72 cv_init(&autofs_softc
->sc_cv
, "autofscv");
73 mtx_init(&autofs_softc
->sc_lock
, "autofssclk");
74 autofs_softc
->sc_dev_opened
= false;
76 autofs_softc
->sc_cdev
= make_dev(&autofs_ops
, 0, UID_ROOT
, GID_OPERATOR
,
78 if (autofs_softc
->sc_cdev
== NULL
) {
79 AUTOFS_WARN("failed to create device node");
80 objcache_destroy(autofs_request_objcache
);
81 objcache_destroy(autofs_node_objcache
);
82 kfree(autofs_softc
, M_AUTOFS
);
85 autofs_softc
->sc_cdev
->si_drv1
= autofs_softc
;
91 autofs_uninit(struct vfsconf
*vfsp
)
93 mtx_lock_ex_quick(&autofs_softc
->sc_lock
);
94 if (autofs_softc
->sc_dev_opened
) {
95 mtx_unlock_ex(&autofs_softc
->sc_lock
);
99 if (autofs_softc
->sc_cdev
!= NULL
)
100 destroy_dev(autofs_softc
->sc_cdev
);
102 objcache_destroy(autofs_request_objcache
);
103 objcache_destroy(autofs_node_objcache
);
105 mtx_unlock_ex(&autofs_softc
->sc_lock
);
107 kfree(autofs_softc
, M_AUTOFS
); /* race with open */
114 autofs_mount(struct mount
*mp
, char *mntpt
, caddr_t data
, struct ucred
*cred
)
116 struct autofs_mount_info info
;
117 struct autofs_mount
*amp
;
118 struct statfs
*sbp
= &mp
->mnt_stat
;
121 if (mp
->mnt_flag
& MNT_UPDATE
) {
122 autofs_flush(VFSTOAUTOFS(mp
));
126 error
= copyin(data
, &info
, sizeof(info
));
131 * Copy-in ->f_mntfromname string.
133 memset(sbp
->f_mntfromname
, 0, sizeof(sbp
->f_mntfromname
));
134 error
= copyinstr(info
.from
, sbp
->f_mntfromname
,
135 sizeof(sbp
->f_mntfromname
), NULL
);
139 * Copy-in ->f_mntonname string.
141 memset(sbp
->f_mntonname
, 0, sizeof(sbp
->f_mntonname
));
142 error
= copyinstr(mntpt
, sbp
->f_mntonname
, sizeof(sbp
->f_mntonname
),
148 * Allocate the autofs mount.
150 amp
= kmalloc(sizeof(*amp
), M_AUTOFS
, M_WAITOK
| M_ZERO
);
151 mp
->mnt_data
= (qaddr_t
)amp
;
152 strlcpy(amp
->am_from
, sbp
->f_mntfromname
, sizeof(amp
->am_from
));
153 strlcpy(amp
->am_on
, sbp
->f_mntonname
, sizeof(amp
->am_on
));
156 * Copy-in master_options string.
158 error
= copyinstr(info
.master_options
, amp
->am_options
,
159 sizeof(amp
->am_options
), NULL
);
163 * Copy-in master_prefix string.
165 error
= copyinstr(info
.master_prefix
, amp
->am_prefix
,
166 sizeof(amp
->am_prefix
), NULL
);
171 * Initialize the autofs mount.
173 mtx_init(&
->am_lock
, "autofsmnlk");
174 amp
->am_last_ino
= AUTOFS_ROOTINO
;
176 mtx_lock_ex_quick(&
->am_lock
);
177 error
= autofs_node_new(NULL
, amp
, ".", -1, &
->am_root
);
178 mtx_unlock_ex(&
->am_lock
);
179 KKASSERT(error
== 0);
180 KKASSERT(amp
->am_root
->an_ino
== AUTOFS_ROOTINO
);
183 vfs_add_vnodeops(mp
, &autofs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
185 VFS_STATFS(mp
, &mp
->mnt_stat
, cred
);
190 kfree(amp
, M_AUTOFS
);
195 autofs_unmount(struct mount
*mp
, int mntflags
)
197 struct autofs_mount
*amp
= VFSTOAUTOFS(mp
);
201 if (mntflags
& MNT_FORCE
)
203 error
= vflush(mp
, 0, flags
);
205 AUTOFS_DEBUG("vflush failed with error %d", error
);
210 * All vnodes are gone, and new one will not appear - so,
211 * no new triggerings.
214 struct autofs_request
*ar
;
219 mtx_lock_ex_quick(&autofs_softc
->sc_lock
);
220 TAILQ_FOREACH(ar
, &autofs_softc
->sc_requests
, ar_next
) {
221 if (ar
->ar_mount
!= amp
)
223 ar
->ar_error
= ENXIO
;
225 ar
->ar_in_progress
= false;
228 if (found
== false) {
229 mtx_unlock_ex(&autofs_softc
->sc_lock
);
233 cv_broadcast(&autofs_softc
->sc_cv
);
234 mtx_unlock_ex(&autofs_softc
->sc_lock
);
236 tsleep(&dummy
, 0, "autofs_umount", hz
);
239 mtx_lock_ex_quick(&
->am_lock
);
240 while (!RB_EMPTY(&
->am_root
->an_children
)) {
241 struct autofs_node
*anp
;
243 * Force delete all nodes when more than one level of
244 * directories are created via indirect map. Autofs doesn't
245 * support rmdir(2), thus this is the only way to get out.
247 anp
= RB_MIN(autofs_node_tree
, &
->am_root
->an_children
);
248 while (!RB_EMPTY(&anp
->an_children
))
249 anp
= RB_MIN(autofs_node_tree
, &anp
->an_children
);
250 autofs_node_delete(anp
);
252 autofs_node_delete(amp
->am_root
);
254 mtx_unlock_ex(&
->am_lock
);
256 mtx_uninit(&
->am_lock
);
258 kfree(amp
, M_AUTOFS
);
264 autofs_root(struct mount
*mp
, struct vnode
**vpp
)
266 struct autofs_mount
*amp
= VFSTOAUTOFS(mp
);
269 KASSERT(amp
->am_root
, ("no root node"));
271 error
= autofs_node_vn(amp
->am_root
, mp
, LK_EXCLUSIVE
, vpp
);
273 struct vnode
*vp
= *vpp
;
275 KKASSERT(vp
->v_type
== VDIR
);
282 autofs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
284 sbp
->f_bsize
= S_BLKSIZE
;
296 autofs_statvfs(struct mount
*mp
, struct statvfs
*sbp
, struct ucred
*cred
)
298 sbp
->f_bsize
= S_BLKSIZE
;
309 static struct vfsops autofs_vfsops
= {
311 .vfs_mount
= autofs_mount
,
312 .vfs_unmount
= autofs_unmount
,
313 .vfs_root
= autofs_root
,
314 .vfs_statfs
= autofs_statfs
,
315 .vfs_statvfs
= autofs_statvfs
,
316 .vfs_init
= autofs_init
,
317 .vfs_uninit
= autofs_uninit
,
320 VFS_SET(autofs_vfsops
, autofs
, VFCF_SYNTHETIC
| VFCF_MPSAFE
);
321 MODULE_VERSION(autofs
, 1);