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]
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
26 #include <sys/param.h>
27 #include <sys/errno.h>
31 #include <sys/vfs_opreg.h>
32 #include <sys/vnode.h>
36 #include <sys/statvfs.h>
37 #include <sys/mount.h>
38 #include <sys/tiuser.h>
39 #include <sys/cmn_err.h>
40 #include <sys/debug.h>
41 #include <sys/systm.h>
42 #include <sys/sysmacros.h>
43 #include <sys/pathname.h>
44 #include <rpc/types.h>
47 #include <sys/fs_subr.h>
48 #include <sys/fs/autofs.h>
49 #include <sys/modctl.h>
50 #include <sys/mntent.h>
51 #include <sys/policy.h>
54 static int autofs_init(int, char *);
56 static major_t autofs_major
;
57 static minor_t autofs_minor
;
59 kmutex_t autofs_minor_lock
;
60 zone_key_t autofs_key
;
62 static mntopts_t auto_mntopts
;
65 * The AUTOFS system call.
67 static struct sysent autofssysent
= {
69 SE_32RVAL1
| SE_ARGC
| SE_NOUNLOAD
,
73 static struct modlsys modlsys
= {
79 #ifdef _SYSCALL32_IMPL
80 static struct modlsys modlsys32
= {
82 "AUTOFS syscall (32-bit)",
85 #endif /* _SYSCALL32_IMPL */
87 static vfsdef_t vfw
= {
91 VSW_HASPROTO
|VSW_CANRWRO
|VSW_CANREMOUNT
|VSW_STATS
|VSW_ZMOUNT
,
96 * Module linkage information for the kernel.
98 static struct modlfs modlfs
= {
99 &mod_fsops
, "filesystem for autofs", &vfw
102 static struct modlinkage modlinkage
= {
106 #ifdef _SYSCALL32_IMPL
113 * This is the module initialization routine.
118 return (mod_install(&modlinkage
));
125 * Don't allow the autofs module to be unloaded for now.
131 _info(struct modinfo
*modinfop
)
133 return (mod_info(&modlinkage
, modinfop
));
136 static int autofs_fstype
;
139 * autofs VFS operations
141 static int auto_mount(vfs_t
*, vnode_t
*, struct mounta
*, cred_t
*);
142 static int auto_unmount(vfs_t
*, int, cred_t
*);
143 static int auto_root(vfs_t
*, vnode_t
**);
144 static int auto_statvfs(vfs_t
*, struct statvfs64
*);
147 * Auto Mount options table
150 static char *direct_cancel
[] = { MNTOPT_INDIRECT
, NULL
};
151 static char *indirect_cancel
[] = { MNTOPT_DIRECT
, NULL
};
152 static char *browse_cancel
[] = { MNTOPT_NOBROWSE
, NULL
};
153 static char *nobrowse_cancel
[] = { MNTOPT_BROWSE
, NULL
};
155 static mntopt_t mntopts
[] = {
157 * option name cancel options default arg flags
159 { MNTOPT_DIRECT
, direct_cancel
, NULL
, 0,
161 { MNTOPT_INDIRECT
, indirect_cancel
, NULL
, 0,
163 { MNTOPT_IGNORE
, NULL
, NULL
,
164 MO_DEFAULT
|MO_TAG
, NULL
},
165 { "nest", NULL
, NULL
, MO_TAG
,
167 { MNTOPT_BROWSE
, browse_cancel
, NULL
, MO_TAG
,
169 { MNTOPT_NOBROWSE
, nobrowse_cancel
, NULL
, MO_TAG
,
171 { MNTOPT_RESTRICT
, NULL
, NULL
, MO_TAG
,
175 static mntopts_t auto_mntopts
= {
176 sizeof (mntopts
) / sizeof (mntopt_t
),
182 autofs_zone_destructor(zoneid_t zoneid
, void *arg
)
184 struct autofs_globals
*fngp
= arg
;
189 ASSERT(fngp
->fng_fnnode_count
== 1);
190 ASSERT(fngp
->fng_unmount_threads
== 0);
192 if (fngp
->fng_autofs_daemon_dh
!= NULL
)
193 door_ki_rele(fngp
->fng_autofs_daemon_dh
);
195 * vn_alloc() initialized the rootnode with a count of 1; we need to
196 * make this 0 to placate auto_freefnnode().
198 vp
= fntovn(fngp
->fng_rootfnnodep
);
199 ASSERT(vp
->v_count
== 1);
201 auto_freefnnode(fngp
->fng_rootfnnodep
);
202 mutex_destroy(&fngp
->fng_unmount_threads_lock
);
203 kmem_free(fngp
, sizeof (*fngp
));
207 * rootfnnodep is allocated here. Its sole purpose is to provide
208 * read/write locking for top level fnnodes. This object is
209 * persistent and will not be deallocated until the zone is destroyed.
211 * The current zone is implied as the zone of interest, since we will be
212 * calling zthread_create() which must be called from the correct zone.
214 struct autofs_globals
*
215 autofs_zone_init(void)
217 char rootname
[sizeof ("root_fnnode_zone_") + ZONEID_WIDTH
];
218 struct autofs_globals
*fngp
;
219 zoneid_t zoneid
= getzoneid();
221 fngp
= kmem_zalloc(sizeof (*fngp
), KM_SLEEP
);
222 (void) snprintf(rootname
, sizeof (rootname
), "root_fnnode_zone_%d",
224 fngp
->fng_rootfnnodep
= auto_makefnnode(VNON
, NULL
, rootname
, CRED(),
227 * Don't need to hold fng_rootfnnodep as it's never really used for
230 fngp
->fng_fnnode_count
= 1;
231 fngp
->fng_printed_not_running_msg
= 0;
232 fngp
->fng_zoneid
= zoneid
;
233 mutex_init(&fngp
->fng_unmount_threads_lock
, NULL
, MUTEX_DEFAULT
,
235 fngp
->fng_unmount_threads
= 0;
237 mutex_init(&fngp
->fng_autofs_daemon_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
240 * Start the unmounter thread for this zone.
242 (void) zthread_create(NULL
, 0, auto_do_unmount
, fngp
, 0, minclsyspri
);
247 autofs_init(int fstype
, char *name
)
249 static const fs_operation_def_t auto_vfsops_template
[] = {
250 VFSNAME_MOUNT
, { .vfs_mount
= auto_mount
},
251 VFSNAME_UNMOUNT
, { .vfs_unmount
= auto_unmount
},
252 VFSNAME_ROOT
, { .vfs_root
= auto_root
},
253 VFSNAME_STATVFS
, { .vfs_statvfs
= auto_statvfs
},
258 autofs_fstype
= fstype
;
259 ASSERT(autofs_fstype
!= 0);
261 * Associate VFS ops vector with this fstype
263 error
= vfs_setfsops(fstype
, auto_vfsops_template
, NULL
);
265 cmn_err(CE_WARN
, "autofs_init: bad vfs ops template");
269 error
= vn_make_ops(name
, auto_vnodeops_template
, &auto_vnodeops
);
271 (void) vfs_freevfsops_by_type(fstype
);
272 cmn_err(CE_WARN
, "autofs_init: bad vnode ops template");
276 mutex_init(&autofs_minor_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
278 * Assign unique major number for all autofs mounts
280 if ((autofs_major
= getudev()) == (major_t
)-1) {
282 "autofs: autofs_init: can't get unique device number");
283 mutex_destroy(&autofs_minor_lock
);
288 * We'd like to be able to provide a constructor here, but we can't
289 * since it wants to zthread_create(), something it can't do in a ZSD
292 zone_key_create(&autofs_key
, NULL
, NULL
, autofs_zone_destructor
);
297 static char *restropts
[] = {
302 * This routine adds those options to the option string `buf' which are
303 * forced by secpolicy_fs_mount. If the automatic "security" options
304 * are set, the option string gets them added if they aren't already
305 * there. We search the string with "strstr" and make sure that
306 * the string we find is bracketed with <start|",">MNTOPT<","|"\0">
308 * This is one half of the option inheritence algorithm which
309 * implements the "restrict" option. The other half is implemented
310 * in automountd; it takes its cue from the options we add here.
313 autofs_restrict_opts(struct vfs
*vfsp
, char *buf
, size_t maxlen
, size_t *curlen
)
317 size_t len
= *curlen
- 1;
320 if (!vfs_optionisset(vfsp
, restropts
[0], NULL
))
323 for (i
= 0; i
< sizeof (restropts
)/sizeof (restropts
[0]); i
++) {
324 size_t olen
= strlen(restropts
[i
]);
326 /* Add "restrict" always and the others insofar set */
327 if ((i
== 0 || vfs_optionisset(vfsp
, restropts
[i
], NULL
)) &&
328 ((p
= strstr(buf
, restropts
[i
])) == NULL
||
329 !((p
== buf
|| p
[-1] == ',') &&
330 (p
[olen
] == '\0' || p
[olen
] == ',')))) {
332 if (len
+ olen
+ 1 > maxlen
)
337 (void) strcpy(&buf
[len
], restropts
[i
]);
347 auto_mount(vfs_t
*vfsp
, vnode_t
*vp
, struct mounta
*uap
, cred_t
*cr
)
352 fninfo_t
*fnip
= NULL
;
353 vnode_t
*rootvp
= NULL
;
354 fnnode_t
*rootfnp
= NULL
;
355 char *data
= uap
->dataptr
;
356 char datalen
= uap
->datalen
;
358 char strbuff
[MAXPATHLEN
+ 1];
360 struct autofs_globals
*fngp
;
361 zone_t
*zone
= curproc
->p_zone
;
363 AUTOFS_DPRINT((4, "auto_mount: vfs %p vp %p\n", (void *)vfsp
,
366 if ((error
= secpolicy_fs_mount(cr
, vp
, vfsp
)) != 0)
369 if (zone
== global_zone
) {
372 mntzone
= zone_find_by_path(refstr_value(vfsp
->vfs_mntpt
));
373 ASSERT(mntzone
!= NULL
);
375 if (mntzone
!= zone
) {
381 * Stop the mount from going any further if the zone is going away.
383 if (zone_status_get(zone
) >= ZONE_IS_SHUTTING_DOWN
)
387 * We need a lock to serialize this; minor_lock is as good as any.
389 mutex_enter(&autofs_minor_lock
);
390 if ((fngp
= zone_getspecific(autofs_key
, zone
)) == NULL
) {
391 fngp
= autofs_zone_init();
392 (void) zone_setspecific(autofs_key
, zone
, fngp
);
394 mutex_exit(&autofs_minor_lock
);
395 ASSERT(fngp
!= NULL
);
400 if (uap
->flags
& MS_SYSSPACE
) {
401 if (datalen
!= sizeof (args
))
403 error
= kcopy(data
, &args
, sizeof (args
));
405 if (get_udatamodel() == DATAMODEL_NATIVE
) {
406 if (datalen
!= sizeof (args
))
408 error
= copyin(data
, &args
, sizeof (args
));
410 struct autofs_args32 args32
;
412 if (datalen
!= sizeof (args32
))
414 error
= copyin(data
, &args32
, sizeof (args32
));
416 args
.addr
.maxlen
= args32
.addr
.maxlen
;
417 args
.addr
.len
= args32
.addr
.len
;
418 args
.addr
.buf
= (char *)(uintptr_t)args32
.addr
.buf
;
419 args
.path
= (char *)(uintptr_t)args32
.path
;
420 args
.opts
= (char *)(uintptr_t)args32
.opts
;
421 args
.map
= (char *)(uintptr_t)args32
.map
;
422 args
.subdir
= (char *)(uintptr_t)args32
.subdir
;
423 args
.key
= (char *)(uintptr_t)args32
.key
;
424 args
.mount_to
= args32
.mount_to
;
425 args
.rpc_to
= args32
.rpc_to
;
426 args
.direct
= args32
.direct
;
433 * For a remount, only update mount information
434 * i.e. default mount options, map name, etc.
436 if (uap
->flags
& MS_REMOUNT
) {
437 fnip
= vfstofni(vfsp
);
441 if (args
.direct
== 1)
442 fnip
->fi_flags
|= MF_DIRECT
;
444 fnip
->fi_flags
&= ~MF_DIRECT
;
445 fnip
->fi_mount_to
= args
.mount_to
;
446 fnip
->fi_rpc_to
= args
.rpc_to
;
449 * Get default options
451 if (uap
->flags
& MS_SYSSPACE
)
452 error
= copystr(args
.opts
, strbuff
, sizeof (strbuff
),
455 error
= copyinstr(args
.opts
, strbuff
, sizeof (strbuff
),
460 if (autofs_restrict_opts(vfsp
, strbuff
, sizeof (strbuff
), &len
)
465 kmem_free(fnip
->fi_opts
, fnip
->fi_optslen
);
466 fnip
->fi_opts
= kmem_alloc(len
, KM_SLEEP
);
467 fnip
->fi_optslen
= (int)len
;
468 bcopy(strbuff
, fnip
->fi_opts
, len
);
471 * Get context/map name
473 if (uap
->flags
& MS_SYSSPACE
)
474 error
= copystr(args
.map
, strbuff
, sizeof (strbuff
),
477 error
= copyinstr(args
.map
, strbuff
, sizeof (strbuff
),
482 kmem_free(fnip
->fi_map
, fnip
->fi_maplen
);
483 fnip
->fi_map
= kmem_alloc(len
, KM_SLEEP
);
484 fnip
->fi_maplen
= (int)len
;
485 bcopy(strbuff
, fnip
->fi_map
, len
);
491 * Allocate fninfo struct and attach it to vfs
493 fnip
= kmem_zalloc(sizeof (*fnip
), KM_SLEEP
);
494 fnip
->fi_mountvfs
= vfsp
;
496 fnip
->fi_mount_to
= args
.mount_to
;
497 fnip
->fi_rpc_to
= args
.rpc_to
;
499 vfsp
->vfs_bsize
= AUTOFS_BLOCKSIZE
;
500 vfsp
->vfs_fstype
= autofs_fstype
;
503 * Assign a unique device id to the mount
505 mutex_enter(&autofs_minor_lock
);
507 autofs_minor
= (autofs_minor
+ 1) & L_MAXMIN32
;
508 autofs_dev
= makedevice(autofs_major
, autofs_minor
);
509 } while (vfs_devismounted(autofs_dev
));
510 mutex_exit(&autofs_minor_lock
);
511 vfsp
->vfs_dev
= autofs_dev
;
512 vfs_make_fsid(&vfsp
->vfs_fsid
, autofs_dev
, autofs_fstype
);
513 vfsp
->vfs_data
= (void *)fnip
;
514 vfsp
->vfs_bcount
= 0;
519 fnip
->fi_addr
.len
= args
.addr
.len
;
520 fnip
->fi_addr
.maxlen
= fnip
->fi_addr
.len
;
521 fnip
->fi_addr
.buf
= kmem_alloc(args
.addr
.len
, KM_SLEEP
);
522 if (uap
->flags
& MS_SYSSPACE
)
523 error
= kcopy(args
.addr
.buf
, fnip
->fi_addr
.buf
, args
.addr
.len
);
525 error
= copyin(args
.addr
.buf
, fnip
->fi_addr
.buf
, args
.addr
.len
);
531 fnip
->fi_zoneid
= getzoneid();
533 * Get path for mountpoint
535 if (uap
->flags
& MS_SYSSPACE
)
536 error
= copystr(args
.path
, strbuff
, sizeof (strbuff
), &len
);
538 error
= copyinstr(args
.path
, strbuff
, sizeof (strbuff
), &len
);
543 fnip
->fi_path
= kmem_alloc(len
, KM_SLEEP
);
544 fnip
->fi_pathlen
= (int)len
;
545 bcopy(strbuff
, fnip
->fi_path
, len
);
548 * Get default options
550 if (uap
->flags
& MS_SYSSPACE
)
551 error
= copystr(args
.opts
, strbuff
, sizeof (strbuff
), &len
);
553 error
= copyinstr(args
.opts
, strbuff
, sizeof (strbuff
), &len
);
556 autofs_restrict_opts(vfsp
, strbuff
, sizeof (strbuff
), &len
) != 0) {
560 fnip
->fi_opts
= kmem_alloc(len
, KM_SLEEP
);
561 fnip
->fi_optslen
= (int)len
;
562 bcopy(strbuff
, fnip
->fi_opts
, len
);
565 * Get context/map name
567 if (uap
->flags
& MS_SYSSPACE
)
568 error
= copystr(args
.map
, strbuff
, sizeof (strbuff
), &len
);
570 error
= copyinstr(args
.map
, strbuff
, sizeof (strbuff
), &len
);
575 fnip
->fi_map
= kmem_alloc(len
, KM_SLEEP
);
576 fnip
->fi_maplen
= (int)len
;
577 bcopy(strbuff
, fnip
->fi_map
, len
);
580 * Get subdirectory within map
582 if (uap
->flags
& MS_SYSSPACE
)
583 error
= copystr(args
.subdir
, strbuff
, sizeof (strbuff
), &len
);
585 error
= copyinstr(args
.subdir
, strbuff
, sizeof (strbuff
), &len
);
590 fnip
->fi_subdir
= kmem_alloc(len
, KM_SLEEP
);
591 fnip
->fi_subdirlen
= (int)len
;
592 bcopy(strbuff
, fnip
->fi_subdir
, len
);
597 if (uap
->flags
& MS_SYSSPACE
)
598 error
= copystr(args
.key
, strbuff
, sizeof (strbuff
), &len
);
600 error
= copyinstr(args
.key
, strbuff
, sizeof (strbuff
), &len
);
605 fnip
->fi_key
= kmem_alloc(len
, KM_SLEEP
);
606 fnip
->fi_keylen
= (int)len
;
607 bcopy(strbuff
, fnip
->fi_key
, len
);
610 * Is this a direct mount?
612 if (args
.direct
== 1)
613 fnip
->fi_flags
|= MF_DIRECT
;
617 * Can I pass in knconf as mount argument? what
618 * happens when the daemon gets restarted?
620 if ((error
= lookupname("/dev/ticotsord", UIO_SYSSPACE
, FOLLOW
,
621 NULLVPP
, &kkvp
)) != 0) {
622 cmn_err(CE_WARN
, "autofs: lookupname: %d", error
);
626 fnip
->fi_knconf
.knc_rdev
= kkvp
->v_rdev
;
627 fnip
->fi_knconf
.knc_protofmly
= NC_LOOPBACK
;
628 fnip
->fi_knconf
.knc_semantics
= NC_TPI_COTS_ORD
;
632 * Make the root vnode
634 rootfnp
= auto_makefnnode(VDIR
, vfsp
, fnip
->fi_path
, cr
, fngp
);
635 if (rootfnp
== NULL
) {
639 rootvp
= fntovn(rootfnp
);
641 rootvp
->v_flag
|= VROOT
;
642 rootfnp
->fn_mode
= AUTOFS_MODE
;
643 rootfnp
->fn_parent
= rootfnp
;
644 /* account for ".." entry */
645 rootfnp
->fn_linkcnt
= rootfnp
->fn_size
= 1;
646 fnip
->fi_rootvp
= rootvp
;
649 * Add to list of top level AUTOFS' if it is being mounted by
650 * a user level process.
652 if (!(uap
->flags
& MS_SYSSPACE
)) {
653 rw_enter(&fngp
->fng_rootfnnodep
->fn_rwlock
, RW_WRITER
);
654 rootfnp
->fn_parent
= fngp
->fng_rootfnnodep
;
655 rootfnp
->fn_next
= fngp
->fng_rootfnnodep
->fn_dirents
;
656 fngp
->fng_rootfnnodep
->fn_dirents
= rootfnp
;
657 rw_exit(&fngp
->fng_rootfnnodep
->fn_rwlock
);
660 AUTOFS_DPRINT((5, "auto_mount: vfs %p root %p fnip %p return %d\n",
661 (void *)vfsp
, (void *)rootvp
, (void *)fnip
, error
));
666 ASSERT(fnip
!= NULL
);
667 ASSERT((uap
->flags
& MS_REMOUNT
) == 0);
669 if (fnip
->fi_addr
.buf
!= NULL
)
670 kmem_free(fnip
->fi_addr
.buf
, fnip
->fi_addr
.len
);
671 if (fnip
->fi_path
!= NULL
)
672 kmem_free(fnip
->fi_path
, fnip
->fi_pathlen
);
673 if (fnip
->fi_opts
!= NULL
)
674 kmem_free(fnip
->fi_opts
, fnip
->fi_optslen
);
675 if (fnip
->fi_map
!= NULL
)
676 kmem_free(fnip
->fi_map
, fnip
->fi_maplen
);
677 if (fnip
->fi_subdir
!= NULL
)
678 kmem_free(fnip
->fi_subdir
, fnip
->fi_subdirlen
);
679 if (fnip
->fi_key
!= NULL
)
680 kmem_free(fnip
->fi_key
, fnip
->fi_keylen
);
681 kmem_free(fnip
, sizeof (*fnip
));
683 AUTOFS_DPRINT((5, "auto_mount: vfs %p root %p fnip %p return %d\n",
684 (void *)vfsp
, (void *)rootvp
, (void *)fnip
, error
));
691 auto_unmount(vfs_t
*vfsp
, int flag
, cred_t
*cr
)
695 fnnode_t
*rfnp
, *fnp
, *pfnp
;
696 fnnode_t
*myrootfnnodep
;
698 fnip
= vfstofni(vfsp
);
699 AUTOFS_DPRINT((4, "auto_unmount vfsp %p fnip %p\n", (void *)vfsp
,
702 if (secpolicy_fs_unmount(cr
, vfsp
) != 0)
705 * forced unmount is not supported by this file system
706 * and thus, ENOTSUP, is being returned.
711 ASSERT(vn_vfswlock_held(vfsp
->vfs_vnodecovered
));
712 rvp
= fnip
->fi_rootvp
;
715 if (rvp
->v_count
> 1 || rfnp
->fn_dirents
!= NULL
)
719 * The root vnode is on the linked list of root fnnodes only if
720 * this was not a trigger node. Since we have no way of knowing,
721 * if we don't find it, then we assume it was a trigger node.
723 myrootfnnodep
= rfnp
->fn_globals
->fng_rootfnnodep
;
725 rw_enter(&myrootfnnodep
->fn_rwlock
, RW_WRITER
);
726 fnp
= myrootfnnodep
->fn_dirents
;
727 while (fnp
!= NULL
) {
730 * A check here is made to see if rvp is busy. If
731 * so, return EBUSY. Otherwise proceed with
732 * disconnecting it from the list.
734 if (rvp
->v_count
> 1 || rfnp
->fn_dirents
!= NULL
) {
735 rw_exit(&myrootfnnodep
->fn_rwlock
);
739 pfnp
->fn_next
= fnp
->fn_next
;
741 myrootfnnodep
->fn_dirents
= fnp
->fn_next
;
748 rw_exit(&myrootfnnodep
->fn_rwlock
);
750 ASSERT(rvp
->v_count
== 1);
751 ASSERT(rfnp
->fn_size
== 1);
752 ASSERT(rfnp
->fn_linkcnt
== 1);
754 * The following drops linkcnt to 0, therefore the disconnect is
755 * not attempted when auto_inactive() is called by
756 * vn_rele(). This is necessary because we have nothing to get
757 * disconnected from since we're the root of the filesystem. As a
758 * side effect the node is not freed, therefore I should free the
761 * XXX - I really need to think of a better way of doing this.
767 * release of last reference causes node
771 rfnp
->fn_parent
= NULL
;
773 auto_freefnnode(rfnp
);
775 kmem_free(fnip
->fi_addr
.buf
, fnip
->fi_addr
.len
);
776 kmem_free(fnip
->fi_path
, fnip
->fi_pathlen
);
777 kmem_free(fnip
->fi_map
, fnip
->fi_maplen
);
778 kmem_free(fnip
->fi_subdir
, fnip
->fi_subdirlen
);
779 kmem_free(fnip
->fi_key
, fnip
->fi_keylen
);
780 kmem_free(fnip
->fi_opts
, fnip
->fi_optslen
);
781 kmem_free(fnip
, sizeof (*fnip
));
782 AUTOFS_DPRINT((5, "auto_unmount: return=0\n"));
789 * find root of autofs
792 auto_root(vfs_t
*vfsp
, vnode_t
**vpp
)
794 *vpp
= (vnode_t
*)vfstofni(vfsp
)->fi_rootvp
;
797 AUTOFS_DPRINT((5, "auto_root: vfs %p, *vpp %p\n", (void *)vfsp
,
803 * Get file system statistics.
806 auto_statvfs(vfs_t
*vfsp
, struct statvfs64
*sbp
)
810 AUTOFS_DPRINT((4, "auto_statvfs %p\n", (void *)vfsp
));
812 bzero(sbp
, sizeof (*sbp
));
813 sbp
->f_bsize
= vfsp
->vfs_bsize
;
814 sbp
->f_frsize
= sbp
->f_bsize
;
815 sbp
->f_blocks
= (fsblkcnt64_t
)0;
816 sbp
->f_bfree
= (fsblkcnt64_t
)0;
817 sbp
->f_bavail
= (fsblkcnt64_t
)0;
818 sbp
->f_files
= (fsfilcnt64_t
)0;
819 sbp
->f_ffree
= (fsfilcnt64_t
)0;
820 sbp
->f_favail
= (fsfilcnt64_t
)0;
821 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
823 (void) strcpy(sbp
->f_basetype
, vfssw
[vfsp
->vfs_fstype
].vsw_name
);
824 sbp
->f_flag
= vf_to_stf(vfsp
->vfs_flag
);
825 sbp
->f_namemax
= MAXNAMELEN
;
826 (void) strcpy(sbp
->f_fstr
, MNTTYPE_AUTOFS
);