diff options
author | phk <phk@FreeBSD.org> | 1999-11-16 20:31:58 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1999-11-16 20:31:58 +0000 |
commit | cc6b664e2eb821b39837e7bb980e5ee87e201491 (patch) | |
tree | 65eeb4add32e588f36f28e2a0bb819c17a67ff70 /sys | |
parent | 47e5f46c7642e6d8e2ed20c8afca59596d3c2dc1 (diff) | |
download | FreeBSD-src-cc6b664e2eb821b39837e7bb980e5ee87e201491.zip FreeBSD-src-cc6b664e2eb821b39837e7bb980e5ee87e201491.tar.gz |
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.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_exec.c | 23 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 56 | ||||
-rw-r--r-- | sys/sys/imgact.h | 1 | ||||
-rw-r--r-- | sys/sys/proc.h | 16 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 1 |
7 files changed, 104 insertions, 2 deletions
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 <machine/reg.h> +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 <sys/systm.h> #include <sys/kernel.h> #include <sys/sysctl.h> -#include <sys/proc.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/filedesc.h> #include <sys/tty.h> #include <sys/signalvar.h> @@ -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"); diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h index ec147ba..83ed79c 100644 --- a/sys/sys/imgact.h +++ b/sys/sys/imgact.h @@ -44,6 +44,7 @@ struct image_params { const char *image_header; /* head of file to exec */ char *stringbase; /* base address of tmp string storage */ char *stringp; /* current 'end' pointer of tmp strings */ + char *endargs; /* end of argv vector */ int stringspace; /* space left in tmp string storage area */ int argc, envc; /* count of argument and environment strings */ char *argv0; /* Replacement for argv[0] when interpreting */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 8144a46..9373d5d 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -98,6 +98,16 @@ struct pasleep { }; /* + * pargs, used to hold a copy of the command line, if it had a sane + * length + */ +struct pargs { + u_int ar_ref; /* Reference count */ + u_int ar_length; /* Length */ + u_char ar_args[0]; /* Arguments */ +}; + +/* * Description of a process. * * This structure contains the information needed to manage a thread of @@ -211,7 +221,8 @@ struct proc { struct sysentvec *p_sysent; /* System call dispatch information. */ struct rtprio p_rtprio; /* Realtime priority. */ - struct prison *p_prison; + struct prison *p_prison; + struct pargs *p_args; /* End area that is copied on creation. */ #define p_endcopy p_addr struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ @@ -299,6 +310,7 @@ struct pcred { MALLOC_DECLARE(M_SESSION); MALLOC_DECLARE(M_SUBPROC); MALLOC_DECLARE(M_ZOMBIE); +MALLOC_DECLARE(M_PARGS); #endif /* flags for suser_xxx() */ @@ -371,6 +383,8 @@ extern int whichqs; /* Bit mask summary of non-empty Q's. */ extern int whichrtqs; /* Bit mask summary of non-empty Q's. */ extern int whichidqs; /* Bit mask summary of non-empty Q's. */ +extern u_long ps_arg_cache_limit; + struct proc *pfind __P((pid_t)); /* Find process by id. */ struct pgrp *pgfind __P((pid_t)); /* Find process group by id. */ diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index d8564dd..bea866e 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -317,6 +317,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); #define KERN_PROC_TTY 4 /* by controlling tty */ #define KERN_PROC_UID 5 /* by effective uid */ #define KERN_PROC_RUID 6 /* by real uid */ +#define KERN_PROC_ARGS 7 /* get/set arguments/proctitle */ /* * KERN_IPC identifiers |