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) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/atomic.h>
26 #include <sys/cmn_err.h>
27 #include <sys/errno.h>
28 #include <sys/mount.h>
29 #include <sys/objfs.h>
30 #include <sys/objfs_impl.h>
31 #include <sys/vfs_opreg.h>
32 #include <sys/policy.h>
33 #include <sys/sunddi.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
38 * Kernel object filesystem.
40 * This is a pseudo filesystem which exports information about currently loaded
41 * kernel objects. The root directory contains one directory for each loaded
42 * object, indexed by module name. Within each object directory is an ELF file,
43 * 'object', that contains information about the currently loaded module.
45 * This file contains functions that interact with the VFS layer. Each
46 * filesystem element is represented by a a different node.
48 * / objfs_rootnode_t objfs_root.c
49 * /<obj> objfs_odirnode_t objfs_odir.c
50 * /<obj>/object objfs_datanode_t objfs_data.c
52 * In addition, some common routines are found in the 'objfs_common.c' file.
55 vnodeops_t
*objfs_ops_root
;
56 vnodeops_t
*objfs_ops_odir
;
57 vnodeops_t
*objfs_ops_data
;
59 static const fs_operation_def_t objfs_vfstops
[];
60 static gfs_opsvec_t objfs_opsvec
[];
62 static int objfs_init(int, char *);
67 static mntopts_t objfs_mntopts
= {
72 static vfsdef_t vfw
= {
76 VSW_HASPROTO
| VSW_ZMOUNT
,
80 extern struct mod_ops mod_fsops
;
82 static struct modlfs modlfs
= {
83 &mod_fsops
, "kernel object filesystem", &vfw
86 static struct modlinkage modlinkage
= {
87 MODREV_1
, (void *)&modlfs
, NULL
93 return (mod_install(&modlinkage
));
97 _info(struct modinfo
*modinfop
)
99 return (mod_info(&modlinkage
, modinfop
));
106 * The object filesystem cannot be unloaded.
112 * Filesystem initialization.
115 static int objfs_fstype
;
116 static major_t objfs_major
;
117 static minor_t objfs_minor
;
119 static gfs_opsvec_t objfs_opsvec
[] = {
120 { "objfs root directory", objfs_tops_root
, &objfs_ops_root
},
121 { "objfs object directory", objfs_tops_odir
, &objfs_ops_odir
},
122 { "objfs data file", objfs_tops_data
, &objfs_ops_data
},
128 objfs_init(int fstype
, char *name
)
133 objfs_fstype
= fstype
;
134 if (error
= vfs_setfsops(fstype
, objfs_vfstops
, &vfsops
)) {
135 cmn_err(CE_WARN
, "objfs_init: bad vfs ops template");
139 if (error
= gfs_make_opsvec(objfs_opsvec
)) {
140 (void) vfs_freevfsops(vfsops
);
144 if ((objfs_major
= getudev()) == (major_t
)-1) {
145 cmn_err(CE_WARN
, "objfs_init: can't get unique device number");
158 objfs_mount(vfs_t
*vfsp
, vnode_t
*mvp
, struct mounta
*uap
, cred_t
*cr
)
163 if (secpolicy_fs_mount(cr
, mvp
, vfsp
) != 0)
166 if (mvp
->v_type
!= VDIR
)
169 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
170 (mvp
->v_count
> 1 || (mvp
->v_flag
& VROOT
)))
173 data
= kmem_alloc(sizeof (objfs_vfs_t
), KM_SLEEP
);
176 * Initialize vfs fields
178 vfsp
->vfs_bsize
= DEV_BSIZE
;
179 vfsp
->vfs_fstype
= objfs_fstype
;
181 dev
= makedevice(objfs_major
,
182 atomic_inc_32_nv(&objfs_minor
) & L_MAXMIN32
);
183 } while (vfs_devismounted(dev
));
184 vfs_make_fsid(&vfsp
->vfs_fsid
, dev
, objfs_fstype
);
185 vfsp
->vfs_data
= data
;
191 data
->objfs_vfs_root
= objfs_create_root(vfsp
);
197 objfs_unmount(vfs_t
*vfsp
, int flag
, struct cred
*cr
)
201 if (secpolicy_fs_unmount(cr
, vfsp
) != 0)
205 * We do not currently support forced unmounts
211 * We should never have a reference count of less than 2: one for the
212 * caller, one for the root vnode.
214 ASSERT(vfsp
->vfs_count
>= 2);
217 * Any active vnodes will result in a hold on the root vnode
219 data
= vfsp
->vfs_data
;
220 if (data
->objfs_vfs_root
->v_count
> 1)
224 * Release the last hold on the root vnode
226 VN_RELE(data
->objfs_vfs_root
);
228 kmem_free(data
, sizeof (objfs_vfs_t
));
234 objfs_root(vfs_t
*vfsp
, vnode_t
**vpp
)
236 objfs_vfs_t
*data
= vfsp
->vfs_data
;
238 *vpp
= data
->objfs_vfs_root
;
245 objfs_statvfs(vfs_t
*vfsp
, statvfs64_t
*sp
)
248 int total
= objfs_nobjs();
250 bzero(sp
, sizeof (*sp
));
251 sp
->f_bsize
= DEV_BSIZE
;
252 sp
->f_frsize
= DEV_BSIZE
;
254 sp
->f_ffree
= sp
->f_favail
= INT_MAX
- total
;
255 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
257 (void) strlcpy(sp
->f_basetype
, vfssw
[vfsp
->vfs_fstype
].vsw_name
,
258 sizeof (sp
->f_basetype
));
259 sp
->f_flag
= vf_to_stf(vfsp
->vfs_flag
);
260 sp
->f_namemax
= OBJFS_NAME_MAX
;
261 (void) strlcpy(sp
->f_fstr
, "object", sizeof (sp
->f_fstr
));
266 static const fs_operation_def_t objfs_vfstops
[] = {
267 { VFSNAME_MOUNT
, { .vfs_mount
= objfs_mount
} },
268 { VFSNAME_UNMOUNT
, { .vfs_unmount
= objfs_unmount
} },
269 { VFSNAME_ROOT
, { .vfs_root
= objfs_root
} },
270 { VFSNAME_STATVFS
, { .vfs_statvfs
= objfs_statvfs
} },