xref: /illumos-gate/usr/src/uts/common/fs/objfs/objfs_vfs.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/atomic.h>
29 #include <sys/cmn_err.h>
30 #include <sys/errno.h>
31 #include <sys/mount.h>
32 #include <sys/objfs.h>
33 #include <sys/objfs_impl.h>
34 #include <sys/vfs_opreg.h>
35 #include <sys/policy.h>
36 #include <sys/sunddi.h>
37 #include <sys/sysmacros.h>
38 #include <sys/systm.h>
39 
40 /*
41  * Kernel object filesystem.
42  *
43  * This is a pseudo filesystem which exports information about currently loaded
44  * kernel objects.  The root directory contains one directory for each loaded
45  * object, indexed by module name.  Within each object directory is an ELF file,
46  * 'object', that contains information about the currently loaded module.
47  *
48  * This file contains functions that interact with the VFS layer.  Each
49  * filesystem element is represented by a a different node.
50  *
51  * 	/		objfs_rootnode_t	objfs_root.c
52  *	/<obj>		objfs_odirnode_t	objfs_odir.c
53  *	/<obj>/object	objfs_datanode_t	objfs_data.c
54  *
55  * In addition, some common routines are found in the 'objfs_common.c' file.
56  */
57 
58 vnodeops_t *objfs_ops_root;
59 vnodeops_t *objfs_ops_odir;
60 vnodeops_t *objfs_ops_data;
61 
62 static const fs_operation_def_t objfs_vfstops[];
63 static gfs_opsvec_t objfs_opsvec[];
64 
65 static int objfs_init(int, char *);
66 
67 /*
68  * Module linkage
69  */
70 static mntopts_t objfs_mntopts = {
71 	0,
72 	NULL
73 };
74 
75 static vfsdef_t vfw = {
76 	VFSDEF_VERSION,
77 	"objfs",
78 	objfs_init,
79 	VSW_HASPROTO,
80 	&objfs_mntopts,
81 };
82 
83 extern struct mod_ops mod_fsops;
84 
85 static struct modlfs modlfs = {
86 	&mod_fsops, "kernel object filesystem", &vfw
87 };
88 
89 static struct modlinkage modlinkage = {
90 	MODREV_1, (void *)&modlfs, NULL
91 };
92 
93 int
94 _init(void)
95 {
96 	return (mod_install(&modlinkage));
97 }
98 
99 int
100 _info(struct modinfo *modinfop)
101 {
102 	return (mod_info(&modlinkage, modinfop));
103 }
104 
105 int
106 _fini(void)
107 {
108 	/*
109 	 * The object filesystem cannot be unloaded.
110 	 */
111 	return (EBUSY);
112 }
113 
114 /*
115  * Filesystem initialization.
116  */
117 
118 static int objfs_fstype;
119 static major_t objfs_major;
120 static minor_t objfs_minor;
121 
122 static gfs_opsvec_t objfs_opsvec[] = {
123 	{ "objfs root directory", objfs_tops_root, &objfs_ops_root },
124 	{ "objfs object directory", objfs_tops_odir, &objfs_ops_odir },
125 	{ "objfs data file", objfs_tops_data, &objfs_ops_data },
126 	{ NULL }
127 };
128 
129 /* ARGSUSED */
130 static int
131 objfs_init(int fstype, char *name)
132 {
133 	vfsops_t *vfsops;
134 	int error;
135 
136 	objfs_fstype = fstype;
137 	if (error = vfs_setfsops(fstype, objfs_vfstops, &vfsops)) {
138 		cmn_err(CE_WARN, "objfs_init: bad vfs ops template");
139 		return (error);
140 	}
141 
142 	if (error = gfs_make_opsvec(objfs_opsvec)) {
143 		(void) vfs_freevfsops(vfsops);
144 		return (error);
145 	}
146 
147 	if ((objfs_major = getudev()) == (major_t)-1) {
148 		cmn_err(CE_WARN, "objfs_init: can't get unique device number");
149 		objfs_major = 0;
150 	}
151 
152 	objfs_data_init();
153 
154 	return (0);
155 }
156 
157 /*
158  * VFS entry points
159  */
160 static int
161 objfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
162 {
163 	objfs_vfs_t *data;
164 	dev_t dev;
165 
166 	if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
167 		return (EPERM);
168 
169 	if (mvp->v_type != VDIR)
170 		return (ENOTDIR);
171 
172 	if ((uap->flags & MS_OVERLAY) == 0 &&
173 	    (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
174 		return (EBUSY);
175 
176 	data = kmem_alloc(sizeof (objfs_vfs_t), KM_SLEEP);
177 
178 	/*
179 	 * Initialize vfs fields
180 	 */
181 	vfsp->vfs_bsize = DEV_BSIZE;
182 	vfsp->vfs_fstype = objfs_fstype;
183 	do {
184 		dev = makedevice(objfs_major,
185 		    atomic_add_32_nv(&objfs_minor, 1) & L_MAXMIN32);
186 	} while (vfs_devismounted(dev));
187 	vfs_make_fsid(&vfsp->vfs_fsid, dev, objfs_fstype);
188 	vfsp->vfs_data = data;
189 	vfsp->vfs_dev = dev;
190 
191 	/*
192 	 * Create root
193 	 */
194 	data->objfs_vfs_root = objfs_create_root(vfsp);
195 
196 	return (0);
197 }
198 
199 static int
200 objfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
201 {
202 	objfs_vfs_t *data;
203 
204 	if (secpolicy_fs_unmount(cr, vfsp) != 0)
205 		return (EPERM);
206 
207 	/*
208 	 * We do not currently support forced unmounts
209 	 */
210 	if (flag & MS_FORCE)
211 		return (ENOTSUP);
212 
213 	/*
214 	 * We should never have a reference count of less than 2: one for the
215 	 * caller, one for the root vnode.
216 	 */
217 	ASSERT(vfsp->vfs_count >= 2);
218 
219 	/*
220 	 * Any active vnodes will result in a hold on the root vnode
221 	 */
222 	data = vfsp->vfs_data;
223 	if (data->objfs_vfs_root->v_count > 1)
224 		return (EBUSY);
225 
226 	/*
227 	 * Release the last hold on the root vnode
228 	 */
229 	VN_RELE(data->objfs_vfs_root);
230 
231 	kmem_free(data, sizeof (objfs_vfs_t));
232 
233 	return (0);
234 }
235 
236 static int
237 objfs_root(vfs_t *vfsp, vnode_t **vpp)
238 {
239 	objfs_vfs_t *data = vfsp->vfs_data;
240 
241 	*vpp = data->objfs_vfs_root;
242 	VN_HOLD(*vpp);
243 
244 	return (0);
245 }
246 
247 static int
248 objfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
249 {
250 	dev32_t d32;
251 	int total = objfs_nobjs();
252 
253 	bzero(sp, sizeof (*sp));
254 	sp->f_bsize = DEV_BSIZE;
255 	sp->f_frsize = DEV_BSIZE;
256 	sp->f_files = total;
257 	sp->f_ffree = sp->f_favail = INT_MAX - total;
258 	(void) cmpldev(&d32, vfsp->vfs_dev);
259 	sp->f_fsid = d32;
260 	(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
261 	    sizeof (sp->f_basetype));
262 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
263 	sp->f_namemax = OBJFS_NAME_MAX;
264 	(void) strlcpy(sp->f_fstr, "object", sizeof (sp->f_fstr));
265 
266 	return (0);
267 }
268 
269 static const fs_operation_def_t objfs_vfstops[] = {
270 	{ VFSNAME_MOUNT,	{ .vfs_mount = objfs_mount } },
271 	{ VFSNAME_UNMOUNT,	{ .vfs_unmount = objfs_unmount } },
272 	{ VFSNAME_ROOT,		{ .vfs_root = objfs_root } },
273 	{ VFSNAME_STATVFS,	{ .vfs_statvfs = objfs_statvfs } },
274 	{ NULL }
275 };
276