From owner-p4-projects@FreeBSD.ORG Sun Jul 25 08:41:30 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0D5D61065678; Sun, 25 Jul 2010 08:41:30 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9FE061065673 for ; Sun, 25 Jul 2010 08:41:29 +0000 (UTC) (envelope-from gabor@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 917F88FC27 for ; Sun, 25 Jul 2010 08:41:29 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.4/8.14.4) with ESMTP id o6P8fTuH001210 for ; Sun, 25 Jul 2010 08:41:29 GMT (envelope-from gabor@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.4/8.14.4/Submit) id o6P8fSio001208 for perforce@freebsd.org; Sun, 25 Jul 2010 08:41:28 GMT (envelope-from gabor@freebsd.org) Date: Sun, 25 Jul 2010 08:41:28 GMT Message-Id: <201007250841.o6P8fSio001208@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gabor@freebsd.org using -f From: Gabor Kovesdan To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 181452 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 25 Jul 2010 08:41:30 -0000 http://p4web.freebsd.org/@@181452?ac=10 Change 181452 by gabor@gabor_aspire on 2010/07/25 08:39:08 - Add more test cases to the testsuite and refactor a bit - Some code changes, which are necessary for more complicated resource checks - Add support for JLIMIT_NOFILE Affected files ... .. //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/fs/fdescfs/fdesc_vfsops.c#2 edit .. //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/kern/kern_fork.c#4 edit .. //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/kern/kern_jobs.c#5 edit .. //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/sys/jobs.h#3 edit .. //depot/projects/soc2010/gabor_jobs/irix_jobs/tools/test/irix_jobs/jobtest.c#3 edit Differences ... ==== //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/fs/fdescfs/fdesc_vfsops.c#2 (text+ko) ==== @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,7 @@ struct thread *td; struct filedesc *fdp; int lim; + int jlim_cur_avail; int i; int last; int freefd; @@ -198,9 +200,10 @@ PROC_LOCK(td->td_proc); lim = lim_cur(td->td_proc, RLIMIT_NOFILE); PROC_UNLOCK(td->td_proc); + jlim_cur_avail = irix_jobs_cur_avail(td->td_proc->p_ucred->cr_jid, JLIMIT_NOFILE); fdp = td->td_proc->p_fd; FILEDESC_SLOCK(fdp); - last = min(fdp->fd_nfiles, lim); + last = min(min(fdp->fd_nfiles, lim), (jlim_cur_avail + fdp->fd_nfiles)); freefd = 0; for (i = fdp->fd_freefile; i < last; i++) if (fdp->fd_ofiles[i] == NULL) ==== //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/kern/kern_fork.c#4 (text+ko) ==== @@ -114,7 +114,7 @@ td->td_retval[0] = p2->p_pid; td->td_retval[1] = 0; if (td->td_proc->p_ucred->cr_jid != 0) - irix_jobs_add_proc(td->td_proc->p_ucred->cr_jid, p2->p_pid); + irix_jobs_add_proc(td->td_proc->p_ucred->cr_jid, p2); } return (error); } ==== //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/kern/kern_jobs.c#5 (text+ko) ==== @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD"); #include +#include #include #include #include @@ -52,7 +53,7 @@ static jid_t min_free_jid = 1; struct procentry { - pid_t pid; + struct proc *td_proc; LIST_ENTRY(procentry) entries; }; @@ -124,15 +125,12 @@ } */ - - p = td->td_proc; - /* * per-job accounting */ jp = jobentry_alloc(uap->rjid); pp = malloc(sizeof(struct procentry), M_IRIX_JOBS, M_NOWAIT | M_ZERO); - pp->pid = p->p_pid; + pp->td_proc = td->td_proc; LIST_INIT(&jp->proclist); LIST_INSERT_HEAD(&jp->proclist, pp, entries); JOBLIST_WLOCK; @@ -142,8 +140,8 @@ /* * per-process accounting */ - PROC_LOCK(p); - p->p_ucred->cr_jid = uap->rjid; + PROC_LOCK(td->td_proc); + td->td_proc->p_ucred->cr_jid = uap->rjid; PROC_UNLOCK(p); /* success, if we have reached here */ @@ -161,20 +159,24 @@ LIST_FOREACH_SAFE(jp, &irix_joblist, entries, jtmp) { if (jp->jid == (jid_t)uap->jid) { LIST_FOREACH_SAFE(pp, &jp->proclist, entries, ptmp) { - struct kill_args args; + struct kill_args kuap; + + printf("killjob traversed pid %d\n", pp->td_proc->p_pid); - args.pid = pp->pid; - args.signum = uap->signal; - if (kill((struct thread *)0, &args) == -1) { + kuap.pid = pp->td_proc->p_pid; + kuap.signum = uap->signal; + if (kill(td, &kuap) == -1) { td->td_retval[0] = -1; JOBLIST_WUNLOCK; return (EPERM); } LIST_REMOVE(pp, entries); + free(pp, M_IRIX_JOBS); } - td->td_retval[0] = 0; LIST_REMOVE(jp, entries); JOBLIST_WUNLOCK; + jobentry_free(jp); + td->td_retval[0] = 0; return (0); } } @@ -272,6 +274,92 @@ return (ENOJOB); } +#define SUM_UP(jid, res, expr) do { \ + struct procentry *pp; \ + \ + JOBLIST_RLOCK; \ + LIST_FOREACH(jp, &irix_joblist, entries) { \ + if (jp->jid == jid) { \ + LIST_FOREACH(pp, &jp->proclist, \ + entries) { \ + res += expr; \ + } \ + JOBLIST_RUNLOCK; \ + return (res); \ + } \ + } \ + } \ + while (0) + +rlim_t +irix_jobs_getjusage(jid_t jid, int resource) +{ + struct jobentry *jp; + rlim_t usage; + + usage = 0; + + if ((jid == 0) || (resource >= JLIMIT_NLIMITS)) + return ((rlim_t)-1); + + switch(resource) { + case JLIMIT_DATA: +// SUM_UP(jid, usage, (round_page((vm_offset_t)pp->td_proc-> +// p_vmspace->vm->vmdaddr) + ctob(pp->td_proc->p_vmspace-> +// vm_dsize)); + break; + case JLIMIT_NOFILE: + SUM_UP(jid, usage, pp->td_proc->p_fd->fd_nfiles); + break; + default: + JOBLIST_RLOCK; + LIST_FOREACH(jp, &irix_joblist, entries) { + if (jp->jid == jid) { + JOBLIST_RUNLOCK; + return (jp->usage[resource]); + } + } + JOBLIST_RUNLOCK; + /* no job entry for existing job, cannot happen */ + return ((rlim_t)-1); + } + +} + +rlim_t +irix_jobs_get_cur_avail(jid_t jid, int resource) +{ + struct jobentry *jp; + + LIST_FOREACH(jp, &irix_joblist, entries) { + if (jp->jid == jid) { + if (jp->limits[resource].rlim_cur != RLIM_INFINITY) + return (jp->limits[resource].rlim_cur - + irix_jobs_getjusage(jid, resource)); + else + return (RLIM_INFINITY); + } + } + return (RLIM_INFINITY); +} + +rlim_t +irix_jobs_get_max_avail(jid_t jid, int resource) +{ + struct jobentry *jp; + + LIST_FOREACH(jp, &irix_joblist, entries) { + if (jp->jid == jid) { + if (jp->limits[resource].rlim_max != RLIM_INFINITY) + return (jp->limits[resource].rlim_max - + irix_jobs_getjusage(jid, resource)); + else + return (RLIM_INFINITY); + } + } + return (RLIM_INFINITY); +} + int irix_jobs_alloc(struct proc *p, int resource, rlim_t amount) { @@ -349,7 +437,7 @@ LIST_FOREACH_SAFE(jp, &irix_joblist, entries, jtmp) { if (jp->jid == jid) { LIST_FOREACH_SAFE(pp, &jp->proclist, entries, ptmp) { - if (pp->pid == pid) { + if (pp->td_proc->p_pid == pid) { LIST_REMOVE(pp, entries); free(pp, M_IRIX_JOBS); } @@ -366,7 +454,7 @@ } void -irix_jobs_add_proc(jid_t jid, pid_t pid) +irix_jobs_add_proc(jid_t jid, struct proc *p) { struct jobentry *jp, *jtmp; struct procentry *pp; @@ -375,7 +463,7 @@ LIST_FOREACH_SAFE(jp, &irix_joblist, entries, jtmp) { if (jp->jid == jid) { pp = malloc(sizeof(struct procentry), M_IRIX_JOBS, M_NOWAIT); - pp->pid = pid; + pp->td_proc = p; LIST_INSERT_HEAD(&jp->proclist, pp, entries); } } ==== //depot/projects/soc2010/gabor_jobs/irix_jobs/sys/sys/jobs.h#3 (text+ko) ==== @@ -34,10 +34,13 @@ __BEGIN_DECLS jid_t getjid_by_pid(pid_t pid); -void irix_jobs_add_proc(jid_t jid, pid_t pid); +void irix_jobs_add_proc(jid_t jid, struct proc *p); void irix_jobs_remove_proc(jid_t jid, pid_t pid); int irix_jobs_alloc(struct proc *p, int resource, rlim_t amount); void irix_jobs_free(struct proc *p, int resource, rlim_t amount); +rlim_t irix_jobs_cur_avail(jid_t jid, int resource); +rlim_t irix_jobs_max_avail(jid_t jid, int resource); +rlim_t irix_jobs_getjusage(jid_t jid, int resource); __END_DECLS #endif /* _KERNEL */ ==== //depot/projects/soc2010/gabor_jobs/irix_jobs/tools/test/irix_jobs/jobtest.c#3 (text+ko) ==== @@ -38,26 +38,97 @@ #include #include +#define PARSE_ARG(var, cfunc, mval) errno = 0; \ + var = cfunc(optarg, &ep, 10); \ + if (((errno == ERANGE) && \ + (var == mval)) || \ + ((errno == EINVAL) && \ + (var == 0))) \ + err(2, NULL); \ + else if (ep[0] != '\0') { \ + errno = EINVAL; \ + err(2, NULL); \ + } + +#define SET_LIMIT(var, lim) int ret; \ + struct rlimit rlp; \ + \ + rlp.rlim_cur = (rlim_t)var; \ + rlp.rlim_max = (rlim_t)var; \ + \ + ret = setjlimit(jid, lim, &rlp);\ + if (ret == -1) { \ + diag_print("setjlimit()"\ + "of " #lim \ + " failed:" \ + " %s.\n", \ + strerror(errno)); \ + return (1); \ + } else \ + diag_print(#lim " limit"\ + " set to %lld.\n", \ + var); \ + \ + ret = getjlimit(jid, lim, &rlp);\ + if (ret == -1) { \ + diag_print("getjlimit()"\ + "of " #lim \ + " failed:" \ + " %s.\n", \ + strerror(errno)); \ + return (1); \ + } else \ + diag_print("getjlimit()"\ + " for " #lim \ + " returns " \ + "%lld/%lld.\n", \ + rlp.rlim_cur, \ + rlp.rlim_max); + struct option long_options[] = { - {"diag", no_argument, NULL, 'd'}, + {"cpu", required_argument, NULL, 'c'}, + {"jlimit-cpu", required_argument, NULL, 'C'}, + {"data", required_argument, NULL, 'd'}, + {"jlimit-data", required_argument, NULL, 'D'}, {"exec", required_argument, NULL, 'e'}, - {"fork", optional_argument, NULL, 'f'}, - {"jlimit_numproc", required_argument, NULL, 'n'}, + {"stat", required_argument, NULL, 'f'}, + {"jlimit-fileno", required_argument, NULL, 'F'}, {"job", no_argument, NULL, 'j'}, {"killjob", no_argument, NULL, 'k'}, + {"mem", required_argument, NULL, 'm'}, + {"jlimit-pmem", required_argument, NULL, 'M'}, + {"proc", optional_argument, NULL, 'p'}, + {"jlimit-numproc", required_argument, NULL, 'P'}, + {"resident", required_argument, NULL, 'r'}, + {"jlimit-rss", required_argument, NULL, 'R'}, {"shell", no_argument, NULL, 's'}, + {"vmem", required_argument, NULL, 'v'}, + {"jlimit-vmem", required_argument, NULL, 'V'}, + {"verbose", no_argument, NULL, 'x'}, {NULL, no_argument, NULL, 0} }; -static const char *optstr = "de:f:jkn:s"; +static const char *optstr = "c:C:d:D:e:f:F:jkm:M:p:P:r:R:sv:V:x"; +static unsigned long long cflag; +static long long Cflag; +static unsigned long long dflag; +static long long Dflag; static char *eflag; static unsigned long long fflag; +static long long Fflag; static bool jflag; static bool kflag; -static long long nflag; +static unsigned long long mflag; +static long long Mflag; +static unsigned long long pflag; +static long long Pflag; +static unsigned long long rflag; +static long long Rflag; static bool sflag; +static unsigned long long vflag; +static long long Vflag; static int null_print(const char * restrict, ...); static int (*diag_print)(const char * restrict format, ...) = null_print; @@ -89,22 +160,26 @@ while (((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1)) { switch (c) { + case 'c': + PARSE_ARG(cflag, strtoull, ULLONG_MAX); + break; + case 'C': + PARSE_ARG(Cflag, strtoll, LLONG_MAX); + break; case 'd': - diag_print = printf; + PARSE_ARG(dflag, strtoull, ULLONG_MAX); + break; + case 'D': + PARSE_ARG(Dflag, strtoll, LLONG_MAX); break; case 'e': eflag = strdup(optarg); break; case 'f': - errno = 0; - fflag = strtoull(optarg, &ep, 10); - if (((errno == ERANGE) && (fflag == ULLONG_MAX)) || - ((errno == EINVAL) && (fflag == 0))) - err(2, NULL); - else if (ep[0] != '\0') { - errno = EINVAL; - err(2, NULL); - } + PARSE_ARG(fflag, strtoull, ULLONG_MAX); + break; + case 'F': + PARSE_ARG(Fflag, strtoll, LLONG_MAX); break; case 'j': jflag = true; @@ -112,26 +187,42 @@ case 'k': kflag = true; break; - case 'n': - errno = 0; - nflag = strtoll(optarg, &ep, 10); - if (((errno == ERANGE) && (nflag == LLONG_MAX)) || - ((errno == EINVAL) && (nflag == 0))) - err(2, NULL); - else if (ep[0] != '\0') { - errno = EINVAL; - err(2, NULL); - } + case 'm': + PARSE_ARG(mflag, strtoull, ULLONG_MAX); + break; + case 'M': + PARSE_ARG(Mflag, strtoll, LLONG_MAX); + break; + case 'p': + PARSE_ARG(pflag, strtoull, ULLONG_MAX); + break; + case 'P': + PARSE_ARG(Pflag, strtoll, LLONG_MAX); + break; + case 'r': + PARSE_ARG(rflag, strtoull, ULLONG_MAX); + break; + case 'R': + PARSE_ARG(Pflag, strtoll, LLONG_MAX); break; case 's': sflag = true; break; + case 'v': + PARSE_ARG(vflag, strtoull, ULLONG_MAX); + break; + case 'V': + PARSE_ARG(Vflag, strtoll, LLONG_MAX); + break; + case 'x': + diag_print = printf; + break; default: usage(); } } - if (sflag && fflag) + if (sflag && pflag) usage(); if (jflag) { @@ -152,40 +243,64 @@ return (1); } - if (nflag > 0) { - int ret; - struct rlimit rlp; + /* + * Setting resource limits on creaated job. + */ + + if (Cflag > 0) { + SET_LIMIT(Cflag, JLIMIT_CPU); + } + + if (Dflag > 0) { + SET_LIMIT(Fflag, JLIMIT_DATA); + } + + if (Fflag > 0) { + SET_LIMIT(Fflag, JLIMIT_NOFILE); + } + + if (Mflag > 0) { + SET_LIMIT(Mflag, JLIMIT_PMEM); + } + + if (Pflag > 0) { + SET_LIMIT(Pflag, JLIMIT_NUMPROC); + } - rlp.rlim_cur = (rlim_t)nflag; - rlp.rlim_max = (rlim_t)nflag; + if (Rflag > 0) { + SET_LIMIT(Fflag, JLIMIT_RSS); + } - ret = setjlimit(jid, JLIMIT_NUMPROC, &rlp); + if (Vflag > 0) { + SET_LIMIT(Fflag, JLIMIT_VMEM); + } - if (ret == -1) { - diag_print("setjlimit() failed: %s.\n", - strerror(errno)); - return (1); - } else - diag_print("JLIMIT_NUMPROC limit set to %lld.\n", - nflag); + /* + * Start resource consumption. + */ - ret = getjlimit(jid, JLIMIT_NUMPROC, &rlp); + if (cflag > 0) { + /* XXX */ + } - if (ret == -1) { - diag_print("getjlimit() failed: %s.\n", - strerror(errno)); - return (1); - } else - diag_print("getjlimit() says JLIMIT_NUMPROC limit is" - "set to %lld/%lld.\n", rlp.rlim_cur, rlp.rlim_max); + if (dflag > 0) { + /* XXX */ } if (fflag > 0) { - for (unsigned long long i = 0; i < fflag; i++) { + /* XXX */ + } + + if (mflag > 0) { + /* XXX */ + } + + if (pflag > 0) { + for (unsigned long long i = 0; i < pflag; i++) { pid = fork(); if (pid == 0) { - diag_print("Forked process' getjid() returns: %d.\n", - (int)getjid()); + diag_print("Forked process' getjid()" + " returns: %d.\n", (int)getjid()); sleep(5); exit(EXIT_SUCCESS); } else if (pid == -1) { @@ -197,6 +312,18 @@ } } + if (rflag > 0) { + /* XXX */ + } + + if (vflag > 0) { + /* XXX */ + } + + /* + * Misc debug and testing features. + */ + if (sflag) { char *eargv[2]; @@ -210,8 +337,9 @@ if (kflag && (pid != 0)) { int ret; - diag_print("Let's suicide, sending SIGINT to processes of jid %lld...\n", getjid()); - ret = killjob(getjid(), SIGINT); + diag_print("Let's suicide, sending SIGINT to processes of" + " jid %lld...\n", jid); + ret = killjob(jid, SIGINT); if (ret == -1) { diag_print("killjob() failed: %s.\n", strerror(errno));