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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/cmn_err.h>
33 #include <sys/debug.h>
34 #include <sys/errno.h>
36 #include <sys/procfs.h>
38 #include <sys/statvfs.h>
39 #include <sys/sysmacros.h>
40 #include <sys/systm.h>
44 #include <sys/vnode.h>
46 #include <sys/signal.h>
48 #include <sys/mount.h>
49 #include <sys/bitmap.h>
51 #include <sys/policy.h>
52 #include <sys/fs_subr.h>
53 #include <sys/proc/prdata.h>
56 * This is the loadable module wrapper.
58 #include <sys/modctl.h>
62 static mntopts_t proc_mntopts
= {
67 static vfsdef_t vfw
= {
71 VSW_HASPROTO
|VSW_STATS
|VSW_XID
|VSW_ZMOUNT
,
76 * Module linkage information for the kernel.
78 extern struct mod_ops mod_fsops
;
80 static struct modlfs modlfs
= {
81 &mod_fsops
, "filesystem for proc", &vfw
84 static struct modlinkage modlinkage
= {
85 MODREV_1
, (void *)&modlfs
, NULL
91 return (mod_install(&modlinkage
));
95 _info(struct modinfo
*modinfop
)
97 return (mod_info(&modlinkage
, modinfop
));
102 * No _fini routine. The module cannot be unloaded once loaded.
103 * The NO_UNLOAD_STUB in modstubs.s must change if this module
104 * is ever modified to become unloadable.
107 int nproc_highbit
; /* highbit(v.v_nproc) */
109 static int procfstype
;
110 static major_t procfs_major
;
111 static minor_t procfs_minor
;
112 static kmutex_t procfs_minor_lock
;
114 static kmutex_t pr_mount_lock
;
117 * /proc VFS operations vector.
119 static int prmount(), prunmount(), prroot(), prstatvfs();
121 static const struct vfsops pr_vfsops
= {
122 .vfs_mount
= prmount
,
123 .vfs_unmount
= prunmount
,
125 .vfs_statvfs
= prstatvfs
,
129 prinitrootnode(prnode_t
*pnp
, vfs_t
*vfsp
)
133 bzero((caddr_t
)pnp
, sizeof (*pnp
));
134 pnp
->pr_vnode
= vp
= vn_alloc(KM_SLEEP
);
136 mutex_init(&pnp
->pr_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
137 vp
->v_flag
= VROOT
|VNOCACHE
|VNOMAP
|VNOSWAP
|VNOMOUNT
;
138 VN_SET_VFS_TYPE_DEV(vp
, vfsp
, VDIR
, 0);
139 vn_setops(vp
, &prvnodeops
);
140 vp
->v_data
= (caddr_t
)pnp
;
141 pnp
->pr_type
= PR_PROCDIR
;
142 pnp
->pr_mode
= 0555; /* read-search by everyone */
147 prinit(int fstype
, char *name
)
151 nproc_highbit
= highbit(v
.v_proc
);
153 ASSERT(procfstype
!= 0);
155 * Associate VFS ops vector with this fstype.
157 error
= vfs_setfsops(fstype
, &pr_vfsops
);
159 cmn_err(CE_WARN
, "prinit: bad vfs ops template");
164 * Assign a unique "device" number (used by stat(2)).
166 if ((procfs_major
= getudev()) == (major_t
)-1) {
167 cmn_err(CE_WARN
, "prinit: can't get unique device number");
170 mutex_init(&pr_mount_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
171 mutex_init(&procfs_minor_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
178 prmount(struct vfs
*vfsp
, struct vnode
*mvp
,
179 struct mounta
*uap
, struct cred
*cr
)
182 zone_t
*zone
= curproc
->p_zone
;
184 if (secpolicy_fs_mount(cr
, mvp
, vfsp
) != 0)
187 if (mvp
->v_type
!= VDIR
)
190 if (zone
== global_zone
) {
193 mntzone
= zone_find_by_path(refstr_value(vfsp
->vfs_mntpt
));
199 * Having the resource be anything but "proc" doesn't make sense
201 vfs_setresource(vfsp
, "proc", 0);
203 pnp
= kmem_alloc(sizeof (*pnp
), KM_SLEEP
);
204 mutex_enter(&pr_mount_lock
);
206 mutex_enter(&mvp
->v_lock
);
207 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
208 (mvp
->v_count
> 1 || (mvp
->v_flag
& VROOT
))) {
209 mutex_exit(&mvp
->v_lock
);
210 mutex_exit(&pr_mount_lock
);
211 kmem_free(pnp
, sizeof (*pnp
));
214 mutex_exit(&mvp
->v_lock
);
216 prinitrootnode(pnp
, vfsp
);
217 vfsp
->vfs_fstype
= procfstype
;
218 vfsp
->vfs_data
= (caddr_t
)pnp
;
219 vfsp
->vfs_bsize
= DEV_BSIZE
;
221 * find an available minor device number for this mount
223 mutex_enter(&procfs_minor_lock
);
225 vfsp
->vfs_dev
= makedevice(procfs_major
, procfs_minor
);
226 procfs_minor
= (procfs_minor
+ 1) & L_MAXMIN32
;
227 } while (vfs_devismounted(vfsp
->vfs_dev
));
228 mutex_exit(&procfs_minor_lock
);
229 vfs_make_fsid(&vfsp
->vfs_fsid
, vfsp
->vfs_dev
, procfstype
);
231 mutex_exit(&pr_mount_lock
);
237 prunmount(struct vfs
*vfsp
, int flag
, struct cred
*cr
)
239 prnode_t
*pnp
= (prnode_t
*)vfsp
->vfs_data
;
240 vnode_t
*vp
= PTOV(pnp
);
242 mutex_enter(&pr_mount_lock
);
243 if (secpolicy_fs_unmount(cr
, vfsp
) != 0) {
244 mutex_exit(&pr_mount_lock
);
249 * forced unmount is not supported by this file system
250 * and thus, ENOTSUP, is being returned.
252 if (flag
& MS_FORCE
) {
253 mutex_exit(&pr_mount_lock
);
258 * Ensure that no /proc vnodes are in use on this mount point.
260 mutex_enter(&vp
->v_lock
);
261 if (vp
->v_count
> 1) {
262 mutex_exit(&vp
->v_lock
);
263 mutex_exit(&pr_mount_lock
);
267 mutex_exit(&vp
->v_lock
);
268 mutex_exit(&pr_mount_lock
);
271 kmem_free(pnp
, sizeof (*pnp
));
277 prroot(struct vfs
*vfsp
, struct vnode
**vpp
)
279 vnode_t
*vp
= PTOV((prnode_t
*)vfsp
->vfs_data
);
287 prstatvfs(struct vfs
*vfsp
, struct statvfs64
*sp
)
293 n
= v
.v_proc
- nproc
;
295 bzero((caddr_t
)sp
, sizeof (*sp
));
296 sp
->f_bsize
= DEV_BSIZE
;
297 sp
->f_frsize
= DEV_BSIZE
;
298 sp
->f_blocks
= (fsblkcnt64_t
)0;
299 sp
->f_bfree
= (fsblkcnt64_t
)0;
300 sp
->f_bavail
= (fsblkcnt64_t
)0;
301 sp
->f_files
= (fsfilcnt64_t
)v
.v_proc
+ 2;
302 sp
->f_ffree
= (fsfilcnt64_t
)n
;
303 sp
->f_favail
= (fsfilcnt64_t
)n
;
304 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
306 (void) strcpy(sp
->f_basetype
, vfssw
[procfstype
].vsw_name
);
307 sp
->f_flag
= vf_to_stf(vfsp
->vfs_flag
);
308 sp
->f_namemax
= 64; /* quite arbitrary */
309 bzero(sp
->f_fstr
, sizeof (sp
->f_fstr
));
310 (void) strcpy(sp
->f_fstr
, "/proc");
311 (void) strcpy(&sp
->f_fstr
[6], "/proc");