From cc6b664e2eb821b39837e7bb980e5ee87e201491 Mon Sep 17 00:00:00 2001 From: phk Date: Tue, 16 Nov 1999 20:31:58 +0000 Subject: Introduce commandline caching in the kernel. This fixes some nasty procfs problems for SMP, makes ps(1) run much faster, and makes ps(1) even less dependent on /proc which will aid chroot and jails alike. To disable this facility and revert to previous behaviour: sysctl -w kern.ps_arg_cache_limit=0 For full details see the current@FreeBSD.org mail-archives. --- sys/kern/kern_exec.c | 23 +++++++++++++++++++++ sys/kern/kern_exit.c | 6 ++++++ sys/kern/kern_fork.c | 3 +++ sys/kern/kern_proc.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 1 deletion(-) (limited to 'sys/kern') diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 35aa228..900da01 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -63,6 +63,8 @@ #include +MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); + static long *exec_copyout_strings __P((struct image_params *)); static long ps_strings = PS_STRINGS; @@ -71,6 +73,10 @@ SYSCTL_LONG(_kern, KERN_PS_STRINGS, ps_strings, CTLFLAG_RD, &ps_strings, ""); static long usrstack = USRSTACK; SYSCTL_LONG(_kern, KERN_USRSTACK, usrstack, CTLFLAG_RD, &usrstack, ""); +u_long ps_arg_cache_limit = PAGE_SIZE / 16; +SYSCTL_LONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, + &ps_arg_cache_limit, ""); + /* * Each of the items is a pointer to a `const struct execsw', hence the * double pointer here. @@ -316,6 +322,21 @@ interpret: setregs(p, imgp->entry_addr, (u_long)(uintptr_t)stack_base, imgp->ps_strings); + /* Free any previous argument cache */ + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + p->p_args = NULL; + + /* Cache arguments if they fit inside our allowance */ + i = imgp->endargs - imgp->stringbase; + if (ps_arg_cache_limit >= i + sizeof(struct pargs)) { + MALLOC(p->p_args, struct pargs *, sizeof(struct pargs) + i, + M_PARGS, M_WAITOK); + p->p_args->ar_ref = 1; + p->p_args->ar_length = i; + bcopy(imgp->stringbase, p->p_args->ar_args, i); + } + exec_fail_dealloc: /* @@ -511,6 +532,8 @@ exec_extract_strings(imgp) } } + imgp->endargs = imgp->stringp; + /* * extract environment strings */ diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6fe2171..6c00e43 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -494,6 +494,12 @@ loop: } /* + * Remove unused arguments + */ + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + + /* * Finally finished with old proc entry. * Unlink it from its process group and free it. */ diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 0fbe915..9268592 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -337,6 +337,9 @@ again: p2->p_flag |= P_JAILED; } + if (p2->p_args) + p2->p_args->ar_ref++; + if (flags & RFSIGSHARE) { p2->p_procsig = p1->p_procsig; p2->p_procsig->ps_refcnt++; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index d420821..4c3ee1c 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -38,8 +38,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -609,6 +609,57 @@ sysctl_kern_proc SYSCTL_HANDLER_ARGS return (0); } +/* + * This sysctl allows a process to retrieve the argument list or process + * title for another process without groping around in the address space + * of the other process. It also allow a process to set its own "process + * title to a string of its own choice. + */ +static int +sysctl_kern_proc_args SYSCTL_HANDLER_ARGS +{ + int *name = (int*) arg1; + u_int namelen = arg2; + struct proc *p; + struct pargs *pa; + int error = 0; + + if (namelen != 1) + return (EINVAL); + + p = pfind((pid_t)name[0]); + if (!p) + return (0); + + if (!PRISON_CHECK(curproc, p)) + return (0); + + if (req->newptr && curproc != p) + return (EPERM); + + if (req->oldptr && p->p_args != NULL) + error = SYSCTL_OUT(req, p->p_args->ar_args, p->p_args->ar_length); + if (req->newptr == NULL) + return (error); + + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + p->p_args = NULL; + + if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit) + return (error); + + MALLOC(pa, struct pargs *, sizeof(struct pargs) + req->newlen, + M_PARGS, M_WAITOK); + pa->ar_ref = 1; + pa->ar_length = req->newlen; + error = SYSCTL_IN(req, pa->ar_args, req->newlen); + if (!error) + p->p_args = pa; + else + FREE(pa, M_PARGS); + return (error); +} SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD, 0, "Process table"); @@ -629,3 +680,6 @@ SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD, SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD, sysctl_kern_proc, "Process table"); + +SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args, CTLFLAG_RW, + sysctl_kern_proc_args, "Return process argument"); -- cgit v1.1