1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2017 by Delphix. All rights reserved.
24 */
25
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/vfs_opreg.h>
33 #include <sys/uio.h>
34 #include <sys/cred.h>
35 #include <sys/pathname.h>
36 #include <sys/dirent.h>
37 #include <sys/debug.h>
38 #include <sys/sysmacros.h>
39 #include <sys/tiuser.h>
40 #include <sys/cmn_err.h>
41 #include <sys/stat.h>
42 #include <sys/mode.h>
43 #include <sys/policy.h>
44 #include <rpc/types.h>
45 #include <rpc/auth.h>
46 #include <rpc/clnt.h>
47 #include <sys/fs/autofs.h>
48 #include <rpcsvc/autofs_prot.h>
49 #include <fs/fs_subr.h>
50
51 /*
52 * Vnode ops for autofs
53 */
54 static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
55 static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
56 caller_context_t *);
57 static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
58 caller_context_t *);
59 static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
60 caller_context_t *);
61 static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
62 static int auto_lookup(vnode_t *, char *, vnode_t **,
63 pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
64 pathname_t *);
65 static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
66 int, vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
67 static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
68 static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
69 caller_context_t *, int);
70 static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
71 caller_context_t *, int);
72 static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
73 caller_context_t *, int, vsecattr_t *);
74 static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
75 caller_context_t *, int);
76 static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
77 caller_context_t *, int);
78 static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
79 caller_context_t *, int);
80 static int auto_readlink(vnode_t *, struct uio *, cred_t *,
81 caller_context_t *);
82 static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
83 static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
84 static int auto_rwlock(vnode_t *, int, caller_context_t *);
85 static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
86 static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
87
88 static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
89
90 vnodeops_t *auto_vnodeops;
91
92 const fs_operation_def_t auto_vnodeops_template[] = {
93 VOPNAME_OPEN, { .vop_open = auto_open },
94 VOPNAME_CLOSE, { .vop_close = auto_close },
95 VOPNAME_GETATTR, { .vop_getattr = auto_getattr },
96 VOPNAME_SETATTR, { .vop_setattr = auto_setattr },
97 VOPNAME_ACCESS, { .vop_access = auto_access },
98 VOPNAME_LOOKUP, { .vop_lookup = auto_lookup },
99 VOPNAME_CREATE, { .vop_create = auto_create },
100 VOPNAME_REMOVE, { .vop_remove = auto_remove },
101 VOPNAME_LINK, { .vop_link = auto_link },
102 VOPNAME_RENAME, { .vop_rename = auto_rename },
103 VOPNAME_MKDIR, { .vop_mkdir = auto_mkdir },
104 VOPNAME_RMDIR, { .vop_rmdir = auto_rmdir },
105 VOPNAME_READDIR, { .vop_readdir = auto_readdir },
106 VOPNAME_SYMLINK, { .vop_symlink = auto_symlink },
107 VOPNAME_READLINK, { .vop_readlink = auto_readlink },
108 VOPNAME_FSYNC, { .vop_fsync = auto_fsync },
109 VOPNAME_INACTIVE, { .vop_inactive = auto_inactive },
110 VOPNAME_RWLOCK, { .vop_rwlock = auto_rwlock },
111 VOPNAME_RWUNLOCK, { .vop_rwunlock = auto_rwunlock },
112 VOPNAME_SEEK, { .vop_seek = auto_seek },
113 VOPNAME_FRLOCK, { .error = fs_error },
114 VOPNAME_DISPOSE, { .error = fs_error },
115 VOPNAME_SHRLOCK, { .error = fs_error },
116 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
117 NULL, NULL
118 };
119
120
121
122 /* ARGSUSED */
123 static int
auto_open(vnode_t ** vpp,int flag,cred_t * cred,caller_context_t * ct)124 auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
125 {
126 vnode_t *newvp;
127 int error;
128
129 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp));
130
131 error = auto_trigger_mount(*vpp, cred, &newvp);
132 if (error)
133 goto done;
134
135 if (newvp != NULL) {
136 /*
137 * Node is now mounted on.
138 */
139 VN_RELE(*vpp);
140 *vpp = newvp;
141 error = VOP_ACCESS(*vpp, VREAD, 0, cred, ct);
142 if (!error)
143 error = VOP_OPEN(vpp, flag, cred, ct);
144 }
145
146 done:
147 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp,
148 error));
149 return (error);
150 }
151
152 /* ARGSUSED */
153 static int
auto_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cred,caller_context_t * ct)154 auto_close(
155 vnode_t *vp,
156 int flag,
157 int count,
158 offset_t offset,
159 cred_t *cred,
160 caller_context_t *ct)
161 {
162 return (0);
163 }
164
165 static int
auto_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cred,caller_context_t * ct)166 auto_getattr(
167 vnode_t *vp,
168 vattr_t *vap,
169 int flags,
170 cred_t *cred,
171 caller_context_t *ct)
172 {
173 fnnode_t *fnp = vntofn(vp);
174 vnode_t *newvp;
175 vfs_t *vfsp;
176 int error;
177
178 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
179
180 if (flags & ATTR_TRIGGER) {
181 /*
182 * Pre-trigger the mount
183 */
184 error = auto_trigger_mount(vp, cred, &newvp);
185 if (error)
186 return (error);
187
188 if (newvp == NULL)
189 goto defattr;
190
191 if (error = vn_vfsrlock_wait(vp)) {
192 VN_RELE(newvp);
193 return (error);
194 }
195
196 vfsp = newvp->v_vfsp;
197 VN_RELE(newvp);
198 } else {
199 /*
200 * Recursive auto_getattr/mount; go to the vfsp == NULL
201 * case.
202 */
203 if (vn_vfswlock_held(vp))
204 goto defattr;
205
206 if (error = vn_vfsrlock_wait(vp))
207 return (error);
208
209 vfsp = vn_mountedvfs(vp);
210 }
211
212 if (vfsp != NULL) {
213 /*
214 * Node is mounted on.
215 */
216 error = VFS_ROOT(vfsp, &newvp);
217 vn_vfsunlock(vp);
218 if (error)
219 return (error);
220 mutex_enter(&fnp->fn_lock);
221 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) {
222 /*
223 * Recursive auto_getattr(); just release newvp and drop
224 * into the vfsp == NULL case.
225 */
226 mutex_exit(&fnp->fn_lock);
227 VN_RELE(newvp);
228 } else {
229 while (fnp->fn_thread && fnp->fn_thread != curthread) {
230 fnp->fn_flags |= MF_ATTR_WAIT;
231 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock);
232 }
233 fnp->fn_thread = curthread;
234 fnp->fn_seen = newvp;
235 mutex_exit(&fnp->fn_lock);
236 error = VOP_GETATTR(newvp, vap, flags, cred, ct);
237 VN_RELE(newvp);
238 mutex_enter(&fnp->fn_lock);
239 fnp->fn_seen = 0;
240 fnp->fn_thread = 0;
241 if (fnp->fn_flags & MF_ATTR_WAIT) {
242 fnp->fn_flags &= ~MF_ATTR_WAIT;
243 cv_broadcast(&fnp->fn_cv_mount);
244 }
245 mutex_exit(&fnp->fn_lock);
246 return (error);
247 }
248 } else {
249 vn_vfsunlock(vp);
250 }
251
252 defattr:
253 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
254 vap->va_uid = 0;
255 vap->va_gid = 0;
256 vap->va_nlink = fnp->fn_linkcnt;
257 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid;
258 vap->va_size = fnp->fn_size;
259 vap->va_atime = fnp->fn_atime;
260 vap->va_mtime = fnp->fn_mtime;
261 vap->va_ctime = fnp->fn_ctime;
262 vap->va_type = vp->v_type;
263 vap->va_mode = fnp->fn_mode;
264 vap->va_fsid = vp->v_vfsp->vfs_dev;
265 vap->va_rdev = 0;
266 vap->va_blksize = MAXBSIZE;
267 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
268 vap->va_seq = 0;
269
270 return (0);
271 }
272
273 /*ARGSUSED4*/
274 static int
auto_setattr(vnode_t * vp,struct vattr * vap,int flags,cred_t * cred,caller_context_t * ct)275 auto_setattr(
276 vnode_t *vp,
277 struct vattr *vap,
278 int flags,
279 cred_t *cred,
280 caller_context_t *ct)
281 {
282 vnode_t *newvp;
283 int error;
284
285 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
286
287 if (error = auto_trigger_mount(vp, cred, &newvp))
288 goto done;
289
290 if (newvp != NULL) {
291 /*
292 * Node is mounted on.
293 */
294 if (vn_is_readonly(newvp))
295 error = EROFS;
296 else
297 error = VOP_SETATTR(newvp, vap, flags, cred, ct);
298 VN_RELE(newvp);
299 } else
300 error = ENOSYS;
301
302 done:
303 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error));
304 return (error);
305 }
306
307 /* ARGSUSED */
308 static int
auto_access(vnode_t * vp,int mode,int flags,cred_t * cred,caller_context_t * ct)309 auto_access(
310 vnode_t *vp,
311 int mode,
312 int flags,
313 cred_t *cred,
314 caller_context_t *ct)
315 {
316 fnnode_t *fnp = vntofn(vp);
317 vnode_t *newvp;
318 int error;
319
320 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp));
321
322 if (error = auto_trigger_mount(vp, cred, &newvp))
323 goto done;
324
325 if (newvp != NULL) {
326 /*
327 * Node is mounted on.
328 */
329 error = VOP_ACCESS(newvp, mode, 0, cred, ct);
330 VN_RELE(newvp);
331 } else {
332 int shift = 0;
333
334 /*
335 * really interested in the autofs node, check the
336 * access on it
337 */
338 ASSERT(error == 0);
339 if (crgetuid(cred) != fnp->fn_uid) {
340 shift += 3;
341 if (groupmember(fnp->fn_gid, cred) == 0)
342 shift += 3;
343 }
344 error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid,
345 fnp->fn_mode << shift, mode);
346 }
347
348 done:
349 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error));
350 return (error);
351 }
352
353 static int
auto_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,pathname_t * pnp,int flags,vnode_t * rdir,cred_t * cred,caller_context_t * ct,int * direntflags,pathname_t * realpnp)354 auto_lookup(
355 vnode_t *dvp,
356 char *nm,
357 vnode_t **vpp,
358 pathname_t *pnp,
359 int flags,
360 vnode_t *rdir,
361 cred_t *cred,
362 caller_context_t *ct,
363 int *direntflags,
364 pathname_t *realpnp)
365 {
366 int error = 0;
367 vnode_t *newvp = NULL;
368 vfs_t *vfsp;
369 fninfo_t *dfnip;
370 fnnode_t *dfnp = NULL;
371 fnnode_t *fnp = NULL;
372 char *searchnm;
373 int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
374
375 dfnip = vfstofni(dvp->v_vfsp);
376 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
377 (void *)dvp, dfnip->fi_map, nm));
378
379 if (nm[0] == 0) {
380 VN_HOLD(dvp);
381 *vpp = dvp;
382 return (0);
383 }
384
385 if (error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct))
386 return (error);
387
388 if (nm[0] == '.' && nm[1] == 0) {
389 VN_HOLD(dvp);
390 *vpp = dvp;
391 return (0);
392 }
393
394 if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
395 fnnode_t *pdfnp;
396
397 pdfnp = (vntofn(dvp))->fn_parent;
398 ASSERT(pdfnp != NULL);
399
400 /*
401 * Since it is legitimate to have the VROOT flag set for the
402 * subdirectories of the indirect map in autofs filesystem,
403 * rootfnnodep is checked against fnnode of dvp instead of
404 * just checking whether VROOT flag is set in dvp
405 */
406
407 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
408 vnode_t *vp;
409
410 vfs_rlock_wait(dvp->v_vfsp);
411 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
412 vfs_unlock(dvp->v_vfsp);
413 return (EIO);
414 }
415 vp = dvp->v_vfsp->vfs_vnodecovered;
416 VN_HOLD(vp);
417 vfs_unlock(dvp->v_vfsp);
418 error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred,
419 ct, direntflags, realpnp);
420 VN_RELE(vp);
421 return (error);
422 } else {
423 *vpp = fntovn(pdfnp);
424 VN_HOLD(*vpp);
425 return (0);
426 }
427 }
428
429 top:
430 dfnp = vntofn(dvp);
431 searchnm = nm;
432 operation = 0;
433
434 ASSERT(vn_matchops(dvp, auto_vnodeops));
435
436 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
437 (void *)dfnp));
438
439 /*
440 * If a lookup or mount of this node is in progress, wait for it
441 * to finish, and return whatever result it got.
442 */
443 mutex_enter(&dfnp->fn_lock);
444 if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
445 mutex_exit(&dfnp->fn_lock);
446 error = auto_wait4mount(dfnp);
447 if (error == AUTOFS_SHUTDOWN)
448 error = ENOENT;
449 if (error == EAGAIN)
450 goto top;
451 if (error)
452 return (error);
453 } else
454 mutex_exit(&dfnp->fn_lock);
455
456
457 error = vn_vfsrlock_wait(dvp);
458 if (error)
459 return (error);
460 vfsp = vn_mountedvfs(dvp);
461 if (vfsp != NULL) {
462 error = VFS_ROOT(vfsp, &newvp);
463 vn_vfsunlock(dvp);
464 if (!error) {
465 error = VOP_LOOKUP(newvp, nm, vpp, pnp,
466 flags, rdir, cred, ct, direntflags, realpnp);
467 VN_RELE(newvp);
468 }
469 return (error);
470 }
471 vn_vfsunlock(dvp);
472
473 rw_enter(&dfnp->fn_rwlock, RW_READER);
474 error = auto_search(dfnp, nm, &fnp, cred);
475 if (error) {
476 if (dfnip->fi_flags & MF_DIRECT) {
477 /*
478 * direct map.
479 */
480 if (dfnp->fn_dirents) {
481 /*
482 * Mount previously triggered.
483 * 'nm' not found
484 */
485 error = ENOENT;
486 } else {
487 /*
488 * I need to contact the daemon to trigger
489 * the mount. 'dfnp' will be the mountpoint.
490 */
491 operation = AUTOFS_MOUNT;
492 VN_HOLD(fntovn(dfnp));
493 fnp = dfnp;
494 error = 0;
495 }
496 } else if (dvp == dfnip->fi_rootvp) {
497 /*
498 * 'dfnp' is the root of the indirect AUTOFS.
499 */
500 if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) {
501 /*
502 * Could not acquire writer lock, release
503 * reader, and wait until available. We
504 * need to search for 'nm' again, since we
505 * had to release the lock before reacquiring
506 * it.
507 */
508 rw_exit(&dfnp->fn_rwlock);
509 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
510 error = auto_search(dfnp, nm, &fnp, cred);
511 }
512
513 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
514 if (error) {
515 /*
516 * create node being looked-up and request
517 * mount on it.
518 */
519 error = auto_enter(dfnp, nm, &fnp, kcred);
520 if (!error)
521 operation = AUTOFS_LOOKUP;
522 }
523 } else if ((dfnp->fn_dirents == NULL) &&
524 ((dvp->v_flag & VROOT) == 0) &&
525 ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) {
526 /*
527 * dfnp is the actual 'mountpoint' of indirect map,
528 * it is the equivalent of a direct mount,
529 * ie, /home/'user1'
530 */
531 operation = AUTOFS_MOUNT;
532 VN_HOLD(fntovn(dfnp));
533 fnp = dfnp;
534 error = 0;
535 searchnm = dfnp->fn_name;
536 }
537 }
538
539 if (error == EAGAIN) {
540 rw_exit(&dfnp->fn_rwlock);
541 goto top;
542 }
543 if (error) {
544 rw_exit(&dfnp->fn_rwlock);
545 return (error);
546 }
547
548 /*
549 * We now have the actual fnnode we're interested in.
550 * The 'MF_LOOKUP' indicates another thread is currently
551 * performing a daemon lookup of this node, therefore we
552 * wait for its completion.
553 * The 'MF_INPROG' indicates another thread is currently
554 * performing a daemon mount of this node, we wait for it
555 * to be done if we are performing a MOUNT. We don't
556 * wait for it if we are performing a LOOKUP.
557 * We can release the reader/writer lock as soon as we acquire
558 * the mutex, since the state of the lock can only change by
559 * first acquiring the mutex.
560 */
561 mutex_enter(&fnp->fn_lock);
562 rw_exit(&dfnp->fn_rwlock);
563 if ((fnp->fn_flags & MF_LOOKUP) ||
564 ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) {
565 mutex_exit(&fnp->fn_lock);
566 error = auto_wait4mount(fnp);
567 VN_RELE(fntovn(fnp));
568 if (error == AUTOFS_SHUTDOWN)
569 error = ENOENT;
570 if (error && error != EAGAIN)
571 return (error);
572 goto top;
573 }
574
575 if (operation == 0) {
576 /*
577 * got the fnnode, check for any errors
578 * on the previous operation on that node.
579 */
580 error = fnp->fn_error;
581 if ((error == EINTR) || (error == EAGAIN)) {
582 /*
583 * previous operation on this node was
584 * not completed, do a lookup now.
585 */
586 operation = AUTOFS_LOOKUP;
587 } else {
588 /*
589 * previous operation completed. Return
590 * a pointer to the node only if there was
591 * no error.
592 */
593 mutex_exit(&fnp->fn_lock);
594 if (!error)
595 *vpp = fntovn(fnp);
596 else
597 VN_RELE(fntovn(fnp));
598 return (error);
599 }
600 }
601
602 /*
603 * Since I got to this point, it means I'm the one
604 * responsible for triggering the mount/look-up of this node.
605 */
606 switch (operation) {
607 case AUTOFS_LOOKUP:
608 AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP);
609 fnp->fn_error = 0;
610 mutex_exit(&fnp->fn_lock);
611 error = auto_lookup_aux(fnp, searchnm, cred);
612 if (!error) {
613 /*
614 * Return this vnode
615 */
616 *vpp = fntovn(fnp);
617 } else {
618 /*
619 * release our reference to this vnode
620 * and return error
621 */
622 VN_RELE(fntovn(fnp));
623 }
624 break;
625 case AUTOFS_MOUNT:
626 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
627 fnp->fn_error = 0;
628 mutex_exit(&fnp->fn_lock);
629 /*
630 * auto_new_mount_thread fires up a new thread which
631 * calls automountd finishing up the work
632 */
633 auto_new_mount_thread(fnp, searchnm, cred);
634
635 /*
636 * At this point, we are simply another thread
637 * waiting for the mount to complete
638 */
639 error = auto_wait4mount(fnp);
640 if (error == AUTOFS_SHUTDOWN)
641 error = ENOENT;
642
643 /*
644 * now release our reference to this vnode
645 */
646 VN_RELE(fntovn(fnp));
647 if (!error)
648 goto top;
649 break;
650 default:
651 auto_log(dfnp->fn_globals->fng_verbose,
652 dfnp->fn_globals->fng_zoneid, CE_WARN,
653 "auto_lookup: unknown operation %d",
654 operation);
655 }
656
657 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
658 nm, (void *)*vpp, error));
659
660 return (error);
661 }
662
663 static int
auto_create(vnode_t * dvp,char * nm,vattr_t * va,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cred,int flag,caller_context_t * ct,vsecattr_t * vsecp)664 auto_create(
665 vnode_t *dvp,
666 char *nm,
667 vattr_t *va,
668 vcexcl_t excl,
669 int mode,
670 vnode_t **vpp,
671 cred_t *cred,
672 int flag,
673 caller_context_t *ct,
674 vsecattr_t *vsecp)
675 {
676 vnode_t *newvp;
677 int error;
678
679 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm));
680
681 if (error = auto_trigger_mount(dvp, cred, &newvp))
682 goto done;
683
684 if (newvp != NULL) {
685 /*
686 * Node is now mounted on.
687 */
688 if (vn_is_readonly(newvp))
689 error = EROFS;
690 else
691 error = VOP_CREATE(newvp, nm, va, excl,
692 mode, vpp, cred, flag, ct, vsecp);
693 VN_RELE(newvp);
694 } else
695 error = ENOSYS;
696
697 done:
698 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
699 return (error);
700 }
701
702 static int
auto_remove(vnode_t * dvp,char * nm,cred_t * cred,caller_context_t * ct,int flags)703 auto_remove(
704 vnode_t *dvp,
705 char *nm,
706 cred_t *cred,
707 caller_context_t *ct,
708 int flags)
709 {
710 vnode_t *newvp;
711 int error;
712
713 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm));
714
715 if (error = auto_trigger_mount(dvp, cred, &newvp))
716 goto done;
717
718 if (newvp != NULL) {
719 /*
720 * Node is now mounted on.
721 */
722 if (vn_is_readonly(newvp))
723 error = EROFS;
724 else
725 error = VOP_REMOVE(newvp, nm, cred, ct, flags);
726 VN_RELE(newvp);
727 } else
728 error = ENOSYS;
729
730 done:
731 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error));
732 return (error);
733 }
734
735 static int
auto_link(vnode_t * tdvp,vnode_t * svp,char * nm,cred_t * cred,caller_context_t * ct,int flags)736 auto_link(
737 vnode_t *tdvp,
738 vnode_t *svp,
739 char *nm,
740 cred_t *cred,
741 caller_context_t *ct,
742 int flags)
743 {
744 vnode_t *newvp;
745 int error;
746
747 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
748 (void *)svp, nm));
749
750 if (error = auto_trigger_mount(tdvp, cred, &newvp))
751 goto done;
752
753 if (newvp == NULL) {
754 /*
755 * an autonode can not be a link to another node
756 */
757 error = ENOSYS;
758 goto done;
759 }
760
761 if (vn_is_readonly(newvp)) {
762 error = EROFS;
763 VN_RELE(newvp);
764 goto done;
765 }
766
767 if (vn_matchops(svp, auto_vnodeops)) {
768 /*
769 * source vp can't be an autonode
770 */
771 error = ENOSYS;
772 VN_RELE(newvp);
773 goto done;
774 }
775
776 error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
777 VN_RELE(newvp);
778
779 done:
780 AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
781 return (error);
782 }
783
784 static int
auto_rename(vnode_t * odvp,char * onm,vnode_t * ndvp,char * nnm,cred_t * cr,caller_context_t * ct,int flags)785 auto_rename(
786 vnode_t *odvp,
787 char *onm,
788 vnode_t *ndvp,
789 char *nnm,
790 cred_t *cr,
791 caller_context_t *ct,
792 int flags)
793 {
794 vnode_t *o_newvp, *n_newvp;
795 int error;
796
797 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
798 (void *)odvp, onm, (void *)ndvp, nnm));
799
800 /*
801 * we know odvp is an autonode, otherwise this function
802 * could not have ever been called.
803 */
804 ASSERT(vn_matchops(odvp, auto_vnodeops));
805
806 if (error = auto_trigger_mount(odvp, cr, &o_newvp))
807 goto done;
808
809 if (o_newvp == NULL) {
810 /*
811 * can't rename an autonode
812 */
813 error = ENOSYS;
814 goto done;
815 }
816
817 if (vn_matchops(ndvp, auto_vnodeops)) {
818 /*
819 * directory is AUTOFS, need to trigger the
820 * mount of the real filesystem.
821 */
822 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) {
823 VN_RELE(o_newvp);
824 goto done;
825 }
826
827 if (n_newvp == NULL) {
828 /*
829 * target can't be an autonode
830 */
831 error = ENOSYS;
832 VN_RELE(o_newvp);
833 goto done;
834 }
835 } else {
836 /*
837 * destination directory mount had been
838 * triggered prior to the call to this function.
839 */
840 n_newvp = ndvp;
841 }
842
843 ASSERT(!vn_matchops(n_newvp, auto_vnodeops));
844
845 if (vn_is_readonly(n_newvp)) {
846 error = EROFS;
847 VN_RELE(o_newvp);
848 if (n_newvp != ndvp)
849 VN_RELE(n_newvp);
850 goto done;
851 }
852
853 error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
854 VN_RELE(o_newvp);
855 if (n_newvp != ndvp)
856 VN_RELE(n_newvp);
857
858 done:
859 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error));
860 return (error);
861 }
862
863 static int
auto_mkdir(vnode_t * dvp,char * nm,vattr_t * va,vnode_t ** vpp,cred_t * cred,caller_context_t * ct,int flags,vsecattr_t * vsecp)864 auto_mkdir(
865 vnode_t *dvp,
866 char *nm,
867 vattr_t *va,
868 vnode_t **vpp,
869 cred_t *cred,
870 caller_context_t *ct,
871 int flags,
872 vsecattr_t *vsecp)
873 {
874 vnode_t *newvp;
875 int error;
876
877 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));
878
879 if (error = auto_trigger_mount(dvp, cred, &newvp))
880 goto done;
881
882 if (newvp != NULL) {
883 /*
884 * Node is now mounted on.
885 */
886 if (vn_is_readonly(newvp))
887 error = EROFS;
888 else
889 error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
890 flags, vsecp);
891 VN_RELE(newvp);
892 } else
893 error = ENOSYS;
894
895 done:
896 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
897 return (error);
898 }
899
900 static int
auto_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,cred_t * cred,caller_context_t * ct,int flags)901 auto_rmdir(
902 vnode_t *dvp,
903 char *nm,
904 vnode_t *cdir,
905 cred_t *cred,
906 caller_context_t *ct,
907 int flags)
908 {
909 vnode_t *newvp;
910 int error;
911
912 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm));
913
914 if (error = auto_trigger_mount(dvp, cred, &newvp))
915 goto done;
916
917 if (newvp != NULL) {
918 /*
919 * Node is now mounted on.
920 */
921 if (vn_is_readonly(newvp))
922 error = EROFS;
923 else
924 error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags);
925 VN_RELE(newvp);
926 } else
927 error = ENOSYS;
928
929 done:
930 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error));
931 return (error);
932 }
933
934 static int autofs_nobrowse = 0;
935
936 #ifdef nextdp
937 #undef nextdp
938 #endif
939 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
940
941 /* ARGSUSED */
942 static int
auto_readdir(vnode_t * vp,uio_t * uiop,cred_t * cred,int * eofp,caller_context_t * ct,int flags)943 auto_readdir(
944 vnode_t *vp,
945 uio_t *uiop,
946 cred_t *cred,
947 int *eofp,
948 caller_context_t *ct,
949 int flags)
950 {
951 struct autofs_rddirargs rda;
952 autofs_rddirres rd;
953 fnnode_t *fnp = vntofn(vp);
954 fnnode_t *cfnp, *nfnp;
955 dirent64_t *dp;
956 ulong_t offset;
957 ulong_t outcount = 0, count = 0;
958 size_t namelen;
959 ulong_t alloc_count;
960 void *outbuf = NULL;
961 fninfo_t *fnip = vfstofni(vp->v_vfsp);
962 struct iovec *iovp;
963 int error = 0;
964 int reached_max = 0;
965 int myeof = 0;
966 int this_reclen;
967 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
968
969 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
970 (void *)vp, uiop->uio_loffset));
971
972 if (eofp != NULL)
973 *eofp = 0;
974
975 if (uiop->uio_iovcnt != 1)
976 return (EINVAL);
977
978 iovp = uiop->uio_iov;
979 alloc_count = iovp->iov_len;
980
981 gethrestime(&fnp->fn_atime);
982 fnp->fn_ref_time = fnp->fn_atime.tv_sec;
983
984 dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP);
985
986 /*
987 * Held when getdents calls VOP_RWLOCK....
988 */
989 ASSERT(RW_READ_HELD(&fnp->fn_rwlock));
990 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) {
991 again:
992 /*
993 * Do readdir of daemon contents only
994 * Drop readers lock and reacquire after reply.
995 */
996 rw_exit(&fnp->fn_rwlock);
997 bzero(&rd, sizeof (struct autofs_rddirres));
998 count = 0;
999 rda.rda_map = fnip->fi_map;
1000 rda.rda_offset = (uint_t)uiop->uio_offset;
1001 rd.rd_rddir.rddir_entries = dp;
1002 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count;
1003 rda.uid = crgetuid(cred);
1004
1005 error = auto_calldaemon(fngp->fng_zoneid,
1006 AUTOFS_READDIR,
1007 xdr_autofs_rddirargs,
1008 &rda,
1009 xdr_autofs_rddirres,
1010 (void *)&rd,
1011 sizeof (autofs_rddirres),
1012 TRUE);
1013
1014 /*
1015 * reacquire previously dropped lock
1016 */
1017 rw_enter(&fnp->fn_rwlock, RW_READER);
1018
1019 if (!error) {
1020 error = rd.rd_status;
1021 dp = rd.rd_rddir.rddir_entries;
1022 }
1023
1024 if (error) {
1025 if (error == AUTOFS_SHUTDOWN) {
1026 /*
1027 * treat as empty directory
1028 */
1029 error = 0;
1030 myeof = 1;
1031 if (eofp)
1032 *eofp = 1;
1033 }
1034 goto done;
1035 }
1036 if (rd.rd_rddir.rddir_size) {
1037 dirent64_t *odp = dp; /* next in output buffer */
1038 dirent64_t *cdp = dp; /* current examined entry */
1039
1040 /*
1041 * Check for duplicates here
1042 */
1043 do {
1044 this_reclen = cdp->d_reclen;
1045 if (auto_search(fnp, cdp->d_name,
1046 NULL, cred)) {
1047 /*
1048 * entry not found in kernel list,
1049 * include it in readdir output.
1050 *
1051 * If we are skipping entries. then
1052 * we need to copy this entry to the
1053 * correct position in the buffer
1054 * to be copied out.
1055 */
1056 if (cdp != odp)
1057 bcopy(cdp, odp,
1058 (size_t)this_reclen);
1059 odp = nextdp(odp);
1060 outcount += this_reclen;
1061 } else {
1062 /*
1063 * Entry was found in the kernel
1064 * list. If it is the first entry
1065 * in this buffer, then just skip it
1066 */
1067 if (odp == dp) {
1068 dp = nextdp(dp);
1069 odp = dp;
1070 }
1071 }
1072 count += this_reclen;
1073 cdp = (struct dirent64 *)
1074 ((char *)cdp + this_reclen);
1075 } while (count < rd.rd_rddir.rddir_size);
1076
1077 if (outcount)
1078 error = uiomove(dp, outcount, UIO_READ, uiop);
1079 uiop->uio_offset = rd.rd_rddir.rddir_offset;
1080 } else {
1081 if (rd.rd_rddir.rddir_eof == 0) {
1082 /*
1083 * alloc_count not large enough for one
1084 * directory entry
1085 */
1086 error = EINVAL;
1087 }
1088 }
1089 if (rd.rd_rddir.rddir_eof && !error) {
1090 myeof = 1;
1091 if (eofp)
1092 *eofp = 1;
1093 }
1094 if (!error && !myeof && outcount == 0) {
1095 /*
1096 * call daemon with new cookie, all previous
1097 * elements happened to be duplicates
1098 */
1099 dp = outbuf;
1100 goto again;
1101 }
1102 goto done;
1103 }
1104
1105 if (uiop->uio_offset == 0) {
1106 /*
1107 * first time: so fudge the . and ..
1108 */
1109 this_reclen = DIRENT64_RECLEN(1);
1110 if (alloc_count < this_reclen) {
1111 error = EINVAL;
1112 goto done;
1113 }
1114 dp->d_ino = (ino64_t)fnp->fn_nodeid;
1115 dp->d_off = (off64_t)1;
1116 dp->d_reclen = (ushort_t)this_reclen;
1117
1118 /* use strncpy(9f) to zero out uninitialized bytes */
1119
1120 (void) strncpy(dp->d_name, ".",
1121 DIRENT64_NAMELEN(this_reclen));
1122 outcount += dp->d_reclen;
1123 dp = nextdp(dp);
1124
1125 this_reclen = DIRENT64_RECLEN(2);
1126 if (alloc_count < outcount + this_reclen) {
1127 error = EINVAL;
1128 goto done;
1129 }
1130 dp->d_reclen = (ushort_t)this_reclen;
1131 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid;
1132 dp->d_off = (off64_t)2;
1133
1134 /* use strncpy(9f) to zero out uninitialized bytes */
1135
1136 (void) strncpy(dp->d_name, "..",
1137 DIRENT64_NAMELEN(this_reclen));
1138 outcount += dp->d_reclen;
1139 dp = nextdp(dp);
1140 }
1141
1142 offset = 2;
1143 cfnp = fnp->fn_dirents;
1144 while (cfnp != NULL) {
1145 nfnp = cfnp->fn_next;
1146 offset = cfnp->fn_offset;
1147 if ((offset >= uiop->uio_offset) &&
1148 (!(cfnp->fn_flags & MF_LOOKUP))) {
1149 int reclen;
1150
1151 /*
1152 * include node only if its offset is greater or
1153 * equal to the one required and it is not in
1154 * transient state (not being looked-up)
1155 */
1156 namelen = strlen(cfnp->fn_name);
1157 reclen = (int)DIRENT64_RECLEN(namelen);
1158 if (outcount + reclen > alloc_count) {
1159 reached_max = 1;
1160 break;
1161 }
1162 dp->d_reclen = (ushort_t)reclen;
1163 dp->d_ino = (ino64_t)cfnp->fn_nodeid;
1164 if (nfnp != NULL) {
1165 /*
1166 * get the offset of the next element
1167 */
1168 dp->d_off = (off64_t)nfnp->fn_offset;
1169 } else {
1170 /*
1171 * This is the last element, make
1172 * offset one plus the current
1173 */
1174 dp->d_off = (off64_t)cfnp->fn_offset + 1;
1175 }
1176
1177 /* use strncpy(9f) to zero out uninitialized bytes */
1178
1179 (void) strncpy(dp->d_name, cfnp->fn_name,
1180 DIRENT64_NAMELEN(reclen));
1181 outcount += dp->d_reclen;
1182 dp = nextdp(dp);
1183 }
1184 cfnp = nfnp;
1185 }
1186
1187 if (outcount)
1188 error = uiomove(outbuf, outcount, UIO_READ, uiop);
1189
1190 if (!error) {
1191 if (reached_max) {
1192 /*
1193 * This entry did not get added to the buffer on this,
1194 * call. We need to add it on the next call therefore
1195 * set uio_offset to this entry's offset. If there
1196 * wasn't enough space for one dirent, return EINVAL.
1197 */
1198 uiop->uio_offset = offset;
1199 if (outcount == 0)
1200 error = EINVAL;
1201 } else if (autofs_nobrowse ||
1202 auto_nobrowse_option(fnip->fi_opts) ||
1203 (fnip->fi_flags & MF_DIRECT) ||
1204 (fnp->fn_trigger != NULL) ||
1205 (((vp->v_flag & VROOT) == 0) &&
1206 ((fntovn(fnp->fn_parent))->v_flag & VROOT) &&
1207 (fnp->fn_dirents == NULL))) {
1208 /*
1209 * done reading directory entries
1210 */
1211 uiop->uio_offset = offset + 1;
1212 if (eofp)
1213 *eofp = 1;
1214 } else {
1215 /*
1216 * Need to get the rest of the entries from the daemon.
1217 */
1218 uiop->uio_offset = AUTOFS_DAEMONCOOKIE;
1219 }
1220 }
1221
1222 done:
1223 kmem_free(outbuf, alloc_count);
1224 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1225 (void *)vp, uiop->uio_loffset, myeof));
1226 return (error);
1227 }
1228
1229 static int
auto_symlink(vnode_t * dvp,char * lnknm,vattr_t * tva,char * tnm,cred_t * cred,caller_context_t * ct,int flags)1230 auto_symlink(
1231 vnode_t *dvp,
1232 char *lnknm, /* new entry */
1233 vattr_t *tva,
1234 char *tnm, /* existing entry */
1235 cred_t *cred,
1236 caller_context_t *ct,
1237 int flags)
1238 {
1239 vnode_t *newvp;
1240 int error;
1241
1242 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1243 (void *)dvp, lnknm, tnm));
1244
1245 if (error = auto_trigger_mount(dvp, cred, &newvp))
1246 goto done;
1247
1248 if (newvp != NULL) {
1249 /*
1250 * Node is mounted on.
1251 */
1252 if (vn_is_readonly(newvp))
1253 error = EROFS;
1254 else
1255 error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred,
1256 ct, flags);
1257 VN_RELE(newvp);
1258 } else
1259 error = ENOSYS;
1260
1261 done:
1262 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error));
1263 return (error);
1264 }
1265
1266 /* ARGSUSED */
1267 static int
auto_readlink(vnode_t * vp,struct uio * uiop,cred_t * cr,caller_context_t * ct)1268 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
1269 {
1270 fnnode_t *fnp = vntofn(vp);
1271 int error;
1272 timestruc_t now;
1273
1274 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
1275
1276 gethrestime(&now);
1277 fnp->fn_ref_time = now.tv_sec;
1278
1279 if (vp->v_type != VLNK)
1280 error = EINVAL;
1281 else {
1282 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP)));
1283 fnp->fn_atime = now;
1284 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
1285 uiop->uio_resid), UIO_READ, uiop);
1286 }
1287
1288 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
1289 return (error);
1290 }
1291
1292 /* ARGSUSED */
1293 static int
auto_fsync(vnode_t * cp,int syncflag,cred_t * cred,caller_context_t * ct)1294 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
1295 {
1296 return (0);
1297 }
1298
1299 /* ARGSUSED */
1300 static void
auto_inactive(vnode_t * vp,cred_t * cred,caller_context_t * ct)1301 auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
1302 {
1303 fnnode_t *fnp = vntofn(vp);
1304 fnnode_t *dfnp = fnp->fn_parent;
1305 int count;
1306
1307 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1308 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1309
1310 /*
1311 * The rwlock should not be already held by this thread.
1312 * The assert relies on the fact that the owner field is cleared
1313 * when the lock is released.
1314 */
1315 ASSERT(dfnp != NULL);
1316 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread);
1317 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1318 mutex_enter(&vp->v_lock);
1319 ASSERT(vp->v_count > 0);
1320 VN_RELE_LOCKED(vp);
1321 count = vp->v_count;
1322 mutex_exit(&vp->v_lock);
1323 if (count == 0) {
1324 /*
1325 * Free only if node has no subdirectories.
1326 */
1327 if (fnp->fn_linkcnt == 1) {
1328 auto_disconnect(dfnp, fnp);
1329 rw_exit(&dfnp->fn_rwlock);
1330 auto_freefnnode(fnp);
1331 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1332 (void *)vp));
1333 return;
1334 }
1335 }
1336 rw_exit(&dfnp->fn_rwlock);
1337
1338 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1339 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1340 }
1341
1342 /* ARGSUSED2 */
1343 static int
auto_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)1344 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1345 {
1346 fnnode_t *fnp = vntofn(vp);
1347 if (write_lock)
1348 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1349 else
1350 rw_enter(&fnp->fn_rwlock, RW_READER);
1351 return (write_lock);
1352 }
1353
1354 /* ARGSUSED */
1355 static void
auto_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)1356 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1357 {
1358 fnnode_t *fnp = vntofn(vp);
1359 rw_exit(&fnp->fn_rwlock);
1360 }
1361
1362
1363 /* ARGSUSED */
1364 static int
auto_seek(struct vnode * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)1365 auto_seek(
1366 struct vnode *vp,
1367 offset_t ooff,
1368 offset_t *noffp,
1369 caller_context_t *ct)
1370 {
1371 /*
1372 * Return 0 unconditionally, since we expect
1373 * a VDIR all the time
1374 */
1375 return (0);
1376 }
1377
1378 /*
1379 * Triggers the mount if needed. If the mount has been triggered by
1380 * another thread, it will wait for its return status, and return it.
1381 * Whether the mount is triggered by this thread, another thread, or
1382 * if the vnode was already covered, '*newvp' is a
1383 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1384 * If the node is not mounted on, and should not be mounted on, '*newvp'
1385 * will be NULL.
1386 * The calling routine may use '*newvp' to do the filesystem jump.
1387 */
1388 static int
auto_trigger_mount(vnode_t * vp,cred_t * cred,vnode_t ** newvp)1389 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp)
1390 {
1391 fnnode_t *fnp = vntofn(vp);
1392 fninfo_t *fnip = vfstofni(vp->v_vfsp);
1393 vnode_t *dvp;
1394 vfs_t *vfsp;
1395 int delayed_ind;
1396 char name[AUTOFS_MAXPATHLEN];
1397 int error;
1398
1399 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp));
1400
1401 *newvp = NULL;
1402
1403 /*
1404 * Cross-zone mount triggering is disallowed.
1405 */
1406 if (fnip->fi_zoneid != getzoneid())
1407 return (EPERM); /* Not owner of mount */
1408
1409 retry:
1410 error = 0;
1411 delayed_ind = 0;
1412 mutex_enter(&fnp->fn_lock);
1413 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
1414 /*
1415 * Mount or lookup in progress,
1416 * wait for it before proceeding.
1417 */
1418 mutex_exit(&fnp->fn_lock);
1419 error = auto_wait4mount(fnp);
1420 if (error == AUTOFS_SHUTDOWN) {
1421 error = 0;
1422 goto done;
1423 }
1424 if (error && error != EAGAIN)
1425 goto done;
1426 error = 0;
1427 mutex_enter(&fnp->fn_lock);
1428 }
1429
1430 /*
1431 * If the vfslock can't be acquired for the first time.
1432 * drop the fn_lock and retry next time in blocking mode.
1433 */
1434 if (vn_vfswlock(vp)) {
1435 /*
1436 * Lock held by another thread.
1437 * Perform blocking by dropping the
1438 * fn_lock.
1439 */
1440 mutex_exit(&fnp->fn_lock);
1441 error = vn_vfswlock_wait(vp);
1442 if (error)
1443 goto done;
1444 /*
1445 * Because fn_lock wasn't held, the state
1446 * of the trigger node might have changed.
1447 * Need to run through the checks on trigger
1448 * node again.
1449 */
1450 vn_vfsunlock(vp);
1451 goto retry;
1452 }
1453
1454 vfsp = vn_mountedvfs(vp);
1455 if (vfsp != NULL) {
1456 mutex_exit(&fnp->fn_lock);
1457 error = VFS_ROOT(vfsp, newvp);
1458 vn_vfsunlock(vp);
1459 goto done;
1460 } else {
1461 vn_vfsunlock(vp);
1462 if ((fnp->fn_flags & MF_MOUNTPOINT) &&
1463 fnp->fn_trigger != NULL) {
1464 ASSERT(fnp->fn_dirents == NULL);
1465 mutex_exit(&fnp->fn_lock);
1466 /*
1467 * The filesystem that used to sit here has been
1468 * forcibly unmounted. Do our best to recover.
1469 * Try to unmount autofs subtree below this node
1470 * and retry the action.
1471 */
1472 if (unmount_subtree(fnp, B_TRUE) != 0) {
1473 error = EIO;
1474 goto done;
1475 }
1476 goto retry;
1477 }
1478 }
1479
1480 ASSERT(vp->v_type == VDIR);
1481 dvp = fntovn(fnp->fn_parent);
1482
1483 if ((fnp->fn_dirents == NULL) &&
1484 ((fnip->fi_flags & MF_DIRECT) == 0) &&
1485 ((vp->v_flag & VROOT) == 0) &&
1486 (dvp->v_flag & VROOT)) {
1487 /*
1488 * If the parent of this node is the root of an indirect
1489 * AUTOFS filesystem, this node is remountable.
1490 */
1491 delayed_ind = 1;
1492 }
1493
1494 if (delayed_ind ||
1495 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) {
1496 /*
1497 * Trigger mount since:
1498 * direct mountpoint with no subdirs or
1499 * delayed indirect.
1500 */
1501 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
1502 fnp->fn_error = 0;
1503 mutex_exit(&fnp->fn_lock);
1504 if (delayed_ind)
1505 (void) strcpy(name, fnp->fn_name);
1506 else
1507 (void) strcpy(name, ".");
1508 fnp->fn_ref_time = gethrestime_sec();
1509 auto_new_mount_thread(fnp, name, cred);
1510 /*
1511 * At this point we're simply another thread waiting
1512 * for the mount to finish.
1513 */
1514 error = auto_wait4mount(fnp);
1515 if (error == EAGAIN)
1516 goto retry;
1517 if (error == AUTOFS_SHUTDOWN) {
1518 error = 0;
1519 goto done;
1520 }
1521 if (error == 0) {
1522 if (error = vn_vfsrlock_wait(vp))
1523 goto done;
1524 /* Reacquire after dropping locks */
1525 vfsp = vn_mountedvfs(vp);
1526 if (vfsp != NULL) {
1527 error = VFS_ROOT(vfsp, newvp);
1528 vn_vfsunlock(vp);
1529 } else {
1530 vn_vfsunlock(vp);
1531 goto retry;
1532 }
1533 }
1534 } else
1535 mutex_exit(&fnp->fn_lock);
1536
1537 done:
1538 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error));
1539 return (error);
1540 }
1541