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) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/cmn_err.h>
29 #include <sys/debug.h>
30 #include <sys/errno.h>
32 #include <sys/procfs.h>
34 #include <sys/statvfs.h>
35 #include <sys/sysmacros.h>
36 #include <sys/systm.h>
39 #include <sys/vnode.h>
41 #include <sys/signal.h>
43 #include <sys/mount.h>
44 #include <sys/bitmap.h>
46 #include <sys/policy.h>
47 #include <sys/fs_subr.h>
48 #include <sys/fs/mntdata.h>
52 * This is the loadable module wrapper.
54 #include <sys/modctl.h>
56 static int mntinit(int, char *);
58 static mntopts_t mnt_mntopts
= {
63 static vfsdef_t vfw
= {
67 VSW_HASPROTO
|VSW_STATS
|VSW_ZMOUNT
,
72 * Module linkage information for the kernel.
74 extern struct mod_ops mod_fsops
;
76 static struct modlfs modlfs
= {
77 &mod_fsops
, "mount information file system", &vfw
80 static struct modlinkage modlinkage
= {
81 MODREV_1
, (void *)&modlfs
, NULL
87 return (mod_install(&modlinkage
));
91 _info(struct modinfo
*modinfop
)
93 return (mod_info(&modlinkage
, modinfop
));
98 * No _fini routine. The module cannot be unloaded once loaded.
99 * The NO_UNLOAD_STUB in modstubs.s must change if this module
100 * is ever modified to become unloadable.
103 extern int mntfstype
;
104 static major_t mnt_major
;
105 static minor_t mnt_minor
;
106 static kmutex_t mnt_minor_lock
;
109 * /mnttab VFS operations vector.
111 static int mntmount(), mntunmount(), mntroot(), mntstatvfs();
114 mntinitrootnode(mntnode_t
*mnp
)
118 bzero((caddr_t
)mnp
, sizeof (*mnp
));
120 mnp
->mnt_vnode
= vn_alloc(KM_SLEEP
);
124 vp
->v_flag
= VROOT
|VNOCACHE
|VNOMAP
|VNOSWAP
|VNOMOUNT
;
125 vn_setops(vp
, &mntvnodeops
);
127 vp
->v_data
= (caddr_t
)mnp
;
130 static const struct vfsops mnt_vfsops
= {
131 .vfs_mount
= mntmount
,
132 .vfs_unmount
= mntunmount
,
134 .vfs_statvfs
= mntstatvfs
,
138 mntinit(int fstype
, char *name
)
143 ASSERT(mntfstype
!= 0);
145 * Associate VFS ops vector with this fstype.
147 error
= vfs_setfsops(fstype
, &mnt_vfsops
);
149 cmn_err(CE_WARN
, "mntinit: bad fstyp");
154 * Assign a unique "device" number (used by stat(2)).
156 if ((mnt_major
= getudev()) == (major_t
)-1) {
157 cmn_err(CE_WARN
, "mntinit: can't get unique device number");
160 mutex_init(&mnt_minor_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
167 mntmount(struct vfs
*vfsp
, struct vnode
*mvp
,
168 struct mounta
*uap
, struct cred
*cr
)
172 zone_t
*zone
= curproc
->p_zone
;
174 if (secpolicy_fs_mount(cr
, mvp
, vfsp
) != 0)
178 * You can only mount mnttab in your current zone.
180 if (zone
== global_zone
) {
183 mntzone
= zone_find_by_path(refstr_value(vfsp
->vfs_mntpt
));
184 ASSERT(mntzone
!= NULL
);
191 * Having the resource be anything but "mnttab" doesn't make sense
193 vfs_setresource(vfsp
, "mnttab", 0);
195 mnt
= kmem_zalloc(sizeof (*mnt
), KM_SLEEP
);
196 mutex_enter(&mvp
->v_lock
);
197 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
198 (mvp
->v_count
> 1 || (mvp
->v_flag
& VROOT
))) {
199 mutex_exit(&mvp
->v_lock
);
200 kmem_free(mnt
, sizeof (*mnt
));
203 mutex_exit(&mvp
->v_lock
);
205 zone_init_ref(&mnt
->mnt_zone_ref
);
206 zone_hold_ref(zone
, &mnt
->mnt_zone_ref
, ZONE_REF_MNTFS
);
207 mnp
= &mnt
->mnt_node
;
209 vfsp
->vfs_fstype
= mntfstype
;
210 vfsp
->vfs_data
= (caddr_t
)mnt
;
212 * find an available minor device number for this mount.
214 mutex_enter(&mnt_minor_lock
);
216 mnt_minor
= (mnt_minor
+ 1) & L_MAXMIN32
;
217 vfsp
->vfs_dev
= makedevice(mnt_major
, mnt_minor
);
218 } while (vfs_devismounted(vfsp
->vfs_dev
));
219 mutex_exit(&mnt_minor_lock
);
220 vfs_make_fsid(&vfsp
->vfs_fsid
, vfsp
->vfs_dev
, mntfstype
);
221 vfsp
->vfs_bsize
= DEV_BSIZE
;
222 mntinitrootnode(mnp
);
223 MTOV(mnp
)->v_vfsp
= vfsp
;
224 mnp
->mnt_mountvp
= mvp
;
225 vn_exists(MTOV(mnp
));
231 mntunmount(struct vfs
*vfsp
, int flag
, struct cred
*cr
)
233 mntdata_t
*mnt
= (mntdata_t
*)vfsp
->vfs_data
;
234 vnode_t
*vp
= MTOV(&mnt
->mnt_node
);
236 if (secpolicy_fs_unmount(cr
, vfsp
) != 0)
240 * Ensure that no /mnttab vnodes are in use on this mount point.
242 mutex_enter(&vp
->v_lock
);
243 if (vp
->v_count
> 1 || mnt
->mnt_nopen
> 0) {
244 mutex_exit(&vp
->v_lock
);
248 mutex_exit(&vp
->v_lock
);
249 zone_rele_ref(&mnt
->mnt_zone_ref
, ZONE_REF_MNTFS
);
252 kmem_free(mnt
, sizeof (*mnt
));
258 mntroot(struct vfs
*vfsp
, struct vnode
**vpp
)
260 mntnode_t
*mnp
= &((mntdata_t
*)vfsp
->vfs_data
)->mnt_node
;
261 struct vnode
*vp
= MTOV(mnp
);
269 mntstatvfs(struct vfs
*vfsp
, struct statvfs64
*sp
)
273 bzero((caddr_t
)sp
, sizeof (*sp
));
274 sp
->f_bsize
= DEV_BSIZE
;
275 sp
->f_frsize
= DEV_BSIZE
;
276 sp
->f_blocks
= (fsblkcnt64_t
)0;
277 sp
->f_bfree
= (fsblkcnt64_t
)0;
278 sp
->f_bavail
= (fsblkcnt64_t
)0;
279 sp
->f_files
= (fsfilcnt64_t
)1;
280 sp
->f_ffree
= (fsfilcnt64_t
)0;
281 sp
->f_favail
= (fsfilcnt64_t
)0;
282 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
284 (void) strcpy(sp
->f_basetype
, vfssw
[mntfstype
].vsw_name
);
285 sp
->f_flag
= vf_to_stf(vfsp
->vfs_flag
);
286 sp
->f_namemax
= 64; /* quite arbitrary */
287 bzero(sp
->f_fstr
, sizeof (sp
->f_fstr
));
288 (void) strcpy(sp
->f_fstr
, "/mnttab");
289 (void) strcpy(&sp
->f_fstr
[8], "/mnttab");