sys/vfs/autofs: Drop unneeded bzero on node/request ctor
[dragonfly.git] / sys / vfs / autofs / autofs_vnops.c
1 /*-
2  * Copyright (c) 2016 The DragonFly Project
3  * Copyright (c) 2014 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * This software was developed by Edward Tomasz Napierala under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/stat.h>
35 #include <sys/dirent.h>
36 #include <sys/namei.h>
37 #include <sys/nlookup.h>
38 #include <sys/mountctl.h>
39
40 #include "autofs.h"
41
42 static int      autofs_trigger_vn(struct vnode *vp, const char *path,
43                     int pathlen, struct vnode **newvp);
44
45 static __inline size_t
46 autofs_dirent_reclen(const char *name)
47 {
48         return (_DIRENT_RECLEN(strlen(name)));
49 }
50
51 static int
52 test_fs_root(struct vnode *vp)
53 {
54         int error;
55
56         if ((error = vget(vp, LK_SHARED)) != 0) {
57                 AUTOFS_WARN("vget failed with error %d", error);
58                 return (1);
59         }
60
61         if (((vp->v_flag & VROOT) == 0) || (vp->v_tag == VT_AUTOFS)) {
62                 vput(vp);
63                 return (1);
64         }
65
66         return (0);
67 }
68
69 static int
70 nlookup_fs_root(struct autofs_node *anp, struct vnode **vpp)
71 {
72         struct nlookupdata nd;
73         char *path;
74         int error;
75
76         path = autofs_path(anp);
77
78         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
79         if (error == 0) {
80                 error = nlookup(&nd);
81                 if (error == 0) {
82                         struct vnode *vp = nd.nl_nch.ncp->nc_vp;
83                         error = test_fs_root(vp);
84                         if (error == 0)
85                                 *vpp = vp;
86                 }
87         }
88         nlookup_done(&nd);
89         kfree(path, M_AUTOFS);
90
91         return (error);
92 }
93
94 static int
95 autofs_access(struct vop_access_args *ap)
96 {
97         /*
98          * Nothing to do here; the only kind of access control
99          * needed is in autofs_mkdir().
100          */
101         return (0);
102 }
103
104 static int
105 autofs_getattr(struct vop_getattr_args *ap)
106 {
107         struct vnode *vp = ap->a_vp;
108         struct vattr *vap = ap->a_vap;
109         struct autofs_node *anp = VTOI(vp);
110         static bool warned = false;
111
112         KASSERT(vp->v_type == VDIR, ("!VDIR"));
113
114         /*
115          * The reason we must do this is that some tree-walking software,
116          * namely fts(3), assumes that stat(".") results will not change
117          * between chdir("subdir") and chdir(".."), and fails with ENOENT
118          * otherwise.
119          *
120          * XXX: Not supported on DragonFly.
121          * With the current trigger mechanism on DragonFly, the process
122          * will hang while in nlookup() in nlookup_fs_root().
123          */
124         if (autofs_mount_on_stat) {
125                 if (!warned) {
126                         AUTOFS_WARN("vfs.autofs.mount_on_stat not supported");
127                         warned = true;
128                 }
129         }
130
131         vap->va_type = VDIR;
132         vap->va_mode = 0755;
133         vap->va_nlink = 3; /* XXX: FreeBSD had it like this */
134         vap->va_uid = 0;
135         vap->va_gid = 0;
136         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
137         vap->va_fileid = anp->an_ino;
138         vap->va_size = S_BLKSIZE;
139         vap->va_blocksize = S_BLKSIZE;
140         vap->va_mtime = anp->an_ctime;
141         vap->va_atime = anp->an_ctime;
142         vap->va_ctime = anp->an_ctime;
143         vap->va_gen = 0;
144         vap->va_flags = 0;
145         vap->va_rmajor = 0;
146         vap->va_rminor = 0;
147         vap->va_bytes = S_BLKSIZE;
148         vap->va_filerev = 0;
149         vap->va_spare = 0;
150
151         return (0);
152 }
153
154 static int
155 autofs_trigger_vn(struct vnode *vp, const char *path, int pathlen,
156     struct vnode **newvp)
157 {
158         struct autofs_node *anp = VTOI(vp);
159         struct vnode *nvp = NULL;
160         int error;
161
162         KKASSERT(!vn_islocked(vp));
163
164         if (test_fs_root(vp) == 0)
165                 goto mounted;
166
167         /*
168          * Don't remove this.  Without having this extra nlookup,
169          * automountd tries to mount the target filesystem twice
170          * and the second attempt to mount returns an error.
171          */
172         if (nlookup_fs_root(anp, &nvp) == 0)
173                 goto mounted;
174
175         lockmgr(&autofs_softc->sc_lock, LK_EXCLUSIVE);
176         error = autofs_trigger(anp, path, pathlen);
177         lockmgr(&autofs_softc->sc_lock, LK_RELEASE);
178
179         if (error)
180                 return (error);
181
182         if (nlookup_fs_root(anp, &nvp))
183                 return (0);
184
185         /*
186          * If the operation that succeeded was mount, then mark
187          * the node as non-cached.  Otherwise, if someone unmounts
188          * the filesystem before the cache times out, we will fail
189          * to trigger.
190          */
191         autofs_node_uncache(anp);
192 mounted:
193         *newvp = nvp;
194         KKASSERT(vn_islocked(*newvp));
195
196         return (0);
197 }
198
199 static int
200 autofs_nresolve(struct vop_nresolve_args *ap)
201 {
202         struct vnode *vp = NULL;
203         struct vnode *dvp = ap->a_dvp;
204         struct nchandle *nch = ap->a_nch;
205         struct namecache *ncp = nch->ncp;
206         struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount);
207         struct autofs_node *anp = VTOI(dvp);
208         struct autofs_node *child = NULL;
209         int error;
210
211         if (autofs_cached(anp, ncp->nc_name, ncp->nc_nlen) == false &&
212             autofs_ignore_thread() == false) {
213                 struct vnode *newvp = NULL;
214
215                 cache_hold(nch);
216                 cache_unlock(nch);
217                 error = autofs_trigger_vn(dvp,
218                     ncp->nc_name, ncp->nc_nlen, &newvp);
219                 cache_lock(nch);
220                 cache_drop(nch);
221
222                 if (error)
223                         return (error);
224                 if (newvp != NULL) {
225                         KKASSERT(newvp->v_tag != VT_AUTOFS);
226                         vput(newvp);
227                         return (ESTALE);
228                 }
229                 return (0);
230         }
231
232         mtx_lock_sh_quick(&amp->am_lock);
233         error = autofs_node_find(anp, ncp->nc_name, ncp->nc_nlen, &child);
234         mtx_unlock_sh(&amp->am_lock);
235
236         if (error) {
237                 cache_setvp(nch, NULL);
238                 return (0);
239         }
240
241         error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp);
242         if (error == 0) {
243                 KKASSERT(vn_islocked(vp));
244                 vn_unlock(vp);
245                 cache_setvp(nch, vp);
246                 vrele(vp);
247                 return (0);
248         }
249
250         return (error);
251 }
252
253 static int
254 autofs_nmkdir(struct vop_nmkdir_args *ap)
255 {
256         struct vnode *vp = NULL;
257         struct vnode *dvp = ap->a_dvp;
258         struct nchandle *nch = ap->a_nch;
259         struct namecache *ncp = nch->ncp;
260         struct autofs_mount *amp = VFSTOAUTOFS(dvp->v_mount);
261         struct autofs_node *anp = VTOI(dvp);
262         struct autofs_node *child = NULL;
263         int error;
264
265         /*
266          * Do not allow mkdir() if the calling thread is not
267          * automountd(8) descendant.
268          */
269         if (autofs_ignore_thread() == false)
270                 return (EPERM);
271
272         mtx_lock_ex_quick(&amp->am_lock);
273         error = autofs_node_new(anp, amp, ncp->nc_name, ncp->nc_nlen, &child);
274         mtx_unlock_ex(&amp->am_lock);
275         KKASSERT(error == 0);
276
277         error = autofs_node_vn(child, dvp->v_mount, LK_EXCLUSIVE, &vp);
278         if (error == 0) {
279                 KKASSERT(vn_islocked(vp));
280                 cache_setunresolved(nch);
281                 cache_setvp(nch, vp);
282                 *(ap->a_vpp) = vp;
283                 return (0);
284         }
285
286         return (error);
287 }
288
289 static int
290 autofs_readdir_one(struct uio *uio, const char *name, ino_t ino,
291     size_t *reclenp)
292 {
293         int error = 0;
294
295         if (reclenp != NULL)
296                 *reclenp = autofs_dirent_reclen(name);
297
298         if (vop_write_dirent(&error, uio, ino, DT_DIR, strlen(name), name))
299                 return (EINVAL);
300
301         return (error);
302 }
303
304 static int
305 autofs_readdir(struct vop_readdir_args *ap)
306 {
307         struct vnode *vp = ap->a_vp;
308         struct autofs_mount *amp = VFSTOAUTOFS(vp->v_mount);
309         struct autofs_node *anp = VTOI(vp);
310         struct autofs_node *child;
311         struct uio *uio = ap->a_uio;
312         ssize_t initial_resid = ap->a_uio->uio_resid;
313         size_t reclen, reclens;
314         int error;
315
316         KASSERT(vp->v_type == VDIR, ("!VDIR"));
317
318         if (autofs_cached(anp, NULL, 0) == false &&
319             autofs_ignore_thread() == false) {
320                 struct vnode *newvp = NULL;
321                 error = autofs_trigger_vn(vp, "", 0, &newvp);
322                 if (error)
323                         return (error);
324                 if (newvp != NULL) {
325                         KKASSERT(newvp->v_tag != VT_AUTOFS);
326                         vn_unlock(newvp);
327                         error = VOP_READDIR(newvp, ap->a_uio, ap->a_cred,
328                             ap->a_eofflag, ap->a_ncookies, ap->a_cookies);
329                         vrele(newvp);
330                         return (error);
331                 }
332         }
333
334         if (uio->uio_offset < 0)
335                 return (EINVAL);
336
337         if (ap->a_eofflag != NULL)
338                 *ap->a_eofflag = FALSE;
339
340         /*
341          * Write out the directory entry for ".".
342          */
343         if (uio->uio_offset == 0) {
344                 error = autofs_readdir_one(uio, ".", anp->an_ino, &reclen);
345                 if (error)
346                         goto out;
347         }
348         reclens = autofs_dirent_reclen(".");
349
350         /*
351          * Write out the directory entry for "..".
352          */
353         if (uio->uio_offset <= reclens) {
354                 if (uio->uio_offset != reclens)
355                         return (EINVAL);
356                 error = autofs_readdir_one(uio, "..",
357                     (anp->an_parent ? anp->an_parent->an_ino : anp->an_ino),
358                     &reclen);
359                 if (error)
360                         goto out;
361         }
362         reclens += autofs_dirent_reclen("..");
363
364         /*
365          * Write out the directory entries for subdirectories.
366          */
367         mtx_lock_sh_quick(&amp->am_lock);
368         RB_FOREACH(child, autofs_node_tree, &anp->an_children) {
369                 /*
370                  * Check the offset to skip entries returned by previous
371                  * calls to getdents().
372                  */
373                 if (uio->uio_offset > reclens) {
374                         reclens += autofs_dirent_reclen(child->an_name);
375                         continue;
376                 }
377
378                 /*
379                  * Prevent seeking into the middle of dirent.
380                  */
381                 if (uio->uio_offset != reclens) {
382                         mtx_unlock_sh(&amp->am_lock);
383                         return (EINVAL);
384                 }
385
386                 error = autofs_readdir_one(uio, child->an_name,
387                     child->an_ino, &reclen);
388                 reclens += reclen;
389                 if (error) {
390                         mtx_unlock_sh(&amp->am_lock);
391                         goto out;
392                 }
393         }
394         mtx_unlock_sh(&amp->am_lock);
395
396         if (ap->a_eofflag != NULL)
397                 *ap->a_eofflag = TRUE;
398
399         return (0);
400 out:
401         /*
402          * Return error if the initial buffer was too small to do anything.
403          */
404         if (uio->uio_resid == initial_resid)
405                 return (error);
406
407         /*
408          * Don't return an error if we managed to copy out some entries.
409          */
410         if (uio->uio_resid < reclen)
411                 return (0);
412
413         return (error);
414 }
415
416 static int
417 autofs_reclaim(struct vop_reclaim_args *ap)
418 {
419         struct vnode *vp = ap->a_vp;
420         struct autofs_node *anp = VTOI(vp);
421
422         /*
423          * We do not free autofs_node here; instead we are
424          * destroying them in autofs_node_delete().
425          */
426         mtx_lock_ex_quick(&anp->an_vnode_lock);
427         anp->an_vnode = NULL;
428         vp->v_data = NULL;
429         mtx_unlock_ex(&anp->an_vnode_lock);
430
431         return (0);
432 }
433
434 static int
435 autofs_mountctl(struct vop_mountctl_args *ap)
436 {
437         struct mount *mp;
438         int res = 0;
439
440         mp = ap->a_head.a_ops->head.vv_mount;
441         lwkt_gettoken(&mp->mnt_token);
442
443         switch (ap->a_op) {
444         //case ...:
445         //      break;
446         default:
447                 res = vop_stdmountctl(ap);
448                 break;
449         }
450
451         lwkt_reltoken(&mp->mnt_token);
452         return (res);
453 }
454
455 static int
456 autofs_print(struct vop_print_args *ap)
457 {
458         struct autofs_node *anp = VTOI(ap->a_vp);
459
460         kprintf("tag VT_AUTOFS, node %p, ino %jd, name %s, cached %d, retries %d, wildcards %d\n",
461             anp, (intmax_t)anp->an_ino, anp->an_name, anp->an_cached,
462             anp->an_retries, anp->an_wildcards);
463
464         return (0);
465 }
466
467 struct vop_ops autofs_vnode_vops = {
468         .vop_default =          vop_defaultop,
469         .vop_getpages =         vop_stdgetpages,
470         .vop_putpages =         vop_stdputpages,
471         .vop_access =           autofs_access,
472         .vop_getattr =          autofs_getattr,
473         .vop_nresolve =         autofs_nresolve,
474         .vop_nmkdir =           autofs_nmkdir,
475         .vop_readdir =          autofs_readdir,
476         .vop_reclaim =          autofs_reclaim,
477         .vop_mountctl =         autofs_mountctl,
478         .vop_print =            autofs_print,
479 };
480
481 int
482 autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp,
483     const char *name, int namelen, struct autofs_node **anpp)
484 {
485         struct autofs_node *anp;
486
487         KKASSERT(mtx_islocked_ex(&amp->am_lock));
488
489         if (parent != NULL) {
490                 KKASSERT(mtx_islocked_ex(&parent->an_mount->am_lock));
491                 KASSERT(autofs_node_find(parent, name, namelen, NULL) == ENOENT,
492                     ("node \"%s\" already exists", name));
493         }
494
495         /*
496          * All struct fields must be initialized.
497          */
498         anp = objcache_get(autofs_node_objcache, M_WAITOK);
499         if (namelen >= 0)
500                 anp->an_name = kstrndup(name, namelen, M_AUTOFS);
501         else
502                 anp->an_name = kstrdup(name, M_AUTOFS);
503         anp->an_ino = amp->am_last_ino++;
504         callout_init(&anp->an_callout);
505         mtx_init(&anp->an_vnode_lock, "autofsvnlk");
506         getnanotime(&anp->an_ctime);
507         anp->an_parent = parent;
508         anp->an_mount = amp;
509         anp->an_vnode = NULL;
510         anp->an_cached = false;
511         anp->an_wildcards = false;
512         anp->an_retries = 0;
513         if (parent != NULL)
514                 RB_INSERT(autofs_node_tree, &parent->an_children, anp);
515         RB_INIT(&anp->an_children);
516
517         *anpp = anp;
518
519         return (0);
520 }
521
522 int
523 autofs_node_find(struct autofs_node *parent, const char *name,
524     int namelen, struct autofs_node **anpp)
525 {
526         struct autofs_node *anp, find;
527         int error;
528
529         KKASSERT(mtx_islocked(&parent->an_mount->am_lock));
530
531         if (namelen >= 0)
532                 find.an_name = kstrndup(name, namelen, M_AUTOFS);
533         else
534                 find.an_name = kstrdup(name, M_AUTOFS);
535
536         anp = RB_FIND(autofs_node_tree, &parent->an_children, &find);
537         if (anp != NULL) {
538                 error = 0;
539                 if (anpp != NULL)
540                         *anpp = anp;
541         } else {
542                 error = ENOENT;
543         }
544
545         kfree(find.an_name, M_AUTOFS);
546
547         return (error);
548 }
549
550 void
551 autofs_node_delete(struct autofs_node *anp)
552 {
553         KKASSERT(mtx_islocked_ex(&anp->an_mount->am_lock));
554         KASSERT(RB_EMPTY(&anp->an_children), ("have children"));
555
556         callout_drain(&anp->an_callout);
557
558         if (anp->an_parent != NULL)
559                 RB_REMOVE(autofs_node_tree, &anp->an_parent->an_children, anp);
560
561         mtx_uninit(&anp->an_vnode_lock);
562         kfree(anp->an_name, M_AUTOFS);
563         objcache_put(autofs_node_objcache, anp);
564 }
565
566 int
567 autofs_node_vn(struct autofs_node *anp, struct mount *mp, int flags,
568     struct vnode **vpp)
569 {
570         struct vnode *vp = NULL;
571         int error;
572 retry:
573         KKASSERT(mtx_notlocked(&anp->an_mount->am_lock));
574         mtx_lock_ex_quick(&anp->an_vnode_lock);
575
576         vp = anp->an_vnode;
577         if (vp != NULL) {
578                 vhold(vp);
579                 mtx_unlock_ex(&anp->an_vnode_lock);
580
581                 error = vget(vp, flags | LK_RETRY);
582                 if (error) {
583                         AUTOFS_WARN("vget failed with error %d", error);
584                         vdrop(vp);
585                         goto retry;
586                 }
587                 vdrop(vp);
588                 *vpp = vp;
589                 return (0);
590         }
591
592         mtx_unlock_ex(&anp->an_vnode_lock);
593
594         error = getnewvnode(VT_AUTOFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE);
595         if (error)
596                 return (error);
597         vp->v_type = VDIR;
598         vp->v_data = anp;
599
600         KASSERT(anp->an_vnode == NULL, ("lost race"));
601         anp->an_vnode = vp;
602         *vpp = vp;
603
604         return (0);
605 }