Unleashed v1.4
[unleashed.git] / kernel / fs / autofs / auto_vnops.c
blob08864943fc0da56a4795c24b4d3bded8b49ce26e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2017 by Delphix. All rights reserved.
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/errno.h>
29 #include <sys/proc.h>
30 #include <sys/vnode.h>
31 #include <sys/vfs.h>
32 #include <sys/uio.h>
33 #include <sys/cred.h>
34 #include <sys/pathname.h>
35 #include <sys/dirent.h>
36 #include <sys/debug.h>
37 #include <sys/sysmacros.h>
38 #include <sys/tiuser.h>
39 #include <sys/cmn_err.h>
40 #include <sys/stat.h>
41 #include <sys/mode.h>
42 #include <sys/policy.h>
43 #include <rpc/types.h>
44 #include <rpc/auth.h>
45 #include <rpc/clnt.h>
46 #include <sys/fs/autofs.h>
47 #include <rpcsvc/autofs_prot.h>
48 #include <sys/fs_subr.h>
51 * Vnode ops for autofs
53 static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
54 static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
55 caller_context_t *);
56 static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
57 caller_context_t *);
58 static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
59 caller_context_t *);
60 static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
61 static int auto_lookup(vnode_t *, char *, vnode_t **,
62 pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
63 pathname_t *);
64 static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
65 int, vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
66 static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
67 static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
68 caller_context_t *, int);
69 static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
70 caller_context_t *, int);
71 static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
72 caller_context_t *, int, vsecattr_t *);
73 static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
74 caller_context_t *, int);
75 static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
76 caller_context_t *, int);
77 static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
78 caller_context_t *, int);
79 static int auto_readlink(vnode_t *, struct uio *, cred_t *,
80 caller_context_t *);
81 static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
82 static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
83 static int auto_rwlock(vnode_t *, int, caller_context_t *);
84 static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
85 static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
87 static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
89 const struct vnodeops auto_vnodeops = {
90 .vnop_name = "autofs",
91 .vop_open = auto_open,
92 .vop_close = auto_close,
93 .vop_getattr = auto_getattr,
94 .vop_setattr = auto_setattr,
95 .vop_access = auto_access,
96 .vop_lookup = auto_lookup,
97 .vop_create = auto_create,
98 .vop_remove = auto_remove,
99 .vop_link = auto_link,
100 .vop_rename = auto_rename,
101 .vop_mkdir = auto_mkdir,
102 .vop_rmdir = auto_rmdir,
103 .vop_readdir = auto_readdir,
104 .vop_symlink = auto_symlink,
105 .vop_readlink = auto_readlink,
106 .vop_fsync = auto_fsync,
107 .vop_inactive = auto_inactive,
108 .vop_rwlock = auto_rwlock,
109 .vop_rwunlock = auto_rwunlock,
110 .vop_seek = auto_seek,
111 .vop_frlock = fs_nosys,
112 .vop_dispose = fs_nodispose,
113 .vop_shrlock = fs_nosys,
114 .vop_vnevent = fs_vnevent_support,
117 /* ARGSUSED */
118 static int
119 auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
121 vnode_t *newvp;
122 int error;
124 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp));
126 error = auto_trigger_mount(*vpp, cred, &newvp);
127 if (error)
128 goto done;
130 if (newvp != NULL) {
132 * Node is now mounted on.
134 VN_RELE(*vpp);
135 *vpp = newvp;
136 error = fop_access(*vpp, VREAD, 0, cred, ct);
137 if (!error)
138 error = fop_open(vpp, flag, cred, ct);
141 done:
142 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp,
143 error));
144 return (error);
147 /* ARGSUSED */
148 static int
149 auto_close(
150 vnode_t *vp,
151 int flag,
152 int count,
153 offset_t offset,
154 cred_t *cred,
155 caller_context_t *ct)
157 return (0);
160 static int
161 auto_getattr(
162 vnode_t *vp,
163 vattr_t *vap,
164 int flags,
165 cred_t *cred,
166 caller_context_t *ct)
168 fnnode_t *fnp = vntofn(vp);
169 vnode_t *newvp;
170 vfs_t *vfsp;
171 int error;
173 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
175 if (flags & ATTR_TRIGGER) {
177 * Pre-trigger the mount
179 error = auto_trigger_mount(vp, cred, &newvp);
180 if (error)
181 return (error);
183 if (newvp == NULL)
184 goto defattr;
186 if (error = vn_vfsrlock_wait(vp)) {
187 VN_RELE(newvp);
188 return (error);
191 vfsp = newvp->v_vfsp;
192 VN_RELE(newvp);
193 } else {
195 * Recursive auto_getattr/mount; go to the vfsp == NULL
196 * case.
198 if (vn_vfswlock_held(vp))
199 goto defattr;
201 if (error = vn_vfsrlock_wait(vp))
202 return (error);
204 vfsp = vn_mountedvfs(vp);
207 if (vfsp != NULL) {
209 * Node is mounted on.
211 error = VFS_ROOT(vfsp, &newvp);
212 vn_vfsunlock(vp);
213 if (error)
214 return (error);
215 mutex_enter(&fnp->fn_lock);
216 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) {
218 * Recursive auto_getattr(); just release newvp and drop
219 * into the vfsp == NULL case.
221 mutex_exit(&fnp->fn_lock);
222 VN_RELE(newvp);
223 } else {
224 while (fnp->fn_thread && fnp->fn_thread != curthread) {
225 fnp->fn_flags |= MF_ATTR_WAIT;
226 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock);
228 fnp->fn_thread = curthread;
229 fnp->fn_seen = newvp;
230 mutex_exit(&fnp->fn_lock);
231 error = fop_getattr(newvp, vap, flags, cred, ct);
232 VN_RELE(newvp);
233 mutex_enter(&fnp->fn_lock);
234 fnp->fn_seen = 0;
235 fnp->fn_thread = 0;
236 if (fnp->fn_flags & MF_ATTR_WAIT) {
237 fnp->fn_flags &= ~MF_ATTR_WAIT;
238 cv_broadcast(&fnp->fn_cv_mount);
240 mutex_exit(&fnp->fn_lock);
241 return (error);
243 } else {
244 vn_vfsunlock(vp);
247 defattr:
248 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
249 vap->va_uid = 0;
250 vap->va_gid = 0;
251 vap->va_nlink = fnp->fn_linkcnt;
252 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid;
253 vap->va_size = fnp->fn_size;
254 vap->va_atime = fnp->fn_atime;
255 vap->va_mtime = fnp->fn_mtime;
256 vap->va_ctime = fnp->fn_ctime;
257 vap->va_type = vp->v_type;
258 vap->va_mode = fnp->fn_mode;
259 vap->va_fsid = vp->v_vfsp->vfs_dev;
260 vap->va_rdev = 0;
261 vap->va_blksize = MAXBSIZE;
262 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
263 vap->va_seq = 0;
265 return (0);
268 /*ARGSUSED4*/
269 static int
270 auto_setattr(
271 vnode_t *vp,
272 struct vattr *vap,
273 int flags,
274 cred_t *cred,
275 caller_context_t *ct)
277 vnode_t *newvp;
278 int error;
280 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
282 if (error = auto_trigger_mount(vp, cred, &newvp))
283 goto done;
285 if (newvp != NULL) {
287 * Node is mounted on.
289 if (vn_is_readonly(newvp))
290 error = EROFS;
291 else
292 error = fop_setattr(newvp, vap, flags, cred, ct);
293 VN_RELE(newvp);
294 } else
295 error = ENOSYS;
297 done:
298 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error));
299 return (error);
302 /* ARGSUSED */
303 static int
304 auto_access(
305 vnode_t *vp,
306 int mode,
307 int flags,
308 cred_t *cred,
309 caller_context_t *ct)
311 fnnode_t *fnp = vntofn(vp);
312 vnode_t *newvp;
313 int error;
315 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp));
317 if (error = auto_trigger_mount(vp, cred, &newvp))
318 goto done;
320 if (newvp != NULL) {
322 * Node is mounted on.
324 error = fop_access(newvp, mode, 0, cred, ct);
325 VN_RELE(newvp);
326 } else {
327 int shift = 0;
330 * really interested in the autofs node, check the
331 * access on it
333 ASSERT(error == 0);
334 if (crgetuid(cred) != fnp->fn_uid) {
335 shift += 3;
336 if (groupmember(fnp->fn_gid, cred) == 0)
337 shift += 3;
339 error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid,
340 fnp->fn_mode << shift, mode);
343 done:
344 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error));
345 return (error);
348 static int
349 auto_lookup(
350 vnode_t *dvp,
351 char *nm,
352 vnode_t **vpp,
353 pathname_t *pnp,
354 int flags,
355 vnode_t *rdir,
356 cred_t *cred,
357 caller_context_t *ct,
358 int *direntflags,
359 pathname_t *realpnp)
361 int error = 0;
362 vnode_t *newvp = NULL;
363 vfs_t *vfsp;
364 fninfo_t *dfnip;
365 fnnode_t *dfnp = NULL;
366 fnnode_t *fnp = NULL;
367 char *searchnm;
368 int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
370 dfnip = vfstofni(dvp->v_vfsp);
371 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
372 (void *)dvp, dfnip->fi_map, nm));
374 if (nm[0] == 0) {
375 VN_HOLD(dvp);
376 *vpp = dvp;
377 return (0);
380 if (error = fop_access(dvp, VEXEC, 0, cred, ct))
381 return (error);
383 if (nm[0] == '.' && nm[1] == 0) {
384 VN_HOLD(dvp);
385 *vpp = dvp;
386 return (0);
389 if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
390 fnnode_t *pdfnp;
392 pdfnp = (vntofn(dvp))->fn_parent;
393 ASSERT(pdfnp != NULL);
396 * Since it is legitimate to have the VROOT flag set for the
397 * subdirectories of the indirect map in autofs filesystem,
398 * rootfnnodep is checked against fnnode of dvp instead of
399 * just checking whether VROOT flag is set in dvp
402 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
403 vnode_t *vp;
405 vfs_rlock_wait(dvp->v_vfsp);
406 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
407 vfs_unlock(dvp->v_vfsp);
408 return (EIO);
410 vp = dvp->v_vfsp->vfs_vnodecovered;
411 VN_HOLD(vp);
412 vfs_unlock(dvp->v_vfsp);
413 error = fop_lookup(vp, nm, vpp, pnp, flags, rdir, cred,
414 ct, direntflags, realpnp);
415 VN_RELE(vp);
416 return (error);
417 } else {
418 *vpp = fntovn(pdfnp);
419 VN_HOLD(*vpp);
420 return (0);
424 top:
425 dfnp = vntofn(dvp);
426 searchnm = nm;
427 operation = 0;
429 ASSERT(vn_matchops(dvp, &auto_vnodeops));
431 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
432 (void *)dfnp));
435 * If a lookup or mount of this node is in progress, wait for it
436 * to finish, and return whatever result it got.
438 mutex_enter(&dfnp->fn_lock);
439 if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
440 mutex_exit(&dfnp->fn_lock);
441 error = auto_wait4mount(dfnp);
442 if (error == AUTOFS_SHUTDOWN)
443 error = ENOENT;
444 if (error == EAGAIN)
445 goto top;
446 if (error)
447 return (error);
448 } else
449 mutex_exit(&dfnp->fn_lock);
452 error = vn_vfsrlock_wait(dvp);
453 if (error)
454 return (error);
455 vfsp = vn_mountedvfs(dvp);
456 if (vfsp != NULL) {
457 error = VFS_ROOT(vfsp, &newvp);
458 vn_vfsunlock(dvp);
459 if (!error) {
460 error = fop_lookup(newvp, nm, vpp, pnp,
461 flags, rdir, cred, ct, direntflags, realpnp);
462 VN_RELE(newvp);
464 return (error);
466 vn_vfsunlock(dvp);
468 rw_enter(&dfnp->fn_rwlock, RW_READER);
469 error = auto_search(dfnp, nm, &fnp, cred);
470 if (error) {
471 if (dfnip->fi_flags & MF_DIRECT) {
473 * direct map.
475 if (dfnp->fn_dirents) {
477 * Mount previously triggered.
478 * 'nm' not found
480 error = ENOENT;
481 } else {
483 * I need to contact the daemon to trigger
484 * the mount. 'dfnp' will be the mountpoint.
486 operation = AUTOFS_MOUNT;
487 VN_HOLD(fntovn(dfnp));
488 fnp = dfnp;
489 error = 0;
491 } else if (dvp == dfnip->fi_rootvp) {
493 * 'dfnp' is the root of the indirect AUTOFS.
495 if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) {
497 * Could not acquire writer lock, release
498 * reader, and wait until available. We
499 * need to search for 'nm' again, since we
500 * had to release the lock before reacquiring
501 * it.
503 rw_exit(&dfnp->fn_rwlock);
504 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
505 error = auto_search(dfnp, nm, &fnp, cred);
508 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
509 if (error) {
511 * create node being looked-up and request
512 * mount on it.
514 error = auto_enter(dfnp, nm, &fnp, kcred);
515 if (!error)
516 operation = AUTOFS_LOOKUP;
518 } else if ((dfnp->fn_dirents == NULL) &&
519 ((dvp->v_flag & VROOT) == 0) &&
520 ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) {
522 * dfnp is the actual 'mountpoint' of indirect map,
523 * it is the equivalent of a direct mount,
524 * ie, /home/'user1'
526 operation = AUTOFS_MOUNT;
527 VN_HOLD(fntovn(dfnp));
528 fnp = dfnp;
529 error = 0;
530 searchnm = dfnp->fn_name;
534 if (error == EAGAIN) {
535 rw_exit(&dfnp->fn_rwlock);
536 goto top;
538 if (error) {
539 rw_exit(&dfnp->fn_rwlock);
540 return (error);
544 * We now have the actual fnnode we're interested in.
545 * The 'MF_LOOKUP' indicates another thread is currently
546 * performing a daemon lookup of this node, therefore we
547 * wait for its completion.
548 * The 'MF_INPROG' indicates another thread is currently
549 * performing a daemon mount of this node, we wait for it
550 * to be done if we are performing a MOUNT. We don't
551 * wait for it if we are performing a LOOKUP.
552 * We can release the reader/writer lock as soon as we acquire
553 * the mutex, since the state of the lock can only change by
554 * first acquiring the mutex.
556 mutex_enter(&fnp->fn_lock);
557 rw_exit(&dfnp->fn_rwlock);
558 if ((fnp->fn_flags & MF_LOOKUP) ||
559 ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) {
560 mutex_exit(&fnp->fn_lock);
561 error = auto_wait4mount(fnp);
562 VN_RELE(fntovn(fnp));
563 if (error == AUTOFS_SHUTDOWN)
564 error = ENOENT;
565 if (error && error != EAGAIN)
566 return (error);
567 goto top;
570 if (operation == 0) {
572 * got the fnnode, check for any errors
573 * on the previous operation on that node.
575 error = fnp->fn_error;
576 if ((error == EINTR) || (error == EAGAIN)) {
578 * previous operation on this node was
579 * not completed, do a lookup now.
581 operation = AUTOFS_LOOKUP;
582 } else {
584 * previous operation completed. Return
585 * a pointer to the node only if there was
586 * no error.
588 mutex_exit(&fnp->fn_lock);
589 if (!error)
590 *vpp = fntovn(fnp);
591 else
592 VN_RELE(fntovn(fnp));
593 return (error);
598 * Since I got to this point, it means I'm the one
599 * responsible for triggering the mount/look-up of this node.
601 switch (operation) {
602 case AUTOFS_LOOKUP:
603 AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP);
604 fnp->fn_error = 0;
605 mutex_exit(&fnp->fn_lock);
606 error = auto_lookup_aux(fnp, searchnm, cred);
607 if (!error) {
609 * Return this vnode
611 *vpp = fntovn(fnp);
612 } else {
614 * release our reference to this vnode
615 * and return error
617 VN_RELE(fntovn(fnp));
619 break;
620 case AUTOFS_MOUNT:
621 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
622 fnp->fn_error = 0;
623 mutex_exit(&fnp->fn_lock);
625 * auto_new_mount_thread fires up a new thread which
626 * calls automountd finishing up the work
628 auto_new_mount_thread(fnp, searchnm, cred);
631 * At this point, we are simply another thread
632 * waiting for the mount to complete
634 error = auto_wait4mount(fnp);
635 if (error == AUTOFS_SHUTDOWN)
636 error = ENOENT;
639 * now release our reference to this vnode
641 VN_RELE(fntovn(fnp));
642 if (!error)
643 goto top;
644 break;
645 default:
646 auto_log(dfnp->fn_globals->fng_verbose,
647 dfnp->fn_globals->fng_zoneid, CE_WARN,
648 "auto_lookup: unknown operation %d",
649 operation);
652 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
653 nm, (void *)*vpp, error));
655 return (error);
658 static int
659 auto_create(
660 vnode_t *dvp,
661 char *nm,
662 vattr_t *va,
663 vcexcl_t excl,
664 int mode,
665 vnode_t **vpp,
666 cred_t *cred,
667 int flag,
668 caller_context_t *ct,
669 vsecattr_t *vsecp)
671 vnode_t *newvp;
672 int error;
674 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm));
676 if (error = auto_trigger_mount(dvp, cred, &newvp))
677 goto done;
679 if (newvp != NULL) {
681 * Node is now mounted on.
683 if (vn_is_readonly(newvp))
684 error = EROFS;
685 else
686 error = fop_create(newvp, nm, va, excl,
687 mode, vpp, cred, flag, ct, vsecp);
688 VN_RELE(newvp);
689 } else
690 error = ENOSYS;
692 done:
693 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
694 return (error);
697 static int
698 auto_remove(
699 vnode_t *dvp,
700 char *nm,
701 cred_t *cred,
702 caller_context_t *ct,
703 int flags)
705 vnode_t *newvp;
706 int error;
708 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm));
710 if (error = auto_trigger_mount(dvp, cred, &newvp))
711 goto done;
713 if (newvp != NULL) {
715 * Node is now mounted on.
717 if (vn_is_readonly(newvp))
718 error = EROFS;
719 else
720 error = fop_remove(newvp, nm, cred, ct, flags);
721 VN_RELE(newvp);
722 } else
723 error = ENOSYS;
725 done:
726 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error));
727 return (error);
730 static int
731 auto_link(
732 vnode_t *tdvp,
733 vnode_t *svp,
734 char *nm,
735 cred_t *cred,
736 caller_context_t *ct,
737 int flags)
739 vnode_t *newvp;
740 int error;
742 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
743 (void *)svp, nm));
745 if (error = auto_trigger_mount(tdvp, cred, &newvp))
746 goto done;
748 if (newvp == NULL) {
750 * an autonode can not be a link to another node
752 error = ENOSYS;
753 goto done;
756 if (vn_is_readonly(newvp)) {
757 error = EROFS;
758 VN_RELE(newvp);
759 goto done;
762 if (vn_matchops(svp, &auto_vnodeops)) {
764 * source vp can't be an autonode
766 error = ENOSYS;
767 VN_RELE(newvp);
768 goto done;
771 error = fop_link(newvp, svp, nm, cred, ct, flags);
772 VN_RELE(newvp);
774 done:
775 AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
776 return (error);
779 static int
780 auto_rename(
781 vnode_t *odvp,
782 char *onm,
783 vnode_t *ndvp,
784 char *nnm,
785 cred_t *cr,
786 caller_context_t *ct,
787 int flags)
789 vnode_t *o_newvp, *n_newvp;
790 int error;
792 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
793 (void *)odvp, onm, (void *)ndvp, nnm));
796 * we know odvp is an autonode, otherwise this function
797 * could not have ever been called.
799 ASSERT(vn_matchops(odvp, &auto_vnodeops));
801 if (error = auto_trigger_mount(odvp, cr, &o_newvp))
802 goto done;
804 if (o_newvp == NULL) {
806 * can't rename an autonode
808 error = ENOSYS;
809 goto done;
812 if (vn_matchops(ndvp, &auto_vnodeops)) {
814 * directory is AUTOFS, need to trigger the
815 * mount of the real filesystem.
817 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) {
818 VN_RELE(o_newvp);
819 goto done;
822 if (n_newvp == NULL) {
824 * target can't be an autonode
826 error = ENOSYS;
827 VN_RELE(o_newvp);
828 goto done;
830 } else {
832 * destination directory mount had been
833 * triggered prior to the call to this function.
835 n_newvp = ndvp;
838 ASSERT(!vn_matchops(n_newvp, &auto_vnodeops));
840 if (vn_is_readonly(n_newvp)) {
841 error = EROFS;
842 VN_RELE(o_newvp);
843 if (n_newvp != ndvp)
844 VN_RELE(n_newvp);
845 goto done;
848 error = fop_rename(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
849 VN_RELE(o_newvp);
850 if (n_newvp != ndvp)
851 VN_RELE(n_newvp);
853 done:
854 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error));
855 return (error);
858 static int
859 auto_mkdir(
860 vnode_t *dvp,
861 char *nm,
862 vattr_t *va,
863 vnode_t **vpp,
864 cred_t *cred,
865 caller_context_t *ct,
866 int flags,
867 vsecattr_t *vsecp)
869 vnode_t *newvp;
870 int error;
872 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));
874 if (error = auto_trigger_mount(dvp, cred, &newvp))
875 goto done;
877 if (newvp != NULL) {
879 * Node is now mounted on.
881 if (vn_is_readonly(newvp))
882 error = EROFS;
883 else
884 error = fop_mkdir(newvp, nm, va, vpp, cred, ct,
885 flags, vsecp);
886 VN_RELE(newvp);
887 } else
888 error = ENOSYS;
890 done:
891 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
892 return (error);
895 static int
896 auto_rmdir(
897 vnode_t *dvp,
898 char *nm,
899 vnode_t *cdir,
900 cred_t *cred,
901 caller_context_t *ct,
902 int flags)
904 vnode_t *newvp;
905 int error;
907 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm));
909 if (error = auto_trigger_mount(dvp, cred, &newvp))
910 goto done;
912 if (newvp != NULL) {
914 * Node is now mounted on.
916 if (vn_is_readonly(newvp))
917 error = EROFS;
918 else
919 error = fop_rmdir(newvp, nm, cdir, cred, ct, flags);
920 VN_RELE(newvp);
921 } else
922 error = ENOSYS;
924 done:
925 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error));
926 return (error);
929 static int autofs_nobrowse = 0;
931 #ifdef nextdp
932 #undef nextdp
933 #endif
934 #define nextdp(dp) ((struct dirent *)((char *)(dp) + (dp)->d_reclen))
936 /* ARGSUSED */
937 static int
938 auto_readdir(
939 vnode_t *vp,
940 uio_t *uiop,
941 cred_t *cred,
942 int *eofp,
943 caller_context_t *ct,
944 int flags)
946 struct autofs_rddirargs rda;
947 autofs_rddirres rd;
948 fnnode_t *fnp = vntofn(vp);
949 fnnode_t *cfnp, *nfnp;
950 dirent_t *dp;
951 ulong_t offset;
952 ulong_t outcount = 0, count = 0;
953 size_t namelen;
954 ulong_t alloc_count;
955 void *outbuf = NULL;
956 fninfo_t *fnip = vfstofni(vp->v_vfsp);
957 struct iovec *iovp;
958 int error = 0;
959 int reached_max = 0;
960 int myeof = 0;
961 int this_reclen;
962 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
964 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
965 (void *)vp, uiop->uio_loffset));
967 if (eofp != NULL)
968 *eofp = 0;
970 if (uiop->uio_iovcnt != 1)
971 return (EINVAL);
973 iovp = uiop->uio_iov;
974 alloc_count = iovp->iov_len;
976 gethrestime(&fnp->fn_atime);
977 fnp->fn_ref_time = fnp->fn_atime.tv_sec;
979 dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP);
982 * Held when getdents calls fop_rwlock....
984 ASSERT(RW_READ_HELD(&fnp->fn_rwlock));
985 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) {
986 again:
988 * Do readdir of daemon contents only
989 * Drop readers lock and reacquire after reply.
991 rw_exit(&fnp->fn_rwlock);
992 bzero(&rd, sizeof (struct autofs_rddirres));
993 count = 0;
994 rda.rda_map = fnip->fi_map;
995 rda.rda_offset = (uint_t)uiop->uio_offset;
996 rd.rd_rddir.rddir_entries = dp;
997 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count;
998 rda.uid = crgetuid(cred);
1000 error = auto_calldaemon(fngp->fng_zoneid,
1001 AUTOFS_READDIR,
1002 xdr_autofs_rddirargs,
1003 &rda,
1004 xdr_autofs_rddirres,
1005 (void *)&rd,
1006 sizeof (autofs_rddirres),
1007 TRUE);
1010 * reacquire previously dropped lock
1012 rw_enter(&fnp->fn_rwlock, RW_READER);
1014 if (!error) {
1015 error = rd.rd_status;
1016 dp = rd.rd_rddir.rddir_entries;
1019 if (error) {
1020 if (error == AUTOFS_SHUTDOWN) {
1022 * treat as empty directory
1024 error = 0;
1025 myeof = 1;
1026 if (eofp)
1027 *eofp = 1;
1029 goto done;
1031 if (rd.rd_rddir.rddir_size) {
1032 dirent_t *odp = dp; /* next in output buffer */
1033 dirent_t *cdp = dp; /* current examined entry */
1036 * Check for duplicates here
1038 do {
1039 this_reclen = cdp->d_reclen;
1040 if (auto_search(fnp, cdp->d_name,
1041 NULL, cred)) {
1043 * entry not found in kernel list,
1044 * include it in readdir output.
1046 * If we are skipping entries. then
1047 * we need to copy this entry to the
1048 * correct position in the buffer
1049 * to be copied out.
1051 if (cdp != odp)
1052 bcopy(cdp, odp,
1053 (size_t)this_reclen);
1054 odp = nextdp(odp);
1055 outcount += this_reclen;
1056 } else {
1058 * Entry was found in the kernel
1059 * list. If it is the first entry
1060 * in this buffer, then just skip it
1062 if (odp == dp) {
1063 dp = nextdp(dp);
1064 odp = dp;
1067 count += this_reclen;
1068 cdp = (struct dirent *)
1069 ((char *)cdp + this_reclen);
1070 } while (count < rd.rd_rddir.rddir_size);
1072 if (outcount)
1073 error = uiomove(dp, outcount, UIO_READ, uiop);
1074 uiop->uio_offset = rd.rd_rddir.rddir_offset;
1075 } else {
1076 if (rd.rd_rddir.rddir_eof == 0) {
1078 * alloc_count not large enough for one
1079 * directory entry
1081 error = EINVAL;
1084 if (rd.rd_rddir.rddir_eof && !error) {
1085 myeof = 1;
1086 if (eofp)
1087 *eofp = 1;
1089 if (!error && !myeof && outcount == 0) {
1091 * call daemon with new cookie, all previous
1092 * elements happened to be duplicates
1094 dp = outbuf;
1095 goto again;
1097 goto done;
1100 if (uiop->uio_offset == 0) {
1102 * first time: so fudge the . and ..
1104 this_reclen = DIRENT_RECLEN(1);
1105 if (alloc_count < this_reclen) {
1106 error = EINVAL;
1107 goto done;
1109 dp->d_ino = (ino64_t)fnp->fn_nodeid;
1110 dp->d_off = (off64_t)1;
1111 dp->d_reclen = (ushort_t)this_reclen;
1113 /* use strncpy(9f) to zero out uninitialized bytes */
1115 (void) strncpy(dp->d_name, ".",
1116 DIRENT_NAMELEN(this_reclen));
1117 outcount += dp->d_reclen;
1118 dp = nextdp(dp);
1120 this_reclen = DIRENT_RECLEN(2);
1121 if (alloc_count < outcount + this_reclen) {
1122 error = EINVAL;
1123 goto done;
1125 dp->d_reclen = (ushort_t)this_reclen;
1126 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid;
1127 dp->d_off = (off64_t)2;
1129 /* use strncpy(9f) to zero out uninitialized bytes */
1131 (void) strncpy(dp->d_name, "..",
1132 DIRENT_NAMELEN(this_reclen));
1133 outcount += dp->d_reclen;
1134 dp = nextdp(dp);
1137 offset = 2;
1138 cfnp = fnp->fn_dirents;
1139 while (cfnp != NULL) {
1140 nfnp = cfnp->fn_next;
1141 offset = cfnp->fn_offset;
1142 if ((offset >= uiop->uio_offset) &&
1143 (!(cfnp->fn_flags & MF_LOOKUP))) {
1144 int reclen;
1147 * include node only if its offset is greater or
1148 * equal to the one required and it is not in
1149 * transient state (not being looked-up)
1151 namelen = strlen(cfnp->fn_name);
1152 reclen = (int)DIRENT_RECLEN(namelen);
1153 if (outcount + reclen > alloc_count) {
1154 reached_max = 1;
1155 break;
1157 dp->d_reclen = (ushort_t)reclen;
1158 dp->d_ino = (ino64_t)cfnp->fn_nodeid;
1159 if (nfnp != NULL) {
1161 * get the offset of the next element
1163 dp->d_off = (off64_t)nfnp->fn_offset;
1164 } else {
1166 * This is the last element, make
1167 * offset one plus the current
1169 dp->d_off = (off64_t)cfnp->fn_offset + 1;
1172 /* use strncpy(9f) to zero out uninitialized bytes */
1174 (void) strncpy(dp->d_name, cfnp->fn_name,
1175 DIRENT_NAMELEN(reclen));
1176 outcount += dp->d_reclen;
1177 dp = nextdp(dp);
1179 cfnp = nfnp;
1182 if (outcount)
1183 error = uiomove(outbuf, outcount, UIO_READ, uiop);
1185 if (!error) {
1186 if (reached_max) {
1188 * This entry did not get added to the buffer on this,
1189 * call. We need to add it on the next call therefore
1190 * set uio_offset to this entry's offset. If there
1191 * wasn't enough space for one dirent, return EINVAL.
1193 uiop->uio_offset = offset;
1194 if (outcount == 0)
1195 error = EINVAL;
1196 } else if (autofs_nobrowse ||
1197 auto_nobrowse_option(fnip->fi_opts) ||
1198 (fnip->fi_flags & MF_DIRECT) ||
1199 (fnp->fn_trigger != NULL) ||
1200 (((vp->v_flag & VROOT) == 0) &&
1201 ((fntovn(fnp->fn_parent))->v_flag & VROOT) &&
1202 (fnp->fn_dirents == NULL))) {
1204 * done reading directory entries
1206 uiop->uio_offset = offset + 1;
1207 if (eofp)
1208 *eofp = 1;
1209 } else {
1211 * Need to get the rest of the entries from the daemon.
1213 uiop->uio_offset = AUTOFS_DAEMONCOOKIE;
1217 done:
1218 kmem_free(outbuf, alloc_count);
1219 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1220 (void *)vp, uiop->uio_loffset, myeof));
1221 return (error);
1224 static int
1225 auto_symlink(
1226 vnode_t *dvp,
1227 char *lnknm, /* new entry */
1228 vattr_t *tva,
1229 char *tnm, /* existing entry */
1230 cred_t *cred,
1231 caller_context_t *ct,
1232 int flags)
1234 vnode_t *newvp;
1235 int error;
1237 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1238 (void *)dvp, lnknm, tnm));
1240 if (error = auto_trigger_mount(dvp, cred, &newvp))
1241 goto done;
1243 if (newvp != NULL) {
1245 * Node is mounted on.
1247 if (vn_is_readonly(newvp))
1248 error = EROFS;
1249 else
1250 error = fop_symlink(newvp, lnknm, tva, tnm, cred,
1251 ct, flags);
1252 VN_RELE(newvp);
1253 } else
1254 error = ENOSYS;
1256 done:
1257 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error));
1258 return (error);
1261 /* ARGSUSED */
1262 static int
1263 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
1265 fnnode_t *fnp = vntofn(vp);
1266 int error;
1267 timestruc_t now;
1269 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
1271 gethrestime(&now);
1272 fnp->fn_ref_time = now.tv_sec;
1274 if (vp->v_type != VLNK)
1275 error = EINVAL;
1276 else {
1277 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP)));
1278 fnp->fn_atime = now;
1279 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
1280 uiop->uio_resid), UIO_READ, uiop);
1283 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
1284 return (error);
1287 /* ARGSUSED */
1288 static int
1289 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
1291 return (0);
1294 /* ARGSUSED */
1295 static void
1296 auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
1298 fnnode_t *fnp = vntofn(vp);
1299 fnnode_t *dfnp = fnp->fn_parent;
1300 int count;
1302 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1303 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1306 * The rwlock should not be already held by this thread.
1307 * The assert relies on the fact that the owner field is cleared
1308 * when the lock is released.
1310 ASSERT(dfnp != NULL);
1311 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread);
1312 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1313 mutex_enter(&vp->v_lock);
1314 ASSERT(vp->v_count > 0);
1315 VN_RELE_LOCKED(vp);
1316 count = vp->v_count;
1317 mutex_exit(&vp->v_lock);
1318 if (count == 0) {
1320 * Free only if node has no subdirectories.
1322 if (fnp->fn_linkcnt == 1) {
1323 auto_disconnect(dfnp, fnp);
1324 rw_exit(&dfnp->fn_rwlock);
1325 auto_freefnnode(fnp);
1326 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1327 (void *)vp));
1328 return;
1331 rw_exit(&dfnp->fn_rwlock);
1333 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1334 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1337 /* ARGSUSED2 */
1338 static int
1339 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1341 fnnode_t *fnp = vntofn(vp);
1342 if (write_lock)
1343 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1344 else
1345 rw_enter(&fnp->fn_rwlock, RW_READER);
1346 return (write_lock);
1349 /* ARGSUSED */
1350 static void
1351 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1353 fnnode_t *fnp = vntofn(vp);
1354 rw_exit(&fnp->fn_rwlock);
1358 /* ARGSUSED */
1359 static int
1360 auto_seek(
1361 struct vnode *vp,
1362 offset_t ooff,
1363 offset_t *noffp,
1364 caller_context_t *ct)
1367 * Return 0 unconditionally, since we expect
1368 * a VDIR all the time
1370 return (0);
1374 * Triggers the mount if needed. If the mount has been triggered by
1375 * another thread, it will wait for its return status, and return it.
1376 * Whether the mount is triggered by this thread, another thread, or
1377 * if the vnode was already covered, '*newvp' is a
1378 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1379 * If the node is not mounted on, and should not be mounted on, '*newvp'
1380 * will be NULL.
1381 * The calling routine may use '*newvp' to do the filesystem jump.
1383 static int
1384 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp)
1386 fnnode_t *fnp = vntofn(vp);
1387 fninfo_t *fnip = vfstofni(vp->v_vfsp);
1388 vnode_t *dvp;
1389 vfs_t *vfsp;
1390 int delayed_ind;
1391 char name[AUTOFS_MAXPATHLEN];
1392 int error;
1394 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp));
1396 *newvp = NULL;
1399 * Cross-zone mount triggering is disallowed.
1401 if (fnip->fi_zoneid != getzoneid())
1402 return (EPERM); /* Not owner of mount */
1404 retry:
1405 error = 0;
1406 delayed_ind = 0;
1407 mutex_enter(&fnp->fn_lock);
1408 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
1410 * Mount or lookup in progress,
1411 * wait for it before proceeding.
1413 mutex_exit(&fnp->fn_lock);
1414 error = auto_wait4mount(fnp);
1415 if (error == AUTOFS_SHUTDOWN) {
1416 error = 0;
1417 goto done;
1419 if (error && error != EAGAIN)
1420 goto done;
1421 error = 0;
1422 mutex_enter(&fnp->fn_lock);
1426 * If the vfslock can't be acquired for the first time.
1427 * drop the fn_lock and retry next time in blocking mode.
1429 if (vn_vfswlock(vp)) {
1431 * Lock held by another thread.
1432 * Perform blocking by dropping the
1433 * fn_lock.
1435 mutex_exit(&fnp->fn_lock);
1436 error = vn_vfswlock_wait(vp);
1437 if (error)
1438 goto done;
1440 * Because fn_lock wasn't held, the state
1441 * of the trigger node might have changed.
1442 * Need to run through the checks on trigger
1443 * node again.
1445 vn_vfsunlock(vp);
1446 goto retry;
1449 vfsp = vn_mountedvfs(vp);
1450 if (vfsp != NULL) {
1451 mutex_exit(&fnp->fn_lock);
1452 error = VFS_ROOT(vfsp, newvp);
1453 vn_vfsunlock(vp);
1454 goto done;
1455 } else {
1456 vn_vfsunlock(vp);
1457 if ((fnp->fn_flags & MF_MOUNTPOINT) &&
1458 fnp->fn_trigger != NULL) {
1459 ASSERT(fnp->fn_dirents == NULL);
1460 mutex_exit(&fnp->fn_lock);
1462 * The filesystem that used to sit here has been
1463 * forcibly unmounted. Do our best to recover.
1464 * Try to unmount autofs subtree below this node
1465 * and retry the action.
1467 if (unmount_subtree(fnp, B_TRUE) != 0) {
1468 error = EIO;
1469 goto done;
1471 goto retry;
1475 ASSERT(vp->v_type == VDIR);
1476 dvp = fntovn(fnp->fn_parent);
1478 if ((fnp->fn_dirents == NULL) &&
1479 ((fnip->fi_flags & MF_DIRECT) == 0) &&
1480 ((vp->v_flag & VROOT) == 0) &&
1481 (dvp->v_flag & VROOT)) {
1483 * If the parent of this node is the root of an indirect
1484 * AUTOFS filesystem, this node is remountable.
1486 delayed_ind = 1;
1489 if (delayed_ind ||
1490 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) {
1492 * Trigger mount since:
1493 * direct mountpoint with no subdirs or
1494 * delayed indirect.
1496 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
1497 fnp->fn_error = 0;
1498 mutex_exit(&fnp->fn_lock);
1499 if (delayed_ind)
1500 (void) strcpy(name, fnp->fn_name);
1501 else
1502 (void) strcpy(name, ".");
1503 fnp->fn_ref_time = gethrestime_sec();
1504 auto_new_mount_thread(fnp, name, cred);
1506 * At this point we're simply another thread waiting
1507 * for the mount to finish.
1509 error = auto_wait4mount(fnp);
1510 if (error == EAGAIN)
1511 goto retry;
1512 if (error == AUTOFS_SHUTDOWN) {
1513 error = 0;
1514 goto done;
1516 if (error == 0) {
1517 if (error = vn_vfsrlock_wait(vp))
1518 goto done;
1519 /* Reacquire after dropping locks */
1520 vfsp = vn_mountedvfs(vp);
1521 if (vfsp != NULL) {
1522 error = VFS_ROOT(vfsp, newvp);
1523 vn_vfsunlock(vp);
1524 } else {
1525 vn_vfsunlock(vp);
1526 goto retry;
1529 } else
1530 mutex_exit(&fnp->fn_lock);
1532 done:
1533 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error));
1534 return (error);