uts: make emu10k non-verbose
[unleashed.git] / kernel / fs / autofs / auto_vnops.c
blob9d93ef78e453da6539063b9f0b66b61df5f0b571
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.
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/errno.h>
28 #include <sys/proc.h>
29 #include <sys/vnode.h>
30 #include <sys/vfs.h>
31 #include <sys/vfs_opreg.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 vnodeops_t *auto_vnodeops;
91 const fs_operation_def_t auto_vnodeops_template[] = {
92 VOPNAME_OPEN, { .vop_open = auto_open },
93 VOPNAME_CLOSE, { .vop_close = auto_close },
94 VOPNAME_GETATTR, { .vop_getattr = auto_getattr },
95 VOPNAME_SETATTR, { .vop_setattr = auto_setattr },
96 VOPNAME_ACCESS, { .vop_access = auto_access },
97 VOPNAME_LOOKUP, { .vop_lookup = auto_lookup },
98 VOPNAME_CREATE, { .vop_create = auto_create },
99 VOPNAME_REMOVE, { .vop_remove = auto_remove },
100 VOPNAME_LINK, { .vop_link = auto_link },
101 VOPNAME_RENAME, { .vop_rename = auto_rename },
102 VOPNAME_MKDIR, { .vop_mkdir = auto_mkdir },
103 VOPNAME_RMDIR, { .vop_rmdir = auto_rmdir },
104 VOPNAME_READDIR, { .vop_readdir = auto_readdir },
105 VOPNAME_SYMLINK, { .vop_symlink = auto_symlink },
106 VOPNAME_READLINK, { .vop_readlink = auto_readlink },
107 VOPNAME_FSYNC, { .vop_fsync = auto_fsync },
108 VOPNAME_INACTIVE, { .vop_inactive = auto_inactive },
109 VOPNAME_RWLOCK, { .vop_rwlock = auto_rwlock },
110 VOPNAME_RWUNLOCK, { .vop_rwunlock = auto_rwunlock },
111 VOPNAME_SEEK, { .vop_seek = auto_seek },
112 VOPNAME_FRLOCK, { .error = fs_nosys },
113 VOPNAME_DISPOSE, { .vop_dispose = fs_nodispose },
114 VOPNAME_SHRLOCK, { .error = fs_nosys },
115 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
116 NULL, NULL
121 /* ARGSUSED */
122 static int
123 auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
125 vnode_t *newvp;
126 int error;
128 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp));
130 error = auto_trigger_mount(*vpp, cred, &newvp);
131 if (error)
132 goto done;
134 if (newvp != NULL) {
136 * Node is now mounted on.
138 VN_RELE(*vpp);
139 *vpp = newvp;
140 error = fop_access(*vpp, VREAD, 0, cred, ct);
141 if (!error)
142 error = fop_open(vpp, flag, cred, ct);
145 done:
146 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp,
147 error));
148 return (error);
151 /* ARGSUSED */
152 static int
153 auto_close(
154 vnode_t *vp,
155 int flag,
156 int count,
157 offset_t offset,
158 cred_t *cred,
159 caller_context_t *ct)
161 return (0);
164 static int
165 auto_getattr(
166 vnode_t *vp,
167 vattr_t *vap,
168 int flags,
169 cred_t *cred,
170 caller_context_t *ct)
172 fnnode_t *fnp = vntofn(vp);
173 vnode_t *newvp;
174 vfs_t *vfsp;
175 int error;
177 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
179 if (flags & ATTR_TRIGGER) {
181 * Pre-trigger the mount
183 error = auto_trigger_mount(vp, cred, &newvp);
184 if (error)
185 return (error);
187 if (newvp == NULL)
188 goto defattr;
190 if (error = vn_vfsrlock_wait(vp)) {
191 VN_RELE(newvp);
192 return (error);
195 vfsp = newvp->v_vfsp;
196 VN_RELE(newvp);
197 } else {
199 * Recursive auto_getattr/mount; go to the vfsp == NULL
200 * case.
202 if (vn_vfswlock_held(vp))
203 goto defattr;
205 if (error = vn_vfsrlock_wait(vp))
206 return (error);
208 vfsp = vn_mountedvfs(vp);
211 if (vfsp != NULL) {
213 * Node is mounted on.
215 error = VFS_ROOT(vfsp, &newvp);
216 vn_vfsunlock(vp);
217 if (error)
218 return (error);
219 mutex_enter(&fnp->fn_lock);
220 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) {
222 * Recursive auto_getattr(); just release newvp and drop
223 * into the vfsp == NULL case.
225 mutex_exit(&fnp->fn_lock);
226 VN_RELE(newvp);
227 } else {
228 while (fnp->fn_thread && fnp->fn_thread != curthread) {
229 fnp->fn_flags |= MF_ATTR_WAIT;
230 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock);
232 fnp->fn_thread = curthread;
233 fnp->fn_seen = newvp;
234 mutex_exit(&fnp->fn_lock);
235 error = fop_getattr(newvp, vap, flags, cred, ct);
236 VN_RELE(newvp);
237 mutex_enter(&fnp->fn_lock);
238 fnp->fn_seen = 0;
239 fnp->fn_thread = 0;
240 if (fnp->fn_flags & MF_ATTR_WAIT) {
241 fnp->fn_flags &= ~MF_ATTR_WAIT;
242 cv_broadcast(&fnp->fn_cv_mount);
244 mutex_exit(&fnp->fn_lock);
245 return (error);
247 } else {
248 vn_vfsunlock(vp);
251 defattr:
252 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
253 vap->va_uid = 0;
254 vap->va_gid = 0;
255 vap->va_nlink = fnp->fn_linkcnt;
256 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid;
257 vap->va_size = fnp->fn_size;
258 vap->va_atime = fnp->fn_atime;
259 vap->va_mtime = fnp->fn_mtime;
260 vap->va_ctime = fnp->fn_ctime;
261 vap->va_type = vp->v_type;
262 vap->va_mode = fnp->fn_mode;
263 vap->va_fsid = vp->v_vfsp->vfs_dev;
264 vap->va_rdev = 0;
265 vap->va_blksize = MAXBSIZE;
266 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
267 vap->va_seq = 0;
269 return (0);
272 /*ARGSUSED4*/
273 static int
274 auto_setattr(
275 vnode_t *vp,
276 struct vattr *vap,
277 int flags,
278 cred_t *cred,
279 caller_context_t *ct)
281 vnode_t *newvp;
282 int error;
284 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
286 if (error = auto_trigger_mount(vp, cred, &newvp))
287 goto done;
289 if (newvp != NULL) {
291 * Node is mounted on.
293 if (vn_is_readonly(newvp))
294 error = EROFS;
295 else
296 error = fop_setattr(newvp, vap, flags, cred, ct);
297 VN_RELE(newvp);
298 } else
299 error = ENOSYS;
301 done:
302 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error));
303 return (error);
306 /* ARGSUSED */
307 static int
308 auto_access(
309 vnode_t *vp,
310 int mode,
311 int flags,
312 cred_t *cred,
313 caller_context_t *ct)
315 fnnode_t *fnp = vntofn(vp);
316 vnode_t *newvp;
317 int error;
319 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp));
321 if (error = auto_trigger_mount(vp, cred, &newvp))
322 goto done;
324 if (newvp != NULL) {
326 * Node is mounted on.
328 error = fop_access(newvp, mode, 0, cred, ct);
329 VN_RELE(newvp);
330 } else {
331 int shift = 0;
334 * really interested in the autofs node, check the
335 * access on it
337 ASSERT(error == 0);
338 if (crgetuid(cred) != fnp->fn_uid) {
339 shift += 3;
340 if (groupmember(fnp->fn_gid, cred) == 0)
341 shift += 3;
343 error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid,
344 fnp->fn_mode << shift, mode);
347 done:
348 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error));
349 return (error);
352 static int
353 auto_lookup(
354 vnode_t *dvp,
355 char *nm,
356 vnode_t **vpp,
357 pathname_t *pnp,
358 int flags,
359 vnode_t *rdir,
360 cred_t *cred,
361 caller_context_t *ct,
362 int *direntflags,
363 pathname_t *realpnp)
365 int error = 0;
366 vnode_t *newvp = NULL;
367 vfs_t *vfsp;
368 fninfo_t *dfnip;
369 fnnode_t *dfnp = NULL;
370 fnnode_t *fnp = NULL;
371 char *searchnm;
372 int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
374 dfnip = vfstofni(dvp->v_vfsp);
375 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
376 (void *)dvp, dfnip->fi_map, nm));
378 if (nm[0] == 0) {
379 VN_HOLD(dvp);
380 *vpp = dvp;
381 return (0);
384 if (error = fop_access(dvp, VEXEC, 0, cred, ct))
385 return (error);
387 if (nm[0] == '.' && nm[1] == 0) {
388 VN_HOLD(dvp);
389 *vpp = dvp;
390 return (0);
393 if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
394 fnnode_t *pdfnp;
396 pdfnp = (vntofn(dvp))->fn_parent;
397 ASSERT(pdfnp != NULL);
400 * Since it is legitimate to have the VROOT flag set for the
401 * subdirectories of the indirect map in autofs filesystem,
402 * rootfnnodep is checked against fnnode of dvp instead of
403 * just checking whether VROOT flag is set in dvp
406 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
407 vnode_t *vp;
409 vfs_rlock_wait(dvp->v_vfsp);
410 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
411 vfs_unlock(dvp->v_vfsp);
412 return (EIO);
414 vp = dvp->v_vfsp->vfs_vnodecovered;
415 VN_HOLD(vp);
416 vfs_unlock(dvp->v_vfsp);
417 error = fop_lookup(vp, nm, vpp, pnp, flags, rdir, cred,
418 ct, direntflags, realpnp);
419 VN_RELE(vp);
420 return (error);
421 } else {
422 *vpp = fntovn(pdfnp);
423 VN_HOLD(*vpp);
424 return (0);
428 top:
429 dfnp = vntofn(dvp);
430 searchnm = nm;
431 operation = 0;
433 ASSERT(vn_matchops(dvp, auto_vnodeops));
435 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
436 (void *)dfnp));
439 * If a lookup or mount of this node is in progress, wait for it
440 * to finish, and return whatever result it got.
442 mutex_enter(&dfnp->fn_lock);
443 if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
444 mutex_exit(&dfnp->fn_lock);
445 error = auto_wait4mount(dfnp);
446 if (error == AUTOFS_SHUTDOWN)
447 error = ENOENT;
448 if (error == EAGAIN)
449 goto top;
450 if (error)
451 return (error);
452 } else
453 mutex_exit(&dfnp->fn_lock);
456 error = vn_vfsrlock_wait(dvp);
457 if (error)
458 return (error);
459 vfsp = vn_mountedvfs(dvp);
460 if (vfsp != NULL) {
461 error = VFS_ROOT(vfsp, &newvp);
462 vn_vfsunlock(dvp);
463 if (!error) {
464 error = fop_lookup(newvp, nm, vpp, pnp,
465 flags, rdir, cred, ct, direntflags, realpnp);
466 VN_RELE(newvp);
468 return (error);
470 vn_vfsunlock(dvp);
472 rw_enter(&dfnp->fn_rwlock, RW_READER);
473 error = auto_search(dfnp, nm, &fnp, cred);
474 if (error) {
475 if (dfnip->fi_flags & MF_DIRECT) {
477 * direct map.
479 if (dfnp->fn_dirents) {
481 * Mount previously triggered.
482 * 'nm' not found
484 error = ENOENT;
485 } else {
487 * I need to contact the daemon to trigger
488 * the mount. 'dfnp' will be the mountpoint.
490 operation = AUTOFS_MOUNT;
491 VN_HOLD(fntovn(dfnp));
492 fnp = dfnp;
493 error = 0;
495 } else if (dvp == dfnip->fi_rootvp) {
497 * 'dfnp' is the root of the indirect AUTOFS.
499 if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) {
501 * Could not acquire writer lock, release
502 * reader, and wait until available. We
503 * need to search for 'nm' again, since we
504 * had to release the lock before reacquiring
505 * it.
507 rw_exit(&dfnp->fn_rwlock);
508 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
509 error = auto_search(dfnp, nm, &fnp, cred);
512 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
513 if (error) {
515 * create node being looked-up and request
516 * mount on it.
518 error = auto_enter(dfnp, nm, &fnp, kcred);
519 if (!error)
520 operation = AUTOFS_LOOKUP;
522 } else if ((dfnp->fn_dirents == NULL) &&
523 ((dvp->v_flag & VROOT) == 0) &&
524 ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) {
526 * dfnp is the actual 'mountpoint' of indirect map,
527 * it is the equivalent of a direct mount,
528 * ie, /home/'user1'
530 operation = AUTOFS_MOUNT;
531 VN_HOLD(fntovn(dfnp));
532 fnp = dfnp;
533 error = 0;
534 searchnm = dfnp->fn_name;
538 if (error == EAGAIN) {
539 rw_exit(&dfnp->fn_rwlock);
540 goto top;
542 if (error) {
543 rw_exit(&dfnp->fn_rwlock);
544 return (error);
548 * We now have the actual fnnode we're interested in.
549 * The 'MF_LOOKUP' indicates another thread is currently
550 * performing a daemon lookup of this node, therefore we
551 * wait for its completion.
552 * The 'MF_INPROG' indicates another thread is currently
553 * performing a daemon mount of this node, we wait for it
554 * to be done if we are performing a MOUNT. We don't
555 * wait for it if we are performing a LOOKUP.
556 * We can release the reader/writer lock as soon as we acquire
557 * the mutex, since the state of the lock can only change by
558 * first acquiring the mutex.
560 mutex_enter(&fnp->fn_lock);
561 rw_exit(&dfnp->fn_rwlock);
562 if ((fnp->fn_flags & MF_LOOKUP) ||
563 ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) {
564 mutex_exit(&fnp->fn_lock);
565 error = auto_wait4mount(fnp);
566 VN_RELE(fntovn(fnp));
567 if (error == AUTOFS_SHUTDOWN)
568 error = ENOENT;
569 if (error && error != EAGAIN)
570 return (error);
571 goto top;
574 if (operation == 0) {
576 * got the fnnode, check for any errors
577 * on the previous operation on that node.
579 error = fnp->fn_error;
580 if ((error == EINTR) || (error == EAGAIN)) {
582 * previous operation on this node was
583 * not completed, do a lookup now.
585 operation = AUTOFS_LOOKUP;
586 } else {
588 * previous operation completed. Return
589 * a pointer to the node only if there was
590 * no error.
592 mutex_exit(&fnp->fn_lock);
593 if (!error)
594 *vpp = fntovn(fnp);
595 else
596 VN_RELE(fntovn(fnp));
597 return (error);
602 * Since I got to this point, it means I'm the one
603 * responsible for triggering the mount/look-up of this node.
605 switch (operation) {
606 case AUTOFS_LOOKUP:
607 AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP);
608 fnp->fn_error = 0;
609 mutex_exit(&fnp->fn_lock);
610 error = auto_lookup_aux(fnp, searchnm, cred);
611 if (!error) {
613 * Return this vnode
615 *vpp = fntovn(fnp);
616 } else {
618 * release our reference to this vnode
619 * and return error
621 VN_RELE(fntovn(fnp));
623 break;
624 case AUTOFS_MOUNT:
625 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
626 fnp->fn_error = 0;
627 mutex_exit(&fnp->fn_lock);
629 * auto_new_mount_thread fires up a new thread which
630 * calls automountd finishing up the work
632 auto_new_mount_thread(fnp, searchnm, cred);
635 * At this point, we are simply another thread
636 * waiting for the mount to complete
638 error = auto_wait4mount(fnp);
639 if (error == AUTOFS_SHUTDOWN)
640 error = ENOENT;
643 * now release our reference to this vnode
645 VN_RELE(fntovn(fnp));
646 if (!error)
647 goto top;
648 break;
649 default:
650 auto_log(dfnp->fn_globals->fng_verbose,
651 dfnp->fn_globals->fng_zoneid, CE_WARN,
652 "auto_lookup: unknown operation %d",
653 operation);
656 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
657 nm, (void *)*vpp, error));
659 return (error);
662 static int
663 auto_create(
664 vnode_t *dvp,
665 char *nm,
666 vattr_t *va,
667 vcexcl_t excl,
668 int mode,
669 vnode_t **vpp,
670 cred_t *cred,
671 int flag,
672 caller_context_t *ct,
673 vsecattr_t *vsecp)
675 vnode_t *newvp;
676 int error;
678 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm));
680 if (error = auto_trigger_mount(dvp, cred, &newvp))
681 goto done;
683 if (newvp != NULL) {
685 * Node is now mounted on.
687 if (vn_is_readonly(newvp))
688 error = EROFS;
689 else
690 error = fop_create(newvp, nm, va, excl,
691 mode, vpp, cred, flag, ct, vsecp);
692 VN_RELE(newvp);
693 } else
694 error = ENOSYS;
696 done:
697 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
698 return (error);
701 static int
702 auto_remove(
703 vnode_t *dvp,
704 char *nm,
705 cred_t *cred,
706 caller_context_t *ct,
707 int flags)
709 vnode_t *newvp;
710 int error;
712 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm));
714 if (error = auto_trigger_mount(dvp, cred, &newvp))
715 goto done;
717 if (newvp != NULL) {
719 * Node is now mounted on.
721 if (vn_is_readonly(newvp))
722 error = EROFS;
723 else
724 error = fop_remove(newvp, nm, cred, ct, flags);
725 VN_RELE(newvp);
726 } else
727 error = ENOSYS;
729 done:
730 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error));
731 return (error);
734 static int
735 auto_link(
736 vnode_t *tdvp,
737 vnode_t *svp,
738 char *nm,
739 cred_t *cred,
740 caller_context_t *ct,
741 int flags)
743 vnode_t *newvp;
744 int error;
746 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
747 (void *)svp, nm));
749 if (error = auto_trigger_mount(tdvp, cred, &newvp))
750 goto done;
752 if (newvp == NULL) {
754 * an autonode can not be a link to another node
756 error = ENOSYS;
757 goto done;
760 if (vn_is_readonly(newvp)) {
761 error = EROFS;
762 VN_RELE(newvp);
763 goto done;
766 if (vn_matchops(svp, auto_vnodeops)) {
768 * source vp can't be an autonode
770 error = ENOSYS;
771 VN_RELE(newvp);
772 goto done;
775 error = fop_link(newvp, svp, nm, cred, ct, flags);
776 VN_RELE(newvp);
778 done:
779 AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
780 return (error);
783 static int
784 auto_rename(
785 vnode_t *odvp,
786 char *onm,
787 vnode_t *ndvp,
788 char *nnm,
789 cred_t *cr,
790 caller_context_t *ct,
791 int flags)
793 vnode_t *o_newvp, *n_newvp;
794 int error;
796 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
797 (void *)odvp, onm, (void *)ndvp, nnm));
800 * we know odvp is an autonode, otherwise this function
801 * could not have ever been called.
803 ASSERT(vn_matchops(odvp, auto_vnodeops));
805 if (error = auto_trigger_mount(odvp, cr, &o_newvp))
806 goto done;
808 if (o_newvp == NULL) {
810 * can't rename an autonode
812 error = ENOSYS;
813 goto done;
816 if (vn_matchops(ndvp, auto_vnodeops)) {
818 * directory is AUTOFS, need to trigger the
819 * mount of the real filesystem.
821 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) {
822 VN_RELE(o_newvp);
823 goto done;
826 if (n_newvp == NULL) {
828 * target can't be an autonode
830 error = ENOSYS;
831 VN_RELE(o_newvp);
832 goto done;
834 } else {
836 * destination directory mount had been
837 * triggered prior to the call to this function.
839 n_newvp = ndvp;
842 ASSERT(!vn_matchops(n_newvp, auto_vnodeops));
844 if (vn_is_readonly(n_newvp)) {
845 error = EROFS;
846 VN_RELE(o_newvp);
847 if (n_newvp != ndvp)
848 VN_RELE(n_newvp);
849 goto done;
852 error = fop_rename(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
853 VN_RELE(o_newvp);
854 if (n_newvp != ndvp)
855 VN_RELE(n_newvp);
857 done:
858 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error));
859 return (error);
862 static int
863 auto_mkdir(
864 vnode_t *dvp,
865 char *nm,
866 vattr_t *va,
867 vnode_t **vpp,
868 cred_t *cred,
869 caller_context_t *ct,
870 int flags,
871 vsecattr_t *vsecp)
873 vnode_t *newvp;
874 int error;
876 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));
878 if (error = auto_trigger_mount(dvp, cred, &newvp))
879 goto done;
881 if (newvp != NULL) {
883 * Node is now mounted on.
885 if (vn_is_readonly(newvp))
886 error = EROFS;
887 else
888 error = fop_mkdir(newvp, nm, va, vpp, cred, ct,
889 flags, vsecp);
890 VN_RELE(newvp);
891 } else
892 error = ENOSYS;
894 done:
895 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
896 return (error);
899 static int
900 auto_rmdir(
901 vnode_t *dvp,
902 char *nm,
903 vnode_t *cdir,
904 cred_t *cred,
905 caller_context_t *ct,
906 int flags)
908 vnode_t *newvp;
909 int error;
911 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm));
913 if (error = auto_trigger_mount(dvp, cred, &newvp))
914 goto done;
916 if (newvp != NULL) {
918 * Node is now mounted on.
920 if (vn_is_readonly(newvp))
921 error = EROFS;
922 else
923 error = fop_rmdir(newvp, nm, cdir, cred, ct, flags);
924 VN_RELE(newvp);
925 } else
926 error = ENOSYS;
928 done:
929 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error));
930 return (error);
933 static int autofs_nobrowse = 0;
935 #ifdef nextdp
936 #undef nextdp
937 #endif
938 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
940 /* ARGSUSED */
941 static int
942 auto_readdir(
943 vnode_t *vp,
944 uio_t *uiop,
945 cred_t *cred,
946 int *eofp,
947 caller_context_t *ct,
948 int flags)
950 struct autofs_rddirargs rda;
951 autofs_rddirres rd;
952 fnnode_t *fnp = vntofn(vp);
953 fnnode_t *cfnp, *nfnp;
954 dirent64_t *dp;
955 ulong_t offset;
956 ulong_t outcount = 0, count = 0;
957 size_t namelen;
958 ulong_t alloc_count;
959 void *outbuf = NULL;
960 fninfo_t *fnip = vfstofni(vp->v_vfsp);
961 struct iovec *iovp;
962 int error = 0;
963 int reached_max = 0;
964 int myeof = 0;
965 int this_reclen;
966 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
968 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
969 (void *)vp, uiop->uio_loffset));
971 if (eofp != NULL)
972 *eofp = 0;
974 if (uiop->uio_iovcnt != 1)
975 return (EINVAL);
977 iovp = uiop->uio_iov;
978 alloc_count = iovp->iov_len;
980 gethrestime(&fnp->fn_atime);
981 fnp->fn_ref_time = fnp->fn_atime.tv_sec;
983 dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP);
986 * Held when getdents calls fop_rwlock....
988 ASSERT(RW_READ_HELD(&fnp->fn_rwlock));
989 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) {
990 again:
992 * Do readdir of daemon contents only
993 * Drop readers lock and reacquire after reply.
995 rw_exit(&fnp->fn_rwlock);
996 bzero(&rd, sizeof (struct autofs_rddirres));
997 count = 0;
998 rda.rda_map = fnip->fi_map;
999 rda.rda_offset = (uint_t)uiop->uio_offset;
1000 rd.rd_rddir.rddir_entries = dp;
1001 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count;
1002 rda.uid = crgetuid(cred);
1004 error = auto_calldaemon(fngp->fng_zoneid,
1005 AUTOFS_READDIR,
1006 xdr_autofs_rddirargs,
1007 &rda,
1008 xdr_autofs_rddirres,
1009 (void *)&rd,
1010 sizeof (autofs_rddirres),
1011 TRUE);
1014 * reacquire previously dropped lock
1016 rw_enter(&fnp->fn_rwlock, RW_READER);
1018 if (!error) {
1019 error = rd.rd_status;
1020 dp = rd.rd_rddir.rddir_entries;
1023 if (error) {
1024 if (error == AUTOFS_SHUTDOWN) {
1026 * treat as empty directory
1028 error = 0;
1029 myeof = 1;
1030 if (eofp)
1031 *eofp = 1;
1033 goto done;
1035 if (rd.rd_rddir.rddir_size) {
1036 dirent64_t *odp = dp; /* next in output buffer */
1037 dirent64_t *cdp = dp; /* current examined entry */
1040 * Check for duplicates here
1042 do {
1043 this_reclen = cdp->d_reclen;
1044 if (auto_search(fnp, cdp->d_name,
1045 NULL, cred)) {
1047 * entry not found in kernel list,
1048 * include it in readdir output.
1050 * If we are skipping entries. then
1051 * we need to copy this entry to the
1052 * correct position in the buffer
1053 * to be copied out.
1055 if (cdp != odp)
1056 bcopy(cdp, odp,
1057 (size_t)this_reclen);
1058 odp = nextdp(odp);
1059 outcount += this_reclen;
1060 } else {
1062 * Entry was found in the kernel
1063 * list. If it is the first entry
1064 * in this buffer, then just skip it
1066 if (odp == dp) {
1067 dp = nextdp(dp);
1068 odp = dp;
1071 count += this_reclen;
1072 cdp = (struct dirent64 *)
1073 ((char *)cdp + this_reclen);
1074 } while (count < rd.rd_rddir.rddir_size);
1076 if (outcount)
1077 error = uiomove(dp, outcount, UIO_READ, uiop);
1078 uiop->uio_offset = rd.rd_rddir.rddir_offset;
1079 } else {
1080 if (rd.rd_rddir.rddir_eof == 0) {
1082 * alloc_count not large enough for one
1083 * directory entry
1085 error = EINVAL;
1088 if (rd.rd_rddir.rddir_eof && !error) {
1089 myeof = 1;
1090 if (eofp)
1091 *eofp = 1;
1093 if (!error && !myeof && outcount == 0) {
1095 * call daemon with new cookie, all previous
1096 * elements happened to be duplicates
1098 dp = outbuf;
1099 goto again;
1101 goto done;
1104 if (uiop->uio_offset == 0) {
1106 * first time: so fudge the . and ..
1108 this_reclen = DIRENT64_RECLEN(1);
1109 if (alloc_count < this_reclen) {
1110 error = EINVAL;
1111 goto done;
1113 dp->d_ino = (ino64_t)fnp->fn_nodeid;
1114 dp->d_off = (off64_t)1;
1115 dp->d_reclen = (ushort_t)this_reclen;
1117 /* use strncpy(9f) to zero out uninitialized bytes */
1119 (void) strncpy(dp->d_name, ".",
1120 DIRENT64_NAMELEN(this_reclen));
1121 outcount += dp->d_reclen;
1122 dp = nextdp(dp);
1124 this_reclen = DIRENT64_RECLEN(2);
1125 if (alloc_count < outcount + this_reclen) {
1126 error = EINVAL;
1127 goto done;
1129 dp->d_reclen = (ushort_t)this_reclen;
1130 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid;
1131 dp->d_off = (off64_t)2;
1133 /* use strncpy(9f) to zero out uninitialized bytes */
1135 (void) strncpy(dp->d_name, "..",
1136 DIRENT64_NAMELEN(this_reclen));
1137 outcount += dp->d_reclen;
1138 dp = nextdp(dp);
1141 offset = 2;
1142 cfnp = fnp->fn_dirents;
1143 while (cfnp != NULL) {
1144 nfnp = cfnp->fn_next;
1145 offset = cfnp->fn_offset;
1146 if ((offset >= uiop->uio_offset) &&
1147 (!(cfnp->fn_flags & MF_LOOKUP))) {
1148 int reclen;
1151 * include node only if its offset is greater or
1152 * equal to the one required and it is not in
1153 * transient state (not being looked-up)
1155 namelen = strlen(cfnp->fn_name);
1156 reclen = (int)DIRENT64_RECLEN(namelen);
1157 if (outcount + reclen > alloc_count) {
1158 reached_max = 1;
1159 break;
1161 dp->d_reclen = (ushort_t)reclen;
1162 dp->d_ino = (ino64_t)cfnp->fn_nodeid;
1163 if (nfnp != NULL) {
1165 * get the offset of the next element
1167 dp->d_off = (off64_t)nfnp->fn_offset;
1168 } else {
1170 * This is the last element, make
1171 * offset one plus the current
1173 dp->d_off = (off64_t)cfnp->fn_offset + 1;
1176 /* use strncpy(9f) to zero out uninitialized bytes */
1178 (void) strncpy(dp->d_name, cfnp->fn_name,
1179 DIRENT64_NAMELEN(reclen));
1180 outcount += dp->d_reclen;
1181 dp = nextdp(dp);
1183 cfnp = nfnp;
1186 if (outcount)
1187 error = uiomove(outbuf, outcount, UIO_READ, uiop);
1189 if (!error) {
1190 if (reached_max) {
1192 * This entry did not get added to the buffer on this,
1193 * call. We need to add it on the next call therefore
1194 * set uio_offset to this entry's offset. If there
1195 * wasn't enough space for one dirent, return EINVAL.
1197 uiop->uio_offset = offset;
1198 if (outcount == 0)
1199 error = EINVAL;
1200 } else if (autofs_nobrowse ||
1201 auto_nobrowse_option(fnip->fi_opts) ||
1202 (fnip->fi_flags & MF_DIRECT) ||
1203 (fnp->fn_trigger != NULL) ||
1204 (((vp->v_flag & VROOT) == 0) &&
1205 ((fntovn(fnp->fn_parent))->v_flag & VROOT) &&
1206 (fnp->fn_dirents == NULL))) {
1208 * done reading directory entries
1210 uiop->uio_offset = offset + 1;
1211 if (eofp)
1212 *eofp = 1;
1213 } else {
1215 * Need to get the rest of the entries from the daemon.
1217 uiop->uio_offset = AUTOFS_DAEMONCOOKIE;
1221 done:
1222 kmem_free(outbuf, alloc_count);
1223 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1224 (void *)vp, uiop->uio_loffset, myeof));
1225 return (error);
1228 static int
1229 auto_symlink(
1230 vnode_t *dvp,
1231 char *lnknm, /* new entry */
1232 vattr_t *tva,
1233 char *tnm, /* existing entry */
1234 cred_t *cred,
1235 caller_context_t *ct,
1236 int flags)
1238 vnode_t *newvp;
1239 int error;
1241 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1242 (void *)dvp, lnknm, tnm));
1244 if (error = auto_trigger_mount(dvp, cred, &newvp))
1245 goto done;
1247 if (newvp != NULL) {
1249 * Node is mounted on.
1251 if (vn_is_readonly(newvp))
1252 error = EROFS;
1253 else
1254 error = fop_symlink(newvp, lnknm, tva, tnm, cred,
1255 ct, flags);
1256 VN_RELE(newvp);
1257 } else
1258 error = ENOSYS;
1260 done:
1261 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error));
1262 return (error);
1265 /* ARGSUSED */
1266 static int
1267 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
1269 fnnode_t *fnp = vntofn(vp);
1270 int error;
1271 timestruc_t now;
1273 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
1275 gethrestime(&now);
1276 fnp->fn_ref_time = now.tv_sec;
1278 if (vp->v_type != VLNK)
1279 error = EINVAL;
1280 else {
1281 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP)));
1282 fnp->fn_atime = now;
1283 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
1284 uiop->uio_resid), UIO_READ, uiop);
1287 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
1288 return (error);
1291 /* ARGSUSED */
1292 static int
1293 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
1295 return (0);
1298 /* ARGSUSED */
1299 static void
1300 auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
1302 fnnode_t *fnp = vntofn(vp);
1303 fnnode_t *dfnp = fnp->fn_parent;
1304 int count;
1306 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1307 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1310 * The rwlock should not be already held by this thread.
1311 * The assert relies on the fact that the owner field is cleared
1312 * when the lock is released.
1314 ASSERT(dfnp != NULL);
1315 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread);
1316 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1317 mutex_enter(&vp->v_lock);
1318 ASSERT(vp->v_count > 0);
1319 count = --vp->v_count;
1320 mutex_exit(&vp->v_lock);
1321 if (count == 0) {
1323 * Free only if node has no subdirectories.
1325 if (fnp->fn_linkcnt == 1) {
1326 auto_disconnect(dfnp, fnp);
1327 rw_exit(&dfnp->fn_rwlock);
1328 auto_freefnnode(fnp);
1329 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1330 (void *)vp));
1331 return;
1334 rw_exit(&dfnp->fn_rwlock);
1336 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1337 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1340 /* ARGSUSED2 */
1341 static int
1342 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1344 fnnode_t *fnp = vntofn(vp);
1345 if (write_lock)
1346 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1347 else
1348 rw_enter(&fnp->fn_rwlock, RW_READER);
1349 return (write_lock);
1352 /* ARGSUSED */
1353 static void
1354 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1356 fnnode_t *fnp = vntofn(vp);
1357 rw_exit(&fnp->fn_rwlock);
1361 /* ARGSUSED */
1362 static int
1363 auto_seek(
1364 struct vnode *vp,
1365 offset_t ooff,
1366 offset_t *noffp,
1367 caller_context_t *ct)
1370 * Return 0 unconditionally, since we expect
1371 * a VDIR all the time
1373 return (0);
1377 * Triggers the mount if needed. If the mount has been triggered by
1378 * another thread, it will wait for its return status, and return it.
1379 * Whether the mount is triggered by this thread, another thread, or
1380 * if the vnode was already covered, '*newvp' is a
1381 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1382 * If the node is not mounted on, and should not be mounted on, '*newvp'
1383 * will be NULL.
1384 * The calling routine may use '*newvp' to do the filesystem jump.
1386 static int
1387 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp)
1389 fnnode_t *fnp = vntofn(vp);
1390 fninfo_t *fnip = vfstofni(vp->v_vfsp);
1391 vnode_t *dvp;
1392 vfs_t *vfsp;
1393 int delayed_ind;
1394 char name[AUTOFS_MAXPATHLEN];
1395 int error;
1397 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp));
1399 *newvp = NULL;
1402 * Cross-zone mount triggering is disallowed.
1404 if (fnip->fi_zoneid != getzoneid())
1405 return (EPERM); /* Not owner of mount */
1407 retry:
1408 error = 0;
1409 delayed_ind = 0;
1410 mutex_enter(&fnp->fn_lock);
1411 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
1413 * Mount or lookup in progress,
1414 * wait for it before proceeding.
1416 mutex_exit(&fnp->fn_lock);
1417 error = auto_wait4mount(fnp);
1418 if (error == AUTOFS_SHUTDOWN) {
1419 error = 0;
1420 goto done;
1422 if (error && error != EAGAIN)
1423 goto done;
1424 error = 0;
1425 mutex_enter(&fnp->fn_lock);
1429 * If the vfslock can't be acquired for the first time.
1430 * drop the fn_lock and retry next time in blocking mode.
1432 if (vn_vfswlock(vp)) {
1434 * Lock held by another thread.
1435 * Perform blocking by dropping the
1436 * fn_lock.
1438 mutex_exit(&fnp->fn_lock);
1439 error = vn_vfswlock_wait(vp);
1440 if (error)
1441 goto done;
1443 * Because fn_lock wasn't held, the state
1444 * of the trigger node might have changed.
1445 * Need to run through the checks on trigger
1446 * node again.
1448 vn_vfsunlock(vp);
1449 goto retry;
1452 vfsp = vn_mountedvfs(vp);
1453 if (vfsp != NULL) {
1454 mutex_exit(&fnp->fn_lock);
1455 error = VFS_ROOT(vfsp, newvp);
1456 vn_vfsunlock(vp);
1457 goto done;
1458 } else {
1459 vn_vfsunlock(vp);
1460 if ((fnp->fn_flags & MF_MOUNTPOINT) &&
1461 fnp->fn_trigger != NULL) {
1462 ASSERT(fnp->fn_dirents == NULL);
1463 mutex_exit(&fnp->fn_lock);
1465 * The filesystem that used to sit here has been
1466 * forcibly unmounted. Do our best to recover.
1467 * Try to unmount autofs subtree below this node
1468 * and retry the action.
1470 if (unmount_subtree(fnp, B_TRUE) != 0) {
1471 error = EIO;
1472 goto done;
1474 goto retry;
1478 ASSERT(vp->v_type == VDIR);
1479 dvp = fntovn(fnp->fn_parent);
1481 if ((fnp->fn_dirents == NULL) &&
1482 ((fnip->fi_flags & MF_DIRECT) == 0) &&
1483 ((vp->v_flag & VROOT) == 0) &&
1484 (dvp->v_flag & VROOT)) {
1486 * If the parent of this node is the root of an indirect
1487 * AUTOFS filesystem, this node is remountable.
1489 delayed_ind = 1;
1492 if (delayed_ind ||
1493 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) {
1495 * Trigger mount since:
1496 * direct mountpoint with no subdirs or
1497 * delayed indirect.
1499 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
1500 fnp->fn_error = 0;
1501 mutex_exit(&fnp->fn_lock);
1502 if (delayed_ind)
1503 (void) strcpy(name, fnp->fn_name);
1504 else
1505 (void) strcpy(name, ".");
1506 fnp->fn_ref_time = gethrestime_sec();
1507 auto_new_mount_thread(fnp, name, cred);
1509 * At this point we're simply another thread waiting
1510 * for the mount to finish.
1512 error = auto_wait4mount(fnp);
1513 if (error == EAGAIN)
1514 goto retry;
1515 if (error == AUTOFS_SHUTDOWN) {
1516 error = 0;
1517 goto done;
1519 if (error == 0) {
1520 if (error = vn_vfsrlock_wait(vp))
1521 goto done;
1522 /* Reacquire after dropping locks */
1523 vfsp = vn_mountedvfs(vp);
1524 if (vfsp != NULL) {
1525 error = VFS_ROOT(vfsp, newvp);
1526 vn_vfsunlock(vp);
1527 } else {
1528 vn_vfsunlock(vp);
1529 goto retry;
1532 } else
1533 mutex_exit(&fnp->fn_lock);
1535 done:
1536 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error));
1537 return (error);