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