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/vfs_opreg.h>
45 #include <sys/vnode.h>
47 #include <sys/signal.h>
49 #include <sys/mount.h>
50 #include <sys/bitmap.h>
52 #include <sys/policy.h>
53 #include <fs/fs_subr.h>
54 #include <fs/proc/prdata.h>
57 * This is the loadable module wrapper.
59 #include <sys/modctl.h>
63 static mntopts_t proc_mntopts
= {
68 static vfsdef_t vfw
= {
72 VSW_HASPROTO
|VSW_STATS
|VSW_XID
|VSW_ZMOUNT
,
77 * Module linkage information for the kernel.
79 extern struct mod_ops mod_fsops
;
81 static struct modlfs modlfs
= {
82 &mod_fsops
, "filesystem for proc", &vfw
85 static struct modlinkage modlinkage
= {
86 MODREV_1
, (void *)&modlfs
, NULL
92 return (mod_install(&modlinkage
));
96 _info(struct modinfo
*modinfop
)
98 return (mod_info(&modlinkage
, modinfop
));
103 * No _fini routine. The module cannot be unloaded once loaded.
104 * The NO_UNLOAD_STUB in modstubs.s must change if this module
105 * is ever modified to become unloadable.
108 int nproc_highbit
; /* highbit(v.v_nproc) */
110 static int procfstype
;
111 static major_t procfs_major
;
112 static minor_t procfs_minor
;
113 static kmutex_t procfs_minor_lock
;
115 static kmutex_t pr_mount_lock
;
118 * /proc VFS operations vector.
120 static int prmount(), prunmount(), prroot(), prstatvfs();
123 prinitrootnode(prnode_t
*pnp
, vfs_t
*vfsp
)
127 bzero((caddr_t
)pnp
, sizeof (*pnp
));
128 pnp
->pr_vnode
= vp
= vn_alloc(KM_SLEEP
);
130 mutex_init(&pnp
->pr_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
131 vp
->v_flag
= VROOT
|VNOCACHE
|VNOMAP
|VNOSWAP
|VNOMOUNT
;
132 VN_SET_VFS_TYPE_DEV(vp
, vfsp
, VDIR
, 0);
133 vn_setops(vp
, prvnodeops
);
134 vp
->v_data
= (caddr_t
)pnp
;
135 pnp
->pr_type
= PR_PROCDIR
;
136 pnp
->pr_mode
= 0555; /* read-search by everyone */
141 prinit(int fstype
, char *name
)
143 static const fs_operation_def_t pr_vfsops_template
[] = {
144 VFSNAME_MOUNT
, { .vfs_mount
= prmount
},
145 VFSNAME_UNMOUNT
, { .vfs_unmount
= prunmount
},
146 VFSNAME_ROOT
, { .vfs_root
= prroot
},
147 VFSNAME_STATVFS
, { .vfs_statvfs
= prstatvfs
},
150 extern const fs_operation_def_t pr_vnodeops_template
[];
153 nproc_highbit
= highbit(v
.v_proc
);
155 ASSERT(procfstype
!= 0);
157 * Associate VFS ops vector with this fstype.
159 error
= vfs_setfsops(fstype
, pr_vfsops_template
, NULL
);
161 cmn_err(CE_WARN
, "prinit: bad vfs ops template");
166 * Set up vnode ops vector too.
169 error
= vn_make_ops(name
, pr_vnodeops_template
, &prvnodeops
);
171 (void) vfs_freevfsops_by_type(fstype
);
172 cmn_err(CE_WARN
, "prinit: bad vnode ops template");
177 * Assign a unique "device" number (used by stat(2)).
179 if ((procfs_major
= getudev()) == (major_t
)-1) {
180 cmn_err(CE_WARN
, "prinit: can't get unique device number");
183 mutex_init(&pr_mount_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
184 mutex_init(&procfs_minor_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
191 prmount(struct vfs
*vfsp
, struct vnode
*mvp
,
192 struct mounta
*uap
, struct cred
*cr
)
195 zone_t
*zone
= curproc
->p_zone
;
197 if (secpolicy_fs_mount(cr
, mvp
, vfsp
) != 0)
200 if (mvp
->v_type
!= VDIR
)
203 if (zone
== global_zone
) {
206 mntzone
= zone_find_by_path(refstr_value(vfsp
->vfs_mntpt
));
212 * Having the resource be anything but "proc" doesn't make sense
214 vfs_setresource(vfsp
, "proc", 0);
216 pnp
= kmem_alloc(sizeof (*pnp
), KM_SLEEP
);
217 mutex_enter(&pr_mount_lock
);
219 mutex_enter(&mvp
->v_lock
);
220 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
221 (mvp
->v_count
> 1 || (mvp
->v_flag
& VROOT
))) {
222 mutex_exit(&mvp
->v_lock
);
223 mutex_exit(&pr_mount_lock
);
224 kmem_free(pnp
, sizeof (*pnp
));
227 mutex_exit(&mvp
->v_lock
);
229 prinitrootnode(pnp
, vfsp
);
230 vfsp
->vfs_fstype
= procfstype
;
231 vfsp
->vfs_data
= (caddr_t
)pnp
;
232 vfsp
->vfs_bsize
= DEV_BSIZE
;
234 * find an available minor device number for this mount
236 mutex_enter(&procfs_minor_lock
);
238 vfsp
->vfs_dev
= makedevice(procfs_major
, procfs_minor
);
239 procfs_minor
= (procfs_minor
+ 1) & L_MAXMIN32
;
240 } while (vfs_devismounted(vfsp
->vfs_dev
));
241 mutex_exit(&procfs_minor_lock
);
242 vfs_make_fsid(&vfsp
->vfs_fsid
, vfsp
->vfs_dev
, procfstype
);
244 mutex_exit(&pr_mount_lock
);
250 prunmount(struct vfs
*vfsp
, int flag
, struct cred
*cr
)
252 prnode_t
*pnp
= (prnode_t
*)vfsp
->vfs_data
;
253 vnode_t
*vp
= PTOV(pnp
);
255 mutex_enter(&pr_mount_lock
);
256 if (secpolicy_fs_unmount(cr
, vfsp
) != 0) {
257 mutex_exit(&pr_mount_lock
);
262 * forced unmount is not supported by this file system
263 * and thus, ENOTSUP, is being returned.
265 if (flag
& MS_FORCE
) {
266 mutex_exit(&pr_mount_lock
);
271 * Ensure that no /proc vnodes are in use on this mount point.
273 mutex_enter(&vp
->v_lock
);
274 if (vp
->v_count
> 1) {
275 mutex_exit(&vp
->v_lock
);
276 mutex_exit(&pr_mount_lock
);
280 mutex_exit(&vp
->v_lock
);
281 mutex_exit(&pr_mount_lock
);
284 kmem_free(pnp
, sizeof (*pnp
));
290 prroot(struct vfs
*vfsp
, struct vnode
**vpp
)
292 vnode_t
*vp
= PTOV((prnode_t
*)vfsp
->vfs_data
);
300 prstatvfs(struct vfs
*vfsp
, struct statvfs64
*sp
)
306 n
= v
.v_proc
- nproc
;
308 bzero((caddr_t
)sp
, sizeof (*sp
));
309 sp
->f_bsize
= DEV_BSIZE
;
310 sp
->f_frsize
= DEV_BSIZE
;
311 sp
->f_blocks
= (fsblkcnt64_t
)0;
312 sp
->f_bfree
= (fsblkcnt64_t
)0;
313 sp
->f_bavail
= (fsblkcnt64_t
)0;
314 sp
->f_files
= (fsfilcnt64_t
)v
.v_proc
+ 2;
315 sp
->f_ffree
= (fsfilcnt64_t
)n
;
316 sp
->f_favail
= (fsfilcnt64_t
)n
;
317 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
319 (void) strcpy(sp
->f_basetype
, vfssw
[procfstype
].vsw_name
);
320 sp
->f_flag
= vf_to_stf(vfsp
->vfs_flag
);
321 sp
->f_namemax
= 64; /* quite arbitrary */
322 bzero(sp
->f_fstr
, sizeof (sp
->f_fstr
));
323 (void) strcpy(sp
->f_fstr
, "/proc");
324 (void) strcpy(&sp
->f_fstr
[6], "/proc");