sys/vfs/autofs: Add Copyright
[dragonfly.git] / sys / vfs / autofs / autofs_vfsops.c
1 /*-
2  * Copyright (c) 2016 Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
3  * Copyright (c) 2016 The DragonFly Project
4  * Copyright (c) 2014 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Edward Tomasz Napierala under sponsorship
8  * from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  */
32
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/stat.h>
36
37 #include "autofs.h"
38 #include "autofs_mount.h"
39
40 static int      autofs_statfs(struct mount *mp, struct statfs *sbp,
41                     struct ucred *cred);
42
43 static struct objcache_malloc_args autofs_request_args = {
44         sizeof(struct autofs_request), M_AUTOFS,
45 };
46 static struct objcache_malloc_args autofs_node_args = {
47         sizeof(struct autofs_node), M_AUTOFS,
48 };
49
50 static int
51 autofs_init(struct vfsconf *vfsp)
52 {
53         KASSERT(autofs_softc == NULL,
54             ("softc %p, should be NULL", autofs_softc));
55
56         autofs_softc = kmalloc(sizeof(*autofs_softc), M_AUTOFS,
57             M_WAITOK | M_ZERO);
58
59         autofs_request_objcache = objcache_create("autofs_request", 0, 0,
60                 NULL, NULL, NULL,
61                 objcache_malloc_alloc_zero,
62                 objcache_malloc_free,
63                 &autofs_request_args);
64
65         autofs_node_objcache = objcache_create("autofs_node", 0, 0,
66                 NULL, NULL, NULL,
67                 objcache_malloc_alloc_zero,
68                 objcache_malloc_free,
69                 &autofs_node_args);
70
71         TAILQ_INIT(&autofs_softc->sc_requests);
72         cv_init(&autofs_softc->sc_cv, "autofscv");
73         lockinit(&autofs_softc->sc_lock, "autofssclk", 0, 0);
74         autofs_softc->sc_dev_opened = false;
75
76         autofs_softc->sc_cdev = make_dev(&autofs_ops, 0, UID_ROOT,
77             GID_OPERATOR, 0640, "autofs");
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);
83
84                 return (ENODEV);
85         }
86         autofs_softc->sc_cdev->si_drv1 = autofs_softc;
87
88         return (0);
89 }
90
91 static int
92 autofs_uninit(struct vfsconf *vfsp)
93 {
94         lockmgr(&autofs_softc->sc_lock, LK_EXCLUSIVE);
95         if (autofs_softc->sc_dev_opened) {
96                 lockmgr(&autofs_softc->sc_lock, LK_RELEASE);
97                 return (EBUSY);
98         }
99
100         if (autofs_softc->sc_cdev != NULL)
101                 destroy_dev(autofs_softc->sc_cdev);
102
103         objcache_destroy(autofs_request_objcache);
104         objcache_destroy(autofs_node_objcache);
105
106         lockmgr(&autofs_softc->sc_lock, LK_RELEASE);
107
108         kfree(autofs_softc, M_AUTOFS);  /* race with open */
109         autofs_softc = NULL;
110
111         return (0);
112 }
113
114 static int
115 autofs_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred)
116 {
117         struct autofs_mount_info info;
118         struct autofs_mount *amp;
119         struct statfs *sbp = &mp->mnt_stat;
120         int error;
121
122         if (mp->mnt_flag & MNT_UPDATE) {
123                 autofs_flush(VFSTOAUTOFS(mp));
124                 return (0);
125         }
126
127         error = copyin(data, &info, sizeof(info));
128         if (error)
129                 return (error);
130
131         /*
132          * Copy-in ->f_mntfromname string.
133          */
134         memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname));
135         error = copyinstr(info.from, sbp->f_mntfromname,
136             sizeof(sbp->f_mntfromname), NULL);
137         if (error)
138                 return (error);
139         /*
140          * Copy-in ->f_mntonname string.
141          */
142         memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname));
143         error = copyinstr(mntpt, sbp->f_mntonname,
144             sizeof(sbp->f_mntonname), NULL);
145         if (error)
146                 return (error);
147
148         /*
149          * Allocate the autofs mount.
150          */
151         amp = kmalloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO);
152         mp->mnt_data = (qaddr_t)amp;
153         amp->am_mp = mp;
154         strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from));
155         strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on));
156
157         /*
158          * Copy-in master_options string.
159          */
160         error = copyinstr(info.master_options, amp->am_options,
161             sizeof(amp->am_options), NULL);
162         if (error)
163                 goto fail;
164         /*
165          * Copy-in master_prefix string.
166          */
167         error = copyinstr(info.master_prefix, amp->am_prefix,
168             sizeof(amp->am_prefix), NULL);
169         if (error)
170                 goto fail;
171
172         /*
173          * Initialize the autofs mount.
174          */
175         mtx_init(&amp->am_lock, "autofsmnlk");
176         amp->am_last_ino = AUTOFS_ROOTINO;
177
178         vfs_getnewfsid(mp);
179         vfs_add_vnodeops(mp, &autofs_vnode_vops, &mp->mnt_vn_norm_ops);
180
181         mtx_lock_ex_quick(&amp->am_lock);
182         error = autofs_node_new(NULL, amp, ".", -1, &amp->am_root);
183         mtx_unlock_ex(&amp->am_lock);
184         KKASSERT(error == 0);
185         KKASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO);
186
187         autofs_statfs(mp, sbp, cred);
188
189         return (0);
190
191 fail:
192         kfree(amp, M_AUTOFS);
193         return (error);
194 }
195
196 static int
197 autofs_unmount(struct mount *mp, int mntflags)
198 {
199         struct autofs_mount *amp = VFSTOAUTOFS(mp);
200         int error, flags;
201
202         flags = 0;
203         if (mntflags & MNT_FORCE)
204                 flags |= FORCECLOSE;
205         error = vflush(mp, 0, flags);
206         if (error) {
207                 AUTOFS_WARN("vflush failed with error %d", error);
208                 return (error);
209         }
210
211         /*
212          * All vnodes are gone, and new one will not appear - so,
213          * no new triggerings.
214          */
215         for (;;) {
216                 struct autofs_request *ar;
217                 int dummy;
218                 bool found;
219
220                 found = false;
221                 lockmgr(&autofs_softc->sc_lock, LK_EXCLUSIVE);
222                 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
223                         if (ar->ar_mount != amp)
224                                 continue;
225                         ar->ar_error = ENXIO;
226                         ar->ar_done = true;
227                         ar->ar_in_progress = false;
228                         found = true;
229                 }
230                 if (found == false) {
231                         lockmgr(&autofs_softc->sc_lock, LK_RELEASE);
232                         break;
233                 }
234
235                 cv_broadcast(&autofs_softc->sc_cv);
236                 lockmgr(&autofs_softc->sc_lock, LK_RELEASE);
237
238                 tsleep(&dummy, 0, "autofs_umount", hz);
239         }
240
241         mtx_lock_ex_quick(&amp->am_lock);
242         while (!RB_EMPTY(&amp->am_root->an_children)) {
243                 struct autofs_node *anp;
244                 /*
245                  * Force delete all nodes when more than one level of
246                  * directories are created via indirect map. Autofs doesn't
247                  * support rmdir(2), thus this is the only way to get out.
248                  */
249                 anp = RB_MIN(autofs_node_tree, &amp->am_root->an_children);
250                 while (!RB_EMPTY(&anp->an_children))
251                         anp = RB_MIN(autofs_node_tree, &anp->an_children);
252                 autofs_node_delete(anp);
253         }
254         autofs_node_delete(amp->am_root);
255         mp->mnt_data = NULL;
256         mtx_unlock_ex(&amp->am_lock);
257
258         mtx_uninit(&amp->am_lock);
259
260         kfree(amp, M_AUTOFS);
261
262         return (0);
263 }
264
265 static int
266 autofs_root(struct mount *mp, struct vnode **vpp)
267 {
268         struct autofs_mount *amp = VFSTOAUTOFS(mp);
269         int error;
270
271         if (amp->am_root == NULL) {
272                 AUTOFS_FATAL("called without root node %p", mp);
273                 print_backtrace(-1);
274                 *vpp = NULL;
275                 error = EINVAL;
276         } else {
277                 error = autofs_node_vn(amp->am_root, mp, LK_EXCLUSIVE, vpp);
278                 (*vpp)->v_flag |= VROOT;
279                 KKASSERT((*vpp)->v_type == VDIR);
280         }
281
282         return (error);
283 }
284
285 static int
286 autofs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
287 {
288         sbp->f_bsize = S_BLKSIZE;
289         sbp->f_iosize = 0;
290         sbp->f_blocks = 0;
291         sbp->f_bfree = 0;
292         sbp->f_bavail = 0;
293         sbp->f_files = 0;
294         sbp->f_ffree = 0;
295
296         return (0);
297 }
298
299 static int
300 autofs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
301 {
302         sbp->f_bsize = S_BLKSIZE;
303         sbp->f_frsize = 0;
304         sbp->f_blocks = 0;
305         sbp->f_bfree = 0;
306         sbp->f_bavail = 0;
307         sbp->f_files = 0;
308         sbp->f_ffree = 0;
309
310         return (0);
311 }
312
313 static struct vfsops autofs_vfsops = {
314         .vfs_mount =            autofs_mount,
315         .vfs_unmount =          autofs_unmount,
316         .vfs_root =             autofs_root,
317         .vfs_statfs =           autofs_statfs,
318         .vfs_statvfs =          autofs_statvfs,
319         .vfs_init =             autofs_init,
320         .vfs_uninit =           autofs_uninit,
321 };
322
323 VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_MPSAFE);
324 MODULE_VERSION(autofs, 1);