1 /* $NetBSD: procfs_subr.c,v 1.100 2011/09/04 17:32:10 jmcneill 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.100 2011/09/04 17:32:10 jmcneill 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(struct mount *mp, struct vnode **vpp, pid_t pid, 162 pfstype pfs_type, int fd, struct proc *p) 163 { 164 struct pfsnode *pfs; 165 struct vnode *vp; 166 int error; 167 168 retry: 169 *vpp = procfs_hashget(pid, pfs_type, fd, mp, LK_EXCLUSIVE); 170 if (*vpp != NULL) 171 return (0); 172 173 error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, NULL, &vp); 174 if (error) { 175 *vpp = NULL; 176 return (error); 177 } 178 pfs = malloc(sizeof(struct pfsnode), M_TEMP, M_WAITOK); 179 180 mutex_enter(&pfs_hashlock); 181 if ((*vpp = procfs_hashget(pid, pfs_type, fd, mp, 0)) != NULL) { 182 mutex_exit(&pfs_hashlock); 183 ungetnewvnode(vp); 184 free(pfs, M_TEMP); 185 goto retry; 186 } 187 188 vp->v_data = pfs; 189 pfs->pfs_pid = pid; 190 pfs->pfs_type = pfs_type; 191 pfs->pfs_vnode = vp; 192 pfs->pfs_flags = 0; 193 pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type, fd); 194 pfs->pfs_fd = fd; 195 196 switch (pfs_type) { 197 case PFSroot: /* /proc = dr-xr-xr-x */ 198 vp->v_vflag |= VV_ROOT; 199 /*FALLTHROUGH*/ 200 case PFSproc: /* /proc/N = dr-xr-xr-x */ 201 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 202 vp->v_type = VDIR; 203 break; 204 205 case PFScurproc: /* /proc/curproc = lr-xr-xr-x */ 206 case PFSself: /* /proc/self = lr-xr-xr-x */ 207 case PFScwd: /* /proc/N/cwd = lr-xr-xr-x */ 208 case PFSchroot: /* /proc/N/chroot = lr-xr-xr-x */ 209 case PFSexe: /* /proc/N/exe = lr-xr-xr-x */ 210 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 211 vp->v_type = VLNK; 212 break; 213 214 case PFSfd: 215 if (fd == -1) { /* /proc/N/fd = dr-xr-xr-x */ 216 pfs->pfs_mode = S_IRUSR|S_IXUSR; 217 vp->v_type = VDIR; 218 } else { /* /proc/N/fd/M = [ps-]rw------- */ 219 file_t *fp; 220 vnode_t *vxp; 221 222 if ((fp = fd_getfile2(p, pfs->pfs_fd)) == NULL) { 223 error = EBADF; 224 goto bad; 225 } 226 227 pfs->pfs_mode = S_IRUSR|S_IWUSR; 228 switch (fp->f_type) { 229 case DTYPE_VNODE: 230 vxp = fp->f_data; 231 232 /* 233 * We make symlinks for directories 234 * to avoid cycles. 235 */ 236 if (vxp->v_type == VDIR) 237 goto symlink; 238 vp->v_type = vxp->v_type; 239 break; 240 case DTYPE_PIPE: 241 vp->v_type = VFIFO; 242 break; 243 case DTYPE_SOCKET: 244 vp->v_type = VSOCK; 245 break; 246 case DTYPE_KQUEUE: 247 case DTYPE_MISC: 248 symlink: 249 pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP| 250 S_IXGRP|S_IROTH|S_IXOTH; 251 vp->v_type = VLNK; 252 break; 253 default: 254 error = EOPNOTSUPP; 255 closef(fp); 256 goto bad; 257 } 258 closef(fp); 259 } 260 break; 261 262 case PFSfile: /* /proc/N/file = -rw------- */ 263 case PFSmem: /* /proc/N/mem = -rw------- */ 264 case PFSregs: /* /proc/N/regs = -rw------- */ 265 case PFSfpregs: /* /proc/N/fpregs = -rw------- */ 266 pfs->pfs_mode = S_IRUSR|S_IWUSR; 267 vp->v_type = VREG; 268 break; 269 270 case PFSctl: /* /proc/N/ctl = --w------ */ 271 case PFSnote: /* /proc/N/note = --w------ */ 272 case PFSnotepg: /* /proc/N/notepg = --w------ */ 273 pfs->pfs_mode = S_IWUSR; 274 vp->v_type = VREG; 275 break; 276 277 case PFSmap: /* /proc/N/map = -r--r--r-- */ 278 case PFSmaps: /* /proc/N/maps = -r--r--r-- */ 279 case PFSstatus: /* /proc/N/status = -r--r--r-- */ 280 case PFSstat: /* /proc/N/stat = -r--r--r-- */ 281 case PFScmdline: /* /proc/N/cmdline = -r--r--r-- */ 282 case PFSemul: /* /proc/N/emul = -r--r--r-- */ 283 case PFSmeminfo: /* /proc/meminfo = -r--r--r-- */ 284 case PFScpustat: /* /proc/stat = -r--r--r-- */ 285 case PFSdevices: /* /proc/devices = -r--r--r-- */ 286 case PFScpuinfo: /* /proc/cpuinfo = -r--r--r-- */ 287 case PFSuptime: /* /proc/uptime = -r--r--r-- */ 288 case PFSmounts: /* /proc/mounts = -r--r--r-- */ 289 case PFSloadavg: /* /proc/loadavg = -r--r--r-- */ 290 case PFSstatm: /* /proc/N/statm = -r--r--r-- */ 291 case PFSversion: /* /proc/version = -r--r--r-- */ 292 pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH; 293 vp->v_type = VREG; 294 break; 295 296 #ifdef __HAVE_PROCFS_MACHDEP 297 PROCFS_MACHDEP_NODETYPE_CASES 298 procfs_machdep_allocvp(vp); 299 break; 300 #endif 301 302 default: 303 panic("procfs_allocvp"); 304 } 305 306 procfs_hashins(pfs); 307 uvm_vnp_setsize(vp, 0); 308 mutex_exit(&pfs_hashlock); 309 310 *vpp = vp; 311 return (0); 312 313 bad: 314 mutex_exit(&pfs_hashlock); 315 free(pfs, M_TEMP); 316 vp->v_data = NULL; 317 ungetnewvnode(vp); 318 return (error); 319 } 320 321 int 322 procfs_freevp(struct vnode *vp) 323 { 324 struct pfsnode *pfs = VTOPFS(vp); 325 326 procfs_hashrem(pfs); 327 328 free(vp->v_data, M_TEMP); 329 vp->v_data = NULL; 330 return (0); 331 } 332 333 int 334 procfs_rw(void *v) 335 { 336 struct vop_read_args *ap = v; 337 struct vnode *vp = ap->a_vp; 338 struct uio *uio = ap->a_uio; 339 struct lwp *curl; 340 struct lwp *l; 341 struct pfsnode *pfs = VTOPFS(vp); 342 struct proc *p; 343 int error; 344 345 if (uio->uio_offset < 0) 346 return EINVAL; 347 348 if ((error = procfs_proc_lock(pfs->pfs_pid, &p, ESRCH)) != 0) 349 return error; 350 351 curl = curlwp; 352 353 /* 354 * Do not allow init to be modified while in secure mode; it 355 * could be duped into changing the security level. 356 */ 357 #define M2K(m) ((m) == UIO_READ ? KAUTH_REQ_PROCESS_PROCFS_READ : \ 358 KAUTH_REQ_PROCESS_PROCFS_WRITE) 359 mutex_enter(p->p_lock); 360 error = kauth_authorize_process(curl->l_cred, KAUTH_PROCESS_PROCFS, 361 p, pfs, KAUTH_ARG(M2K(uio->uio_rw)), NULL); 362 mutex_exit(p->p_lock); 363 if (error) { 364 procfs_proc_unlock(p); 365 return (error); 366 } 367 #undef M2K 368 369 mutex_enter(p->p_lock); 370 LIST_FOREACH(l, &p->p_lwps, l_sibling) { 371 if (l->l_stat != LSZOMB) 372 break; 373 } 374 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */ 375 if (l == NULL) { 376 mutex_exit(p->p_lock); 377 procfs_proc_unlock(p); 378 return ESRCH; 379 } 380 381 lwp_addref(l); 382 mutex_exit(p->p_lock); 383 384 switch (pfs->pfs_type) { 385 case PFSnote: 386 case PFSnotepg: 387 error = procfs_donote(curl, p, pfs, uio); 388 break; 389 390 case PFSregs: 391 error = procfs_doregs(curl, l, pfs, uio); 392 break; 393 394 case PFSfpregs: 395 error = procfs_dofpregs(curl, l, pfs, uio); 396 break; 397 398 case PFSctl: 399 error = procfs_doctl(curl, l, pfs, uio); 400 break; 401 402 case PFSstatus: 403 error = procfs_dostatus(curl, l, pfs, uio); 404 break; 405 406 case PFSstat: 407 error = procfs_do_pid_stat(curl, l, pfs, uio); 408 break; 409 410 case PFSmap: 411 error = procfs_domap(curl, p, pfs, uio, 0); 412 break; 413 414 case PFSmaps: 415 error = procfs_domap(curl, p, pfs, uio, 1); 416 break; 417 418 case PFSmem: 419 error = procfs_domem(curl, l, pfs, uio); 420 break; 421 422 case PFScmdline: 423 error = procfs_docmdline(curl, p, pfs, uio); 424 break; 425 426 case PFSmeminfo: 427 error = procfs_domeminfo(curl, p, pfs, uio); 428 break; 429 430 case PFSdevices: 431 error = procfs_dodevices(curl, p, pfs, uio); 432 break; 433 434 case PFScpuinfo: 435 error = procfs_docpuinfo(curl, p, pfs, uio); 436 break; 437 438 case PFScpustat: 439 error = procfs_docpustat(curl, p, pfs, uio); 440 break; 441 442 case PFSloadavg: 443 error = procfs_doloadavg(curl, p, pfs, uio); 444 break; 445 446 case PFSstatm: 447 error = procfs_do_pid_statm(curl, l, pfs, uio); 448 break; 449 450 case PFSfd: 451 error = procfs_dofd(curl, p, pfs, uio); 452 break; 453 454 case PFSuptime: 455 error = procfs_douptime(curl, p, pfs, uio); 456 break; 457 458 case PFSmounts: 459 error = procfs_domounts(curl, p, pfs, uio); 460 break; 461 462 case PFSemul: 463 error = procfs_doemul(curl, p, pfs, uio); 464 break; 465 466 case PFSversion: 467 error = procfs_doversion(curl, p, pfs, uio); 468 break; 469 470 #ifdef __HAVE_PROCFS_MACHDEP 471 PROCFS_MACHDEP_NODETYPE_CASES 472 error = procfs_machdep_rw(curl, l, pfs, uio); 473 break; 474 #endif 475 476 default: 477 error = EOPNOTSUPP; 478 break; 479 } 480 481 /* 482 * Release the references that we acquired earlier. 483 */ 484 lwp_delref(l); 485 procfs_proc_unlock(p); 486 487 return (error); 488 } 489 490 /* 491 * Get a string from userland into (bf). Strip a trailing 492 * nl character (to allow easy access from the shell). 493 * The buffer should be *buflenp + 1 chars long. vfs_getuserstr 494 * will automatically add a nul char at the end. 495 * 496 * Returns 0 on success or the following errors 497 * 498 * EINVAL: file offset is non-zero. 499 * EMSGSIZE: message is longer than kernel buffer 500 * EFAULT: user i/o buffer is not addressable 501 */ 502 int 503 vfs_getuserstr(struct uio *uio, char *bf, int *buflenp) 504 { 505 int xlen; 506 int error; 507 508 if (uio->uio_offset != 0) 509 return (EINVAL); 510 511 xlen = *buflenp; 512 513 /* must be able to read the whole string in one go */ 514 if (xlen < uio->uio_resid) 515 return (EMSGSIZE); 516 xlen = uio->uio_resid; 517 518 if ((error = uiomove(bf, xlen, uio)) != 0) 519 return (error); 520 521 /* allow multiple writes without seeks */ 522 uio->uio_offset = 0; 523 524 /* cleanup string and remove trailing newline */ 525 bf[xlen] = '\0'; 526 xlen = strlen(bf); 527 if (xlen > 0 && bf[xlen-1] == '\n') 528 bf[--xlen] = '\0'; 529 *buflenp = xlen; 530 531 return (0); 532 } 533 534 const vfs_namemap_t * 535 vfs_findname(const vfs_namemap_t *nm, const char *bf, int buflen) 536 { 537 538 for (; nm->nm_name; nm++) 539 if (memcmp(bf, nm->nm_name, buflen+1) == 0) 540 return (nm); 541 542 return (0); 543 } 544 545 /* 546 * Initialize pfsnode hash table. 547 */ 548 void 549 procfs_hashinit(void) 550 { 551 mutex_init(&pfs_hashlock, MUTEX_DEFAULT, IPL_NONE); 552 mutex_init(&pfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE); 553 pfs_hashtbl = hashinit(desiredvnodes / 4, HASH_LIST, true, &pfs_ihash); 554 } 555 556 void 557 procfs_hashreinit(void) 558 { 559 struct pfsnode *pp; 560 struct pfs_hashhead *oldhash, *hash; 561 u_long i, oldmask, mask, val; 562 563 hash = hashinit(desiredvnodes / 4, HASH_LIST, true, &mask); 564 565 mutex_enter(&pfs_ihash_lock); 566 oldhash = pfs_hashtbl; 567 oldmask = pfs_ihash; 568 pfs_hashtbl = hash; 569 pfs_ihash = mask; 570 for (i = 0; i <= oldmask; i++) { 571 while ((pp = LIST_FIRST(&oldhash[i])) != NULL) { 572 LIST_REMOVE(pp, pfs_hash); 573 val = PFSPIDHASH(pp->pfs_pid); 574 LIST_INSERT_HEAD(&hash[val], pp, pfs_hash); 575 } 576 } 577 mutex_exit(&pfs_ihash_lock); 578 hashdone(oldhash, HASH_LIST, oldmask); 579 } 580 581 /* 582 * Free pfsnode hash table. 583 */ 584 void 585 procfs_hashdone(void) 586 { 587 hashdone(pfs_hashtbl, HASH_LIST, pfs_ihash); 588 mutex_destroy(&pfs_hashlock); 589 mutex_destroy(&pfs_ihash_lock); 590 } 591 592 struct vnode * 593 procfs_hashget(pid_t pid, pfstype type, int fd, struct mount *mp, int flags) 594 { 595 struct pfs_hashhead *ppp; 596 struct pfsnode *pp; 597 struct vnode *vp; 598 599 loop: 600 mutex_enter(&pfs_ihash_lock); 601 ppp = &pfs_hashtbl[PFSPIDHASH(pid)]; 602 LIST_FOREACH(pp, ppp, pfs_hash) { 603 vp = PFSTOV(pp); 604 if (pid == pp->pfs_pid && pp->pfs_type == type && 605 pp->pfs_fd == fd && vp->v_mount == mp) { 606 if (flags == 0) { 607 mutex_exit(&pfs_ihash_lock); 608 } else { 609 mutex_enter(vp->v_interlock); 610 mutex_exit(&pfs_ihash_lock); 611 if (vget(vp, flags)) 612 goto loop; 613 } 614 return (vp); 615 } 616 } 617 mutex_exit(&pfs_ihash_lock); 618 return (NULL); 619 } 620 621 /* 622 * Insert the pfsnode into the hash table and lock it. 623 */ 624 void 625 procfs_hashins(struct pfsnode *pp) 626 { 627 struct pfs_hashhead *ppp; 628 629 /* lock the pfsnode, then put it on the appropriate hash list */ 630 VOP_LOCK(PFSTOV(pp), LK_EXCLUSIVE); 631 632 mutex_enter(&pfs_ihash_lock); 633 ppp = &pfs_hashtbl[PFSPIDHASH(pp->pfs_pid)]; 634 LIST_INSERT_HEAD(ppp, pp, pfs_hash); 635 mutex_exit(&pfs_ihash_lock); 636 } 637 638 /* 639 * Remove the pfsnode from the hash table. 640 */ 641 void 642 procfs_hashrem(struct pfsnode *pp) 643 { 644 mutex_enter(&pfs_ihash_lock); 645 LIST_REMOVE(pp, pfs_hash); 646 mutex_exit(&pfs_ihash_lock); 647 } 648 649 void 650 procfs_revoke_vnodes(struct proc *p, void *arg) 651 { 652 struct pfsnode *pfs, *pnext; 653 struct vnode *vp; 654 struct mount *mp = (struct mount *)arg; 655 struct pfs_hashhead *ppp; 656 657 if (!(p->p_flag & PK_SUGID)) 658 return; 659 660 mutex_enter(&pfs_ihash_lock); 661 ppp = &pfs_hashtbl[PFSPIDHASH(p->p_pid)]; 662 for (pfs = LIST_FIRST(ppp); pfs; pfs = pnext) { 663 vp = PFSTOV(pfs); 664 pnext = LIST_NEXT(pfs, pfs_hash); 665 mutex_enter(vp->v_interlock); 666 if (vp->v_usecount > 0 && pfs->pfs_pid == p->p_pid && 667 vp->v_mount == mp) { 668 vp->v_usecount++; 669 mutex_exit(vp->v_interlock); 670 mutex_exit(&pfs_ihash_lock); 671 VOP_REVOKE(vp, REVOKEALL); 672 vrele(vp); 673 mutex_enter(&pfs_ihash_lock); 674 } else { 675 mutex_exit(vp->v_interlock); 676 } 677 } 678 mutex_exit(&pfs_ihash_lock); 679 } 680 681 int 682 procfs_proc_lock(int pid, struct proc **bunghole, int notfound) 683 { 684 struct proc *tp; 685 int error = 0; 686 687 mutex_enter(proc_lock); 688 689 if (pid == 0) 690 tp = &proc0; 691 else if ((tp = proc_find(pid)) == NULL) 692 error = notfound; 693 if (tp != NULL && !rw_tryenter(&tp->p_reflock, RW_READER)) 694 error = EBUSY; 695 696 mutex_exit(proc_lock); 697 698 *bunghole = tp; 699 return error; 700 } 701 702 void 703 procfs_proc_unlock(struct proc *p) 704 { 705 706 rw_exit(&p->p_reflock); 707 } 708 709 int 710 procfs_doemul(struct lwp *curl, struct proc *p, 711 struct pfsnode *pfs, struct uio *uio) 712 { 713 const char *ename = p->p_emul->e_name; 714 return uiomove_frombuf(__UNCONST(ename), strlen(ename), uio); 715 } 716