1facf4a8dSllai1 /*
2facf4a8dSllai1 * CDDL HEADER START
3facf4a8dSllai1 *
4facf4a8dSllai1 * The contents of this file are subject to the terms of the
5facf4a8dSllai1 * Common Development and Distribution License (the "License").
6facf4a8dSllai1 * You may not use this file except in compliance with the License.
7facf4a8dSllai1 *
8facf4a8dSllai1 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9facf4a8dSllai1 * or http://www.opensolaris.org/os/licensing.
10facf4a8dSllai1 * See the License for the specific language governing permissions
11facf4a8dSllai1 * and limitations under the License.
12facf4a8dSllai1 *
13facf4a8dSllai1 * When distributing Covered Code, include this CDDL HEADER in each
14facf4a8dSllai1 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15facf4a8dSllai1 * If applicable, add the following below this CDDL HEADER, with the
16facf4a8dSllai1 * fields enclosed by brackets "[]" replaced with your own identifying
17facf4a8dSllai1 * information: Portions Copyright [yyyy] [name of copyright owner]
18facf4a8dSllai1 *
19facf4a8dSllai1 * CDDL HEADER END
20facf4a8dSllai1 */
21facf4a8dSllai1 /*
22*3c5e027bSEric Taylor * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23facf4a8dSllai1 * Use is subject to license terms.
24facf4a8dSllai1 */
25facf4a8dSllai1
26facf4a8dSllai1 /*
27facf4a8dSllai1 * This is the /dev (hence, the sdev_ prefix) filesystem.
28facf4a8dSllai1 */
29facf4a8dSllai1
30facf4a8dSllai1 #include <sys/types.h>
31facf4a8dSllai1 #include <sys/param.h>
32facf4a8dSllai1 #include <sys/sysmacros.h>
33facf4a8dSllai1 #include <sys/systm.h>
34facf4a8dSllai1 #include <sys/kmem.h>
35facf4a8dSllai1 #include <sys/time.h>
36facf4a8dSllai1 #include <sys/pathname.h>
37facf4a8dSllai1 #include <sys/vfs.h>
38aa59c4cbSrsb #include <sys/vfs_opreg.h>
39facf4a8dSllai1 #include <sys/vnode.h>
40facf4a8dSllai1 #include <sys/file.h>
41facf4a8dSllai1 #include <sys/stat.h>
42facf4a8dSllai1 #include <sys/uio.h>
43facf4a8dSllai1 #include <sys/stat.h>
44facf4a8dSllai1 #include <sys/errno.h>
45facf4a8dSllai1 #include <sys/cmn_err.h>
46facf4a8dSllai1 #include <sys/cred.h>
47facf4a8dSllai1 #include <sys/statvfs.h>
48facf4a8dSllai1 #include <sys/policy.h>
49facf4a8dSllai1 #include <sys/mount.h>
50facf4a8dSllai1 #include <sys/debug.h>
51facf4a8dSllai1 #include <sys/modctl.h>
52facf4a8dSllai1 #include <sys/mkdev.h>
53facf4a8dSllai1 #include <fs/fs_subr.h>
54facf4a8dSllai1 #include <sys/fs/sdev_impl.h>
55facf4a8dSllai1 #include <sys/fs/snode.h>
56facf4a8dSllai1 #include <sys/fs/dv_node.h>
57facf4a8dSllai1 #include <sys/sunndi.h>
58facf4a8dSllai1 #include <sys/mntent.h>
59facf4a8dSllai1
60facf4a8dSllai1 /*
61facf4a8dSllai1 * /dev vfs operations.
62facf4a8dSllai1 */
63facf4a8dSllai1
64facf4a8dSllai1 /*
65facf4a8dSllai1 * globals
66facf4a8dSllai1 */
67facf4a8dSllai1 struct sdev_data *sdev_origins; /* mount info for origins under /dev */
680bfaec69Sllai1 kmutex_t sdev_lock; /* used for mount/unmount/rename synchronization */
69facf4a8dSllai1
70facf4a8dSllai1 /*
71facf4a8dSllai1 * static
72facf4a8dSllai1 */
73facf4a8dSllai1 static major_t devmajor; /* the fictitious major we live on */
74facf4a8dSllai1 static major_t devminor; /* the fictitious minor of this instance */
75facf4a8dSllai1 static struct sdev_data *sdev_mntinfo = NULL; /* linked list of instances */
76bc1009abSjg
77bc1009abSjg /* LINTED E_STATIC_UNUSED */ /* useful for debugging */
78facf4a8dSllai1 static struct vnode *sdev_stale_attrvp; /* stale root attrvp after remount */
79facf4a8dSllai1
80facf4a8dSllai1 static int sdev_mount(struct vfs *, struct vnode *, struct mounta *,
81facf4a8dSllai1 struct cred *);
82facf4a8dSllai1 static int sdev_unmount(struct vfs *, int, struct cred *);
83facf4a8dSllai1 static int sdev_root(struct vfs *, struct vnode **);
84facf4a8dSllai1 static int sdev_statvfs(struct vfs *, struct statvfs64 *);
85facf4a8dSllai1 static void sdev_insert_mntinfo(struct sdev_data *);
86facf4a8dSllai1 static int devinit(int, char *);
87facf4a8dSllai1
88facf4a8dSllai1 static vfsdef_t sdev_vfssw = {
89facf4a8dSllai1 VFSDEF_VERSION,
90facf4a8dSllai1 "dev", /* type name string */
91facf4a8dSllai1 devinit, /* init routine */
92facf4a8dSllai1 VSW_CANREMOUNT, /* flags */
93facf4a8dSllai1 NULL /* mount options table prototype */
94facf4a8dSllai1 };
95facf4a8dSllai1
96facf4a8dSllai1
97facf4a8dSllai1 /*
98facf4a8dSllai1 * Module linkage information
99facf4a8dSllai1 */
100facf4a8dSllai1 static struct modlfs modlfs = {
10139b361b2SRichard Bean &mod_fsops, "/dev filesystem", &sdev_vfssw
102facf4a8dSllai1 };
103facf4a8dSllai1
104facf4a8dSllai1 static struct modlinkage modlinkage = {
105facf4a8dSllai1 MODREV_1, (void *)&modlfs, NULL
106facf4a8dSllai1 };
107facf4a8dSllai1
108facf4a8dSllai1 int
_init(void)109facf4a8dSllai1 _init(void)
110facf4a8dSllai1 {
111facf4a8dSllai1 int e;
112facf4a8dSllai1
113facf4a8dSllai1 mutex_init(&sdev_lock, NULL, MUTEX_DEFAULT, NULL);
114facf4a8dSllai1 sdev_node_cache_init();
115facf4a8dSllai1 sdev_devfsadm_lockinit();
116facf4a8dSllai1 if ((e = mod_install(&modlinkage)) != 0) {
117facf4a8dSllai1 sdev_devfsadm_lockdestroy();
118facf4a8dSllai1 sdev_node_cache_fini();
119facf4a8dSllai1 mutex_destroy(&sdev_lock);
120facf4a8dSllai1 return (e);
121facf4a8dSllai1 }
122facf4a8dSllai1 return (0);
123facf4a8dSllai1 }
124facf4a8dSllai1
125facf4a8dSllai1 /*
126facf4a8dSllai1 * dev module remained loaded for the global /dev instance
127facf4a8dSllai1 */
128facf4a8dSllai1 int
_fini(void)129facf4a8dSllai1 _fini(void)
130facf4a8dSllai1 {
131facf4a8dSllai1 return (EBUSY);
132facf4a8dSllai1 }
133facf4a8dSllai1
134facf4a8dSllai1 int
_info(struct modinfo * modinfop)135facf4a8dSllai1 _info(struct modinfo *modinfop)
136facf4a8dSllai1 {
137facf4a8dSllai1 return (mod_info(&modlinkage, modinfop));
138facf4a8dSllai1 }
139facf4a8dSllai1
140facf4a8dSllai1 /*ARGSUSED*/
141facf4a8dSllai1 static int
devinit(int fstype,char * name)142facf4a8dSllai1 devinit(int fstype, char *name)
143facf4a8dSllai1 {
144facf4a8dSllai1 static const fs_operation_def_t dev_vfsops_tbl[] = {
145aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = sdev_mount },
146aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = sdev_unmount },
147aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = sdev_root },
148aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = sdev_statvfs },
149facf4a8dSllai1 NULL, NULL
150facf4a8dSllai1 };
151facf4a8dSllai1
152facf4a8dSllai1 int error;
153facf4a8dSllai1 extern major_t getudev(void);
154facf4a8dSllai1
155facf4a8dSllai1 devtype = fstype;
156facf4a8dSllai1
157facf4a8dSllai1 error = vfs_setfsops(fstype, dev_vfsops_tbl, NULL);
158facf4a8dSllai1 if (error != 0) {
159facf4a8dSllai1 cmn_err(CE_WARN, "devinit: bad vfs ops tbl");
160facf4a8dSllai1 return (error);
161facf4a8dSllai1 }
162facf4a8dSllai1
163facf4a8dSllai1 error = vn_make_ops("dev", sdev_vnodeops_tbl, &sdev_vnodeops);
164facf4a8dSllai1 if (error != 0) {
165facf4a8dSllai1 (void) vfs_freevfsops_by_type(fstype);
166facf4a8dSllai1 cmn_err(CE_WARN, "devinit: bad vnode ops tbl");
167facf4a8dSllai1 return (error);
168facf4a8dSllai1 }
169facf4a8dSllai1
170facf4a8dSllai1 if ((devmajor = getudev()) == (major_t)-1) {
171facf4a8dSllai1 cmn_err(CE_WARN, "%s: can't get unique dev", sdev_vfssw.name);
172facf4a8dSllai1 return (1);
173facf4a8dSllai1 }
174facf4a8dSllai1
175facf4a8dSllai1 /* initialize negative cache */
176facf4a8dSllai1 sdev_ncache_init();
177facf4a8dSllai1
178facf4a8dSllai1 return (0);
179facf4a8dSllai1 }
180facf4a8dSllai1
181facf4a8dSllai1 /*
182facf4a8dSllai1 * Both mount point and backing store directory name are
183facf4a8dSllai1 * passed in from userland
184facf4a8dSllai1 */
185facf4a8dSllai1 static int
sdev_mount(struct vfs * vfsp,struct vnode * mvp,struct mounta * uap,struct cred * cr)186facf4a8dSllai1 sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
187facf4a8dSllai1 struct cred *cr)
188facf4a8dSllai1 {
189facf4a8dSllai1 struct sdev_data *sdev_data;
190facf4a8dSllai1 struct vnode *avp;
191facf4a8dSllai1 struct sdev_node *dv;
192facf4a8dSllai1 struct sdev_mountargs *args = NULL;
193facf4a8dSllai1 int error = 0;
194facf4a8dSllai1 dev_t devdev;
195facf4a8dSllai1
196facf4a8dSllai1 /*
197facf4a8dSllai1 * security check
198facf4a8dSllai1 */
199facf4a8dSllai1 if ((secpolicy_fs_mount(cr, mvp, vfsp) != 0) ||
200facf4a8dSllai1 (secpolicy_sys_devices(cr) != 0))
201facf4a8dSllai1 return (EPERM);
202facf4a8dSllai1
203facf4a8dSllai1 /*
204facf4a8dSllai1 * Sanity check the mount point
205facf4a8dSllai1 */
206facf4a8dSllai1 if (mvp->v_type != VDIR)
207facf4a8dSllai1 return (ENOTDIR);
208facf4a8dSllai1
209facf4a8dSllai1 /*
210facf4a8dSllai1 * Sanity Check for overlay mount.
211facf4a8dSllai1 */
212facf4a8dSllai1 mutex_enter(&mvp->v_lock);
213facf4a8dSllai1 if ((uap->flags & MS_OVERLAY) == 0 &&
214facf4a8dSllai1 (uap->flags & MS_REMOUNT) == 0 &&
215facf4a8dSllai1 (mvp->v_count > 1 || (mvp->v_flag & VROOT))) {
216facf4a8dSllai1 mutex_exit(&mvp->v_lock);
217facf4a8dSllai1 return (EBUSY);
218facf4a8dSllai1 }
219facf4a8dSllai1 mutex_exit(&mvp->v_lock);
220facf4a8dSllai1
221facf4a8dSllai1 args = kmem_zalloc(sizeof (*args), KM_SLEEP);
222facf4a8dSllai1
223facf4a8dSllai1 if ((uap->flags & MS_DATA) &&
224facf4a8dSllai1 (uap->datalen != 0 && uap->dataptr != NULL)) {
225facf4a8dSllai1 /* copy in the arguments */
226facf4a8dSllai1 if (error = sdev_copyin_mountargs(uap, args))
227facf4a8dSllai1 goto cleanup;
228facf4a8dSllai1 }
229facf4a8dSllai1
230facf4a8dSllai1 /*
231facf4a8dSllai1 * Sanity check the backing store
232facf4a8dSllai1 */
233facf4a8dSllai1 if (args->sdev_attrdir) {
234facf4a8dSllai1 /* user supplied an attribute store */
235facf4a8dSllai1 if (error = lookupname((char *)(uintptr_t)args->sdev_attrdir,
236facf4a8dSllai1 UIO_USERSPACE, FOLLOW, NULLVPP, &avp)) {
237facf4a8dSllai1 cmn_err(CE_NOTE, "/dev fs: lookup on attribute "
238facf4a8dSllai1 "directory %s failed",
239facf4a8dSllai1 (char *)(uintptr_t)args->sdev_attrdir);
240facf4a8dSllai1 goto cleanup;
241facf4a8dSllai1 }
242facf4a8dSllai1
243facf4a8dSllai1 if (avp->v_type != VDIR) {
244facf4a8dSllai1 VN_RELE(avp);
245facf4a8dSllai1 error = ENOTDIR;
246facf4a8dSllai1 goto cleanup;
247facf4a8dSllai1 }
248facf4a8dSllai1 } else {
249facf4a8dSllai1 /* use mountp as the attribute store */
250facf4a8dSllai1 avp = mvp;
251facf4a8dSllai1 VN_HOLD(avp);
252facf4a8dSllai1 }
253facf4a8dSllai1
254facf4a8dSllai1 mutex_enter(&sdev_lock);
255facf4a8dSllai1
256facf4a8dSllai1 /*
257facf4a8dSllai1 * handling installation
258facf4a8dSllai1 */
259facf4a8dSllai1 if (uap->flags & MS_REMOUNT) {
260facf4a8dSllai1 sdev_data = (struct sdev_data *)vfsp->vfs_data;
261facf4a8dSllai1 ASSERT(sdev_data);
262facf4a8dSllai1
263facf4a8dSllai1 dv = sdev_data->sdev_root;
264facf4a8dSllai1 ASSERT(dv == dv->sdev_dotdot);
265facf4a8dSllai1
266facf4a8dSllai1 /*
267facf4a8dSllai1 * mark all existing sdev_nodes (except root node) stale
268facf4a8dSllai1 */
269facf4a8dSllai1 sdev_stale(dv);
270facf4a8dSllai1
271facf4a8dSllai1 /* Reset previous mountargs */
272facf4a8dSllai1 if (sdev_data->sdev_mountargs) {
273facf4a8dSllai1 kmem_free(sdev_data->sdev_mountargs,
274facf4a8dSllai1 sizeof (struct sdev_mountargs));
275facf4a8dSllai1 }
276facf4a8dSllai1 sdev_data->sdev_mountargs = args;
277facf4a8dSllai1 args = NULL; /* so it won't be freed below */
278facf4a8dSllai1
279facf4a8dSllai1 sdev_stale_attrvp = dv->sdev_attrvp;
280facf4a8dSllai1 dv->sdev_attrvp = avp;
281facf4a8dSllai1 vfsp->vfs_mtime = ddi_get_time();
282facf4a8dSllai1
283facf4a8dSllai1 mutex_exit(&sdev_lock);
284facf4a8dSllai1 goto cleanup; /* we're done */
285facf4a8dSllai1 }
286facf4a8dSllai1
287facf4a8dSllai1 /*
288facf4a8dSllai1 * Create and initialize the vfs-private data.
289facf4a8dSllai1 */
290facf4a8dSllai1 devdev = makedevice(devmajor, devminor);
291facf4a8dSllai1 while (vfs_devismounted(devdev)) {
292facf4a8dSllai1 devminor = (devminor + 1) & MAXMIN32;
293facf4a8dSllai1
294facf4a8dSllai1 /*
295facf4a8dSllai1 * All the minor numbers are used up.
296facf4a8dSllai1 */
297facf4a8dSllai1 if (devminor == 0) {
298facf4a8dSllai1 mutex_exit(&sdev_lock);
299facf4a8dSllai1 VN_RELE(avp);
300facf4a8dSllai1 error = ENODEV;
301facf4a8dSllai1 goto cleanup;
302facf4a8dSllai1 }
303facf4a8dSllai1
304facf4a8dSllai1 devdev = makedevice(devmajor, devminor);
305facf4a8dSllai1 }
306facf4a8dSllai1
307facf4a8dSllai1 dv = sdev_mkroot(vfsp, devdev, mvp, avp, cr);
308facf4a8dSllai1 sdev_data = kmem_zalloc(sizeof (struct sdev_data), KM_SLEEP);
309facf4a8dSllai1 vfsp->vfs_dev = devdev;
310facf4a8dSllai1 vfsp->vfs_data = (caddr_t)sdev_data;
311facf4a8dSllai1 vfsp->vfs_fstype = devtype;
312facf4a8dSllai1 vfsp->vfs_bsize = DEV_BSIZE;
313facf4a8dSllai1 vfsp->vfs_mtime = ddi_get_time();
314facf4a8dSllai1 vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, devtype);
315facf4a8dSllai1
316facf4a8dSllai1 ASSERT(dv == dv->sdev_dotdot);
317facf4a8dSllai1
318facf4a8dSllai1 sdev_data->sdev_vfsp = vfsp;
319facf4a8dSllai1 sdev_data->sdev_root = dv;
320facf4a8dSllai1 sdev_data->sdev_mountargs = args;
321facf4a8dSllai1
322facf4a8dSllai1 /* get acl flavor from attribute dir */
323facf4a8dSllai1 if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor,
324da6c28aaSamw kcred, NULL) != 0 || sdev_data->sdev_acl_flavor == 0)
325facf4a8dSllai1 sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED;
326facf4a8dSllai1
327facf4a8dSllai1 args = NULL; /* so it won't be freed below */
328facf4a8dSllai1 sdev_insert_mntinfo(sdev_data);
329facf4a8dSllai1 mutex_exit(&sdev_lock);
330facf4a8dSllai1
331facf4a8dSllai1 if (!SDEV_IS_GLOBAL(dv)) {
332facf4a8dSllai1 ASSERT(sdev_origins);
333facf4a8dSllai1 dv->sdev_flags &= ~SDEV_GLOBAL;
334facf4a8dSllai1 dv->sdev_origin = sdev_origins->sdev_root;
335facf4a8dSllai1 } else {
336facf4a8dSllai1 sdev_ncache_setup();
3376b938478Sjg rw_enter(&dv->sdev_contents, RW_WRITER);
3386b938478Sjg sdev_filldir_dynamic(dv);
3396b938478Sjg rw_exit(&dv->sdev_contents);
340facf4a8dSllai1 }
341facf4a8dSllai1
342facf4a8dSllai1 sdev_update_timestamps(dv->sdev_attrvp,
343facf4a8dSllai1 cr, AT_CTIME|AT_MTIME|AT_ATIME);
344facf4a8dSllai1
345facf4a8dSllai1 cleanup:
346facf4a8dSllai1 if (args)
347facf4a8dSllai1 kmem_free(args, sizeof (*args));
348facf4a8dSllai1 return (error);
349facf4a8dSllai1 }
350facf4a8dSllai1
351facf4a8dSllai1 /*
352facf4a8dSllai1 * unmounting the non-global /dev instances, e.g. when deleting a Kevlar zone.
353facf4a8dSllai1 */
354facf4a8dSllai1 static int
sdev_unmount(struct vfs * vfsp,int flag,struct cred * cr)355facf4a8dSllai1 sdev_unmount(struct vfs *vfsp, int flag, struct cred *cr)
356facf4a8dSllai1 {
357facf4a8dSllai1 struct sdev_node *dv;
358facf4a8dSllai1 int error;
359facf4a8dSllai1 struct sdev_data *sdev_data, *prev, *next;
360facf4a8dSllai1
361facf4a8dSllai1 /*
362facf4a8dSllai1 * enforce the security policies
363facf4a8dSllai1 */
364facf4a8dSllai1 if ((secpolicy_fs_unmount(cr, vfsp) != 0) ||
365facf4a8dSllai1 (secpolicy_sys_devices(cr) != 0))
366facf4a8dSllai1 return (EPERM);
367facf4a8dSllai1
368facf4a8dSllai1 if (flag & MS_FORCE)
369facf4a8dSllai1 return (ENOTSUP);
370facf4a8dSllai1
371facf4a8dSllai1 mutex_enter(&sdev_lock);
372facf4a8dSllai1 dv = VFSTOSDEVFS(vfsp)->sdev_root;
373facf4a8dSllai1 ASSERT(dv == dv->sdev_dotdot);
374facf4a8dSllai1 if (SDEVTOV(dv)->v_count > 1) {
375facf4a8dSllai1 mutex_exit(&sdev_lock);
376facf4a8dSllai1 return (EBUSY);
377facf4a8dSllai1 }
378facf4a8dSllai1
379facf4a8dSllai1 /*
380facf4a8dSllai1 * global instance remains mounted
381facf4a8dSllai1 */
382facf4a8dSllai1 if (SDEV_IS_GLOBAL(dv)) {
383facf4a8dSllai1 mutex_exit(&sdev_lock);
384facf4a8dSllai1 return (EBUSY);
385facf4a8dSllai1 }
386facf4a8dSllai1 mutex_exit(&sdev_lock);
387facf4a8dSllai1
388facf4a8dSllai1 /* verify the v_count */
389facf4a8dSllai1 if ((error = sdev_cleandir(dv, NULL, 0)) != 0) {
390facf4a8dSllai1 return (error);
391facf4a8dSllai1 }
392facf4a8dSllai1 ASSERT(SDEVTOV(dv)->v_count == 1);
393facf4a8dSllai1
394facf4a8dSllai1 /* release hold on root node and destroy it */
395facf4a8dSllai1 SDEV_RELE(dv);
396facf4a8dSllai1 dv->sdev_nlink -= 2;
397facf4a8dSllai1 sdev_nodedestroy(dv, 0);
398facf4a8dSllai1
399facf4a8dSllai1 sdev_data = (struct sdev_data *)vfsp->vfs_data;
400facf4a8dSllai1 vfsp->vfs_data = (caddr_t)0;
401facf4a8dSllai1
402facf4a8dSllai1 /*
403facf4a8dSllai1 * XXX separate it into sdev_delete_mntinfo() if useful
404facf4a8dSllai1 */
405facf4a8dSllai1 mutex_enter(&sdev_lock);
406facf4a8dSllai1 prev = sdev_data->sdev_prev;
407facf4a8dSllai1 next = sdev_data->sdev_next;
408facf4a8dSllai1 if (prev)
409facf4a8dSllai1 prev->sdev_next = next;
410facf4a8dSllai1 else
411facf4a8dSllai1 sdev_mntinfo = next;
412facf4a8dSllai1 if (next)
413facf4a8dSllai1 next->sdev_prev = prev;
414facf4a8dSllai1 mutex_exit(&sdev_lock);
415facf4a8dSllai1
416facf4a8dSllai1 if (sdev_data->sdev_mountargs) {
417facf4a8dSllai1 kmem_free(sdev_data->sdev_mountargs,
418facf4a8dSllai1 sizeof (struct sdev_mountargs));
419facf4a8dSllai1 }
420facf4a8dSllai1 kmem_free(sdev_data, sizeof (struct sdev_data));
421facf4a8dSllai1 return (0);
422facf4a8dSllai1 }
423facf4a8dSllai1
424facf4a8dSllai1 /*
425facf4a8dSllai1 * return root vnode for given vfs
426facf4a8dSllai1 */
427facf4a8dSllai1 static int
sdev_root(struct vfs * vfsp,struct vnode ** vpp)428facf4a8dSllai1 sdev_root(struct vfs *vfsp, struct vnode **vpp)
429facf4a8dSllai1 {
430facf4a8dSllai1 *vpp = SDEVTOV(VFSTOSDEVFS(vfsp)->sdev_root);
431facf4a8dSllai1 VN_HOLD(*vpp);
432facf4a8dSllai1 return (0);
433facf4a8dSllai1 }
434facf4a8dSllai1
435facf4a8dSllai1 /*
436facf4a8dSllai1 * return 'generic superblock' information to userland.
437facf4a8dSllai1 *
438facf4a8dSllai1 * not much that we can usefully admit to here
439facf4a8dSllai1 */
440facf4a8dSllai1 static int
sdev_statvfs(struct vfs * vfsp,struct statvfs64 * sbp)441facf4a8dSllai1 sdev_statvfs(struct vfs *vfsp, struct statvfs64 *sbp)
442facf4a8dSllai1 {
443facf4a8dSllai1 dev32_t d32;
444facf4a8dSllai1
445facf4a8dSllai1 bzero(sbp, sizeof (*sbp));
446facf4a8dSllai1 sbp->f_frsize = sbp->f_bsize = vfsp->vfs_bsize;
447facf4a8dSllai1 sbp->f_files = kmem_cache_stat(sdev_node_cache, "alloc");
448facf4a8dSllai1
449facf4a8dSllai1 /* no illusions that free/avail files is relevant to dev */
450facf4a8dSllai1 sbp->f_ffree = 0;
451facf4a8dSllai1 sbp->f_favail = 0;
452facf4a8dSllai1
453facf4a8dSllai1 /* no illusions that blocks are relevant to devfs */
454facf4a8dSllai1 sbp->f_bfree = 0;
455facf4a8dSllai1 sbp->f_bavail = 0;
456facf4a8dSllai1 sbp->f_blocks = 0;
457facf4a8dSllai1
458facf4a8dSllai1 (void) cmpldev(&d32, vfsp->vfs_dev);
459facf4a8dSllai1 sbp->f_fsid = d32;
460facf4a8dSllai1 (void) strcpy(sbp->f_basetype, vfssw[devtype].vsw_name);
461facf4a8dSllai1 sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
462facf4a8dSllai1 sbp->f_namemax = MAXNAMELEN - 1;
463facf4a8dSllai1 (void) strcpy(sbp->f_fstr, "dev");
464facf4a8dSllai1
465facf4a8dSllai1 return (0);
466facf4a8dSllai1 }
467facf4a8dSllai1
468facf4a8dSllai1 static void
sdev_insert_mntinfo(struct sdev_data * data)469facf4a8dSllai1 sdev_insert_mntinfo(struct sdev_data *data)
470facf4a8dSllai1 {
471facf4a8dSllai1 ASSERT(mutex_owned(&sdev_lock));
472facf4a8dSllai1 data->sdev_next = sdev_mntinfo;
473facf4a8dSllai1 data->sdev_prev = NULL;
474facf4a8dSllai1 if (sdev_mntinfo) {
475facf4a8dSllai1 sdev_mntinfo->sdev_prev = data;
476facf4a8dSllai1 } else {
477facf4a8dSllai1 sdev_origins = data;
478facf4a8dSllai1 }
479facf4a8dSllai1 sdev_mntinfo = data;
480facf4a8dSllai1 }
481facf4a8dSllai1
482facf4a8dSllai1 struct sdev_data *
sdev_find_mntinfo(char * mntpt)483facf4a8dSllai1 sdev_find_mntinfo(char *mntpt)
484facf4a8dSllai1 {
485facf4a8dSllai1 struct sdev_data *mntinfo;
486facf4a8dSllai1
487facf4a8dSllai1 mutex_enter(&sdev_lock);
488facf4a8dSllai1 mntinfo = sdev_mntinfo;
489facf4a8dSllai1 while (mntinfo) {
490facf4a8dSllai1 if (strcmp(mntpt, mntinfo->sdev_root->sdev_name) == 0) {
491facf4a8dSllai1 SDEVTOV(mntinfo->sdev_root)->v_count++;
492facf4a8dSllai1 break;
493facf4a8dSllai1 }
494facf4a8dSllai1 mntinfo = mntinfo->sdev_next;
495facf4a8dSllai1 }
496facf4a8dSllai1 mutex_exit(&sdev_lock);
497facf4a8dSllai1 return (mntinfo);
498facf4a8dSllai1 }
499facf4a8dSllai1
500facf4a8dSllai1 void
sdev_mntinfo_rele(struct sdev_data * mntinfo)501facf4a8dSllai1 sdev_mntinfo_rele(struct sdev_data *mntinfo)
502facf4a8dSllai1 {
503facf4a8dSllai1 mutex_enter(&sdev_lock);
504facf4a8dSllai1 SDEVTOV(mntinfo->sdev_root)->v_count--;
505facf4a8dSllai1 mutex_exit(&sdev_lock);
506facf4a8dSllai1 }
507