xref: /netbsd-src/sys/miscfs/procfs/procfs_subr.c (revision 466a16a118933bd295a8a104f095714fadf9cf68)
1 /*	$NetBSD: procfs_subr.c,v 1.93 2008/12/17 20:51:36 cegger Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * Jan-Simon Pendry.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  *
63  *	@(#)procfs_subr.c	8.6 (Berkeley) 5/14/95
64  */
65 
66 /*
67  * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
68  * Copyright (c) 1993 Jan-Simon Pendry
69  *
70  * This code is derived from software contributed to Berkeley by
71  * Jan-Simon Pendry.
72  *
73  * Redistribution and use in source and binary forms, with or without
74  * modification, are permitted provided that the following conditions
75  * are met:
76  * 1. Redistributions of source code must retain the above copyright
77  *    notice, this list of conditions and the following disclaimer.
78  * 2. Redistributions in binary form must reproduce the above copyright
79  *    notice, this list of conditions and the following disclaimer in the
80  *    documentation and/or other materials provided with the distribution.
81  * 3. All advertising materials mentioning features or use of this software
82  *    must display the following acknowledgement:
83  *	This product includes software developed by the University of
84  *	California, Berkeley and its contributors.
85  * 4. Neither the name of the University nor the names of its contributors
86  *    may be used to endorse or promote products derived from this software
87  *    without specific prior written permission.
88  *
89  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
90  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
91  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
92  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
93  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
94  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
95  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
96  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
97  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
98  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99  * SUCH DAMAGE.
100  *
101  *	@(#)procfs_subr.c	8.6 (Berkeley) 5/14/95
102  */
103 
104 #include <sys/cdefs.h>
105 __KERNEL_RCSID(0, "$NetBSD: procfs_subr.c,v 1.93 2008/12/17 20:51:36 cegger Exp $");
106 
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/time.h>
110 #include <sys/kernel.h>
111 #include <sys/proc.h>
112 #include <sys/vnode.h>
113 #include <sys/malloc.h>
114 #include <sys/stat.h>
115 #include <sys/file.h>
116 #include <sys/filedesc.h>
117 #include <sys/kauth.h>
118 
119 #include <miscfs/procfs/procfs.h>
120 
121 void procfs_hashins(struct pfsnode *);
122 void procfs_hashrem(struct pfsnode *);
123 struct vnode *procfs_hashget(pid_t, pfstype, int, struct mount *, int);
124 
125 LIST_HEAD(pfs_hashhead, pfsnode) *pfs_hashtbl;
126 u_long	pfs_ihash;	/* size of hash table - 1 */
127 #define PFSPIDHASH(pid)	((pid) & pfs_ihash)
128 
129 kmutex_t pfs_hashlock;
130 kmutex_t pfs_ihash_lock;
131 
132 #define	ISSET(t, f)	((t) & (f))
133 
134 /*
135  * allocate a pfsnode/vnode pair.  the vnode is
136  * referenced, and locked.
137  *
138  * the pid, pfs_type, and mount point uniquely
139  * identify a pfsnode.  the mount point is needed
140  * because someone might mount this filesystem
141  * twice.
142  *
143  * all pfsnodes are maintained on a singly-linked
144  * list.  new nodes are only allocated when they cannot
145  * be found on this list.  entries on the list are
146  * removed when the vfs reclaim entry is called.
147  *
148  * a single lock is kept for the entire list.  this is
149  * needed because the getnewvnode() function can block
150  * waiting for a vnode to become free, in which case there
151  * may be more than one process trying to get the same
152  * vnode.  this lock is only taken if we are going to
153  * call getnewvnode, since the kernel itself is single-threaded.
154  *
155  * if an entry is found on the list, then call vget() to
156  * take a reference.  this is done because there may be
157  * zero references to it and so it needs to removed from
158  * the vnode free list.
159  */
160 int
161 procfs_allocvp(mp, vpp, pid, pfs_type, fd, p)
162 	struct mount *mp;
163 	struct vnode **vpp;
164 	pid_t pid;
165 	pfstype pfs_type;
166 	int fd;
167 	struct proc *p;
168 {
169 	struct pfsnode *pfs;
170 	struct vnode *vp;
171 	int error;
172 
173  retry:
174 	*vpp = procfs_hashget(pid, pfs_type, fd, mp, LK_EXCLUSIVE);
175 	if (*vpp != NULL)
176 		return (0);
177 
178 	if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, &vp)) != 0) {
179 		*vpp = NULL;
180 		return (error);
181 	}
182 	pfs = malloc(sizeof(struct pfsnode), M_TEMP, M_WAITOK);
183 
184 	mutex_enter(&pfs_hashlock);
185 	if ((*vpp = procfs_hashget(pid, pfs_type, fd, mp, 0)) != NULL) {
186 		mutex_exit(&pfs_hashlock);
187 		ungetnewvnode(vp);
188 		free(pfs, M_TEMP);
189 		goto retry;
190 	}
191 
192 	vp->v_data = pfs;
193 	pfs->pfs_pid = pid;
194 	pfs->pfs_type = pfs_type;
195 	pfs->pfs_vnode = vp;
196 	pfs->pfs_flags = 0;
197 	pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type, fd);
198 	pfs->pfs_fd = fd;
199 
200 	switch (pfs_type) {
201 	case PFSroot:	/* /proc = dr-xr-xr-x */
202 		vp->v_vflag |= VV_ROOT;
203 		/*FALLTHROUGH*/
204 	case PFSproc:	/* /proc/N = dr-xr-xr-x */
205 		pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
206 		vp->v_type = VDIR;
207 		break;
208 
209 	case PFScurproc:	/* /proc/curproc = lr-xr-xr-x */
210 	case PFSself:	/* /proc/self    = lr-xr-xr-x */
211 	case PFScwd:	/* /proc/N/cwd = lr-xr-xr-x */
212 	case PFSchroot:	/* /proc/N/chroot = lr-xr-xr-x */
213 	case PFSexe:	/* /proc/N/exe = lr-xr-xr-x */
214 		pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
215 		vp->v_type = VLNK;
216 		break;
217 
218 	case PFSfd:
219 		if (fd == -1) {	/* /proc/N/fd = dr-xr-xr-x */
220 			pfs->pfs_mode = S_IRUSR|S_IXUSR;
221 			vp->v_type = VDIR;
222 		} else {	/* /proc/N/fd/M = [ps-]rw------- */
223 			file_t *fp;
224 			vnode_t *vxp;
225 
226 			if ((fp = fd_getfile2(p, pfs->pfs_fd)) == NULL) {
227 				error = EBADF;
228 				goto bad;
229 			}
230 
231 			pfs->pfs_mode = S_IRUSR|S_IWUSR;
232 			switch (fp->f_type) {
233 			case DTYPE_VNODE:
234 				vxp = fp->f_data;
235 
236 				/*
237 				 * We make symlinks for directories
238 				 * to avoid cycles.
239 				 */
240 				if (vxp->v_type == VDIR)
241 					goto symlink;
242 				vp->v_type = vxp->v_type;
243 				break;
244 			case DTYPE_PIPE:
245 				vp->v_type = VFIFO;
246 				break;
247 			case DTYPE_SOCKET:
248 				vp->v_type = VSOCK;
249 				break;
250 			case DTYPE_KQUEUE:
251 			case DTYPE_MISC:
252 			symlink:
253 				pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|
254 				    S_IXGRP|S_IROTH|S_IXOTH;
255 				vp->v_type = VLNK;
256 				break;
257 			default:
258 				error = EOPNOTSUPP;
259 				closef(fp);
260 				goto bad;
261 			}
262 			closef(fp);
263 		}
264 		break;
265 
266 	case PFSfile:	/* /proc/N/file = -rw------- */
267 	case PFSmem:	/* /proc/N/mem = -rw------- */
268 	case PFSregs:	/* /proc/N/regs = -rw------- */
269 	case PFSfpregs:	/* /proc/N/fpregs = -rw------- */
270 		pfs->pfs_mode = S_IRUSR|S_IWUSR;
271 		vp->v_type = VREG;
272 		break;
273 
274 	case PFSctl:	/* /proc/N/ctl = --w------ */
275 	case PFSnote:	/* /proc/N/note = --w------ */
276 	case PFSnotepg:	/* /proc/N/notepg = --w------ */
277 		pfs->pfs_mode = S_IWUSR;
278 		vp->v_type = VREG;
279 		break;
280 
281 	case PFSmap:	/* /proc/N/map = -r--r--r-- */
282 	case PFSmaps:	/* /proc/N/maps = -r--r--r-- */
283 	case PFSstatus:	/* /proc/N/status = -r--r--r-- */
284 	case PFSstat:	/* /proc/N/stat = -r--r--r-- */
285 	case PFScmdline:	/* /proc/N/cmdline = -r--r--r-- */
286 	case PFSemul:	/* /proc/N/emul = -r--r--r-- */
287 	case PFSmeminfo:	/* /proc/meminfo = -r--r--r-- */
288 	case PFScpustat:	/* /proc/stat = -r--r--r-- */
289 	case PFSdevices:	/* /proc/devices = -r--r--r-- */
290 	case PFScpuinfo:	/* /proc/cpuinfo = -r--r--r-- */
291 	case PFSuptime:	/* /proc/uptime = -r--r--r-- */
292 	case PFSmounts:	/* /proc/mounts = -r--r--r-- */
293 	case PFSloadavg:	/* /proc/loadavg = -r--r--r-- */
294 	case PFSstatm:	/* /proc/N/statm = -r--r--r-- */
295 		pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH;
296 		vp->v_type = VREG;
297 		break;
298 
299 #ifdef __HAVE_PROCFS_MACHDEP
300 	PROCFS_MACHDEP_NODETYPE_CASES
301 		procfs_machdep_allocvp(vp);
302 		break;
303 #endif
304 
305 	default:
306 		panic("procfs_allocvp");
307 	}
308 
309 	procfs_hashins(pfs);
310 	uvm_vnp_setsize(vp, 0);
311 	mutex_exit(&pfs_hashlock);
312 
313 	*vpp = vp;
314 	return (0);
315 
316  bad:
317 	mutex_exit(&pfs_hashlock);
318 	free(pfs, M_TEMP);
319 	vp->v_data = NULL;
320 	ungetnewvnode(vp);
321 	return (error);
322 }
323 
324 int
325 procfs_freevp(vp)
326 	struct vnode *vp;
327 {
328 	struct pfsnode *pfs = VTOPFS(vp);
329 
330 	procfs_hashrem(pfs);
331 
332 	free(vp->v_data, M_TEMP);
333 	vp->v_data = NULL;
334 	return (0);
335 }
336 
337 int
338 procfs_rw(v)
339 	void *v;
340 {
341 	struct vop_read_args *ap = v;
342 	struct vnode *vp = ap->a_vp;
343 	struct uio *uio = ap->a_uio;
344 	struct lwp *curl;
345 	struct lwp *l;
346 	struct pfsnode *pfs = VTOPFS(vp);
347 	struct proc *p;
348 	int error;
349 
350 	if (uio->uio_offset < 0)
351 		return EINVAL;
352 
353 	if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0)
354 		return error;
355 
356 	curl = curlwp;
357 
358 	/*
359 	 * Do not allow init to be modified while in secure mode; it
360 	 * could be duped into changing the security level.
361 	 */
362 #define	M2K(m)	((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \
363 		 KAUTH_REQ_PROCESS_PROCFS_WRITE)
364 	mutex_enter(p->p_lock);
365 	error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS,
366 	    p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL);
367 	mutex_exit(p->p_lock);
368 	if (error) {
369 		procfs_proc_unlock(p);
370 		return (error);
371 	}
372 #undef	M2K
373 
374 	mutex_enter(p->p_lock);
375 	LIST_FOREACH(l, &p->p_lwps, l_sibling) {
376 		if (l->l_stat != LSZOMB)
377 			break;
378 	}
379 	/* Process is exiting if no-LWPS or all LWPs are LSZOMB */
380 	if (l == NULL) {
381 		mutex_exit(p->p_lock);
382 		procfs_proc_unlock(p);
383 		return ESRCH;
384 	}
385 
386 	lwp_addref(l);
387 	mutex_exit(p->p_lock);
388 
389 	switch (pfs->pfs_type) {
390 	case PFSnote:
391 	case PFSnotepg:
392 		error = procfs_donote(curl, p, pfs, uio);
393 		break;
394 
395 	case PFSregs:
396 		error = procfs_doregs(curl, l, pfs, uio);
397 		break;
398 
399 	case PFSfpregs:
400 		error = procfs_dofpregs(curl, l, pfs, uio);
401 		break;
402 
403 	case PFSctl:
404 		error = procfs_doctl(curl, l, pfs, uio);
405 		break;
406 
407 	case PFSstatus:
408 		error = procfs_dostatus(curl, l, pfs, uio);
409 		break;
410 
411 	case PFSstat:
412 		error = procfs_do_pid_stat(curl, l, pfs, uio);
413 		break;
414 
415 	case PFSmap:
416 		error = procfs_domap(curl, p, pfs, uio, 0);
417 		break;
418 
419 	case PFSmaps:
420 		error = procfs_domap(curl, p, pfs, uio, 1);
421 		break;
422 
423 	case PFSmem:
424 		error = procfs_domem(curl, l, pfs, uio);
425 		break;
426 
427 	case PFScmdline:
428 		error = procfs_docmdline(curl, p, pfs, uio);
429 		break;
430 
431 	case PFSmeminfo:
432 		error = procfs_domeminfo(curl, p, pfs, uio);
433 		break;
434 
435 	case PFSdevices:
436 		error = procfs_dodevices(curl, p, pfs, uio);
437 		break;
438 
439 	case PFScpuinfo:
440 		error = procfs_docpuinfo(curl, p, pfs, uio);
441 		break;
442 
443 	case PFScpustat:
444 		error = procfs_docpustat(curl, p, pfs, uio);
445 		break;
446 
447 	case PFSloadavg:
448 		error = procfs_doloadavg(curl, p, pfs, uio);
449 		break;
450 
451 	case PFSstatm:
452 		error = procfs_do_pid_statm(curl, l, pfs, uio);
453 		break;
454 
455 	case PFSfd:
456 		error = procfs_dofd(curl, p, pfs, uio);
457 		break;
458 
459 	case PFSuptime:
460 		error = procfs_douptime(curl, p, pfs, uio);
461 		break;
462 
463 	case PFSmounts:
464 		error = procfs_domounts(curl, p, pfs, uio);
465 		break;
466 
467 	case PFSemul:
468 		error = procfs_doemul(curl, p, pfs, uio);
469 		break;
470 
471 #ifdef __HAVE_PROCFS_MACHDEP
472 	PROCFS_MACHDEP_NODETYPE_CASES
473 		error = procfs_machdep_rw(curl, l, pfs, uio);
474 		break;
475 #endif
476 
477 	default:
478 		error = EOPNOTSUPP;
479 		break;
480 	}
481 
482 	/*
483 	 * Release the references that we acquired earlier.
484 	 */
485 	lwp_delref(l);
486 	procfs_proc_unlock(p);
487 
488 	return (error);
489 }
490 
491 /*
492  * Get a string from userland into (bf).  Strip a trailing
493  * nl character (to allow easy access from the shell).
494  * The buffer should be *buflenp + 1 chars long.  vfs_getuserstr
495  * will automatically add a nul char at the end.
496  *
497  * Returns 0 on success or the following errors
498  *
499  * EINVAL:    file offset is non-zero.
500  * EMSGSIZE:  message is longer than kernel buffer
501  * EFAULT:    user i/o buffer is not addressable
502  */
503 int
504 vfs_getuserstr(uio, bf, buflenp)
505 	struct uio *uio;
506 	char *bf;
507 	int *buflenp;
508 {
509 	int xlen;
510 	int error;
511 
512 	if (uio->uio_offset != 0)
513 		return (EINVAL);
514 
515 	xlen = *buflenp;
516 
517 	/* must be able to read the whole string in one go */
518 	if (xlen < uio->uio_resid)
519 		return (EMSGSIZE);
520 	xlen = uio->uio_resid;
521 
522 	if ((error = uiomove(bf, xlen, uio)) != 0)
523 		return (error);
524 
525 	/* allow multiple writes without seeks */
526 	uio->uio_offset = 0;
527 
528 	/* cleanup string and remove trailing newline */
529 	bf[xlen] = '\0';
530 	xlen = strlen(bf);
531 	if (xlen > 0 && bf[xlen-1] == '\n')
532 		bf[--xlen] = '\0';
533 	*buflenp = xlen;
534 
535 	return (0);
536 }
537 
538 const vfs_namemap_t *
539 vfs_findname(nm, bf, buflen)
540 	const vfs_namemap_t *nm;
541 	const char *bf;
542 	int buflen;
543 {
544 
545 	for (; nm->nm_name; nm++)
546 		if (memcmp(bf, nm->nm_name, buflen+1) == 0)
547 			return (nm);
548 
549 	return (0);
550 }
551 
552 /*
553  * Initialize pfsnode hash table.
554  */
555 void
556 procfs_hashinit()
557 {
558 	mutex_init(&pfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
559 	mutex_init(&pfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
560 	pfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, true, &pfs_ihash);
561 }
562 
563 void
564 procfs_hashreinit()
565 {
566 	struct pfsnode *pp;
567 	struct pfs_hashhead *oldhash, *hash;
568 	u_long i, oldmask, mask, val;
569 
570 	hash = hashinit(desiredvnodes / 4, HASH_LIST, true, &mask);
571 
572 	mutex_enter(&pfs_ihash_lock);
573 	oldhash = pfs_hashtbl;
574 	oldmask = pfs_ihash;
575 	pfs_hashtbl = hash;
576 	pfs_ihash = mask;
577 	for (i = 0; i <= oldmask; i++) {
578 		while ((pp = LIST_FIRST(&oldhash[i])) != NULL) {
579 			LIST_REMOVE(pp, pfs_hash);
580 			val = PFSPIDHASH(pp->pfs_pid);
581 			LIST_INSERT_HEAD(&hash[val], pp, pfs_hash);
582 		}
583 	}
584 	mutex_exit(&pfs_ihash_lock);
585 	hashdone(oldhash, HASH_LIST, oldmask);
586 }
587 
588 /*
589  * Free pfsnode hash table.
590  */
591 void
592 procfs_hashdone()
593 {
594 	hashdone(pfs_hashtbl, HASH_LIST, pfs_ihash);
595 	mutex_destroy(&pfs_hashlock);
596 	mutex_destroy(&pfs_ihash_lock);
597 }
598 
599 struct vnode *
600 procfs_hashget(pid, type, fd, mp, flags)
601 	pid_t pid;
602 	pfstype type;
603 	int fd;
604 	struct mount *mp;
605 	int flags;
606 {
607 	struct pfs_hashhead *ppp;
608 	struct pfsnode *pp;
609 	struct vnode *vp;
610 
611 loop:
612 	mutex_enter(&pfs_ihash_lock);
613 	ppp = &pfs_hashtbl[PFSPIDHASH(pid)];
614 	LIST_FOREACH(pp, ppp, pfs_hash) {
615 		vp = PFSTOV(pp);
616 		if (pid == pp->pfs_pid && pp->pfs_type == type &&
617 		    pp->pfs_fd == fd && vp->v_mount == mp) {
618 		    	if (flags == 0) {
619 				mutex_exit(&pfs_ihash_lock);
620 			} else {
621 				mutex_enter(&vp->v_interlock);
622 				mutex_exit(&pfs_ihash_lock);
623 				if (vget(vp, flags | LK_INTERLOCK))
624 					goto loop;
625 			}
626 			return (vp);
627 		}
628 	}
629 	mutex_exit(&pfs_ihash_lock);
630 	return (NULL);
631 }
632 
633 /*
634  * Insert the pfsnode into the hash table and lock it.
635  */
636 void
637 procfs_hashins(pp)
638 	struct pfsnode *pp;
639 {
640 	struct pfs_hashhead *ppp;
641 
642 	/* lock the pfsnode, then put it on the appropriate hash list */
643 	vlockmgr(&pp->pfs_vnode->v_lock, LK_EXCLUSIVE);
644 
645 	mutex_enter(&pfs_ihash_lock);
646 	ppp = &pfs_hashtbl[PFSPIDHASH(pp->pfs_pid)];
647 	LIST_INSERT_HEAD(ppp, pp, pfs_hash);
648 	mutex_exit(&pfs_ihash_lock);
649 }
650 
651 /*
652  * Remove the pfsnode from the hash table.
653  */
654 void
655 procfs_hashrem(pp)
656 	struct pfsnode *pp;
657 {
658 	mutex_enter(&pfs_ihash_lock);
659 	LIST_REMOVE(pp, pfs_hash);
660 	mutex_exit(&pfs_ihash_lock);
661 }
662 
663 void
664 procfs_revoke_vnodes(p, arg)
665 	struct proc *p;
666 	void *arg;
667 {
668 	struct pfsnode *pfs, *pnext;
669 	struct vnode *vp;
670 	struct mount *mp = (struct mount *)arg;
671 	struct pfs_hashhead *ppp;
672 
673 	if (!(p->p_flag & PK_SUGID))
674 		return;
675 
676 	mutex_enter(&pfs_ihash_lock);
677 	ppp = &pfs_hashtbl[PFSPIDHASH(p->p_pid)];
678 	for (pfs = LIST_FIRST(ppp); pfs; pfs = pnext) {
679 		vp = PFSTOV(pfs);
680 		pnext = LIST_NEXT(pfs, pfs_hash);
681 		mutex_enter(&vp->v_interlock);
682 		if (vp->v_usecount > 0 && pfs->pfs_pid == p->p_pid &&
683 		    vp->v_mount == mp) {
684 		    	vp->v_usecount++;
685 		    	mutex_exit(&vp->v_interlock);
686 			mutex_exit(&pfs_ihash_lock);
687 			VOP_REVOKE(vp, REVOKEALL);
688 			vrele(vp);
689 			mutex_enter(&pfs_ihash_lock);
690 		} else {
691 			mutex_exit(&vp->v_interlock);
692 		}
693 	}
694 	mutex_exit(&pfs_ihash_lock);
695 }
696 
697 int
698 procfs_proc_lock(int pid, struct proc **bunghole, int notfound)
699 {
700 	struct proc *tp;
701 	int error = 0;
702 
703 	mutex_enter(proc_lock);
704 
705 	if (pid == 0)
706 		tp = &proc0;
707 	else if ((tp = p_find(pid, PFIND_LOCKED)) == NULL)
708 		error = notfound;
709 	if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER))
710 		error = EBUSY;
711 
712 	mutex_exit(proc_lock);
713 
714 	*bunghole = tp;
715 	return error;
716 }
717 
718 void
719 procfs_proc_unlock(struct proc *p)
720 {
721 
722 	rw_exit(&p->p_reflock);
723 }
724 
725 int
726 procfs_doemul(struct lwp *curl, struct proc *p,
727     struct pfsnode *pfs, struct uio *uio)
728 {
729 	const char *ename = p->p_emul->e_name;
730 	return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio);
731 }
732