Change the way rctl interfaces with jails by introducing prison_racct

structure, which acts as a proxy between them.  This makes jail rules
persistent, i.e. they can be added before jail gets created, and they
don't disappear when the jail gets destroyed.
This commit is contained in:
Edward Tomasz Napierala 2011-05-03 07:32:58 +00:00
parent 74ff69fe44
commit a7ad07bff3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221362
6 changed files with 171 additions and 79 deletions

View File

@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/racct.h>
#include <sys/rctl.h>
#include <sys/refcount.h>
#include <sys/sx.h>
#include <sys/sysent.h>
#include <sys/namei.h>
@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#define DEFAULT_HOSTUUID "00000000-0000-0000-0000-000000000000"
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
MALLOC_DEFINE(M_PRISON_RACCT, "prison_racct", "Prison racct structures");
/* Keep struct prison prison0 and some code in kern_jail_set() readable. */
#ifdef INET
@ -114,10 +115,11 @@ struct prison prison0 = {
};
MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF);
/* allprison and lastprid are protected by allprison_lock. */
/* allprison, allprison_racct and lastprid are protected by allprison_lock. */
struct sx allprison_lock;
SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
struct prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
LIST_HEAD(, prison_racct) allprison_racct;
int lastprid = 0;
static int do_jail_attach(struct thread *td, struct prison *pr);
@ -125,6 +127,10 @@ static void prison_complete(void *context, int pending);
static void prison_deref(struct prison *pr, int flags);
static char *prison_path(struct prison *pr1, struct prison *pr2);
static void prison_remove_one(struct prison *pr);
#ifdef RACCT
static void prison_racct_attach(struct prison *pr);
static void prison_racct_detach(struct prison *pr);
#endif
#ifdef INET
static int _prison_check_ip4(struct prison *pr, struct in_addr *ia);
static int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4);
@ -1197,7 +1203,6 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
root = mypr->pr_root;
vref(root);
}
racct_create(&pr->pr_racct);
strlcpy(pr->pr_hostuuid, DEFAULT_HOSTUUID, HOSTUUIDLEN);
pr->pr_flags |= PR_HOST;
#if defined(INET) || defined(INET6)
@ -1657,6 +1662,11 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
mtx_unlock(&pr->pr_mtx);
#ifdef RACCT
if (created)
prison_racct_attach(pr);
#endif
/* Locks may have prevented a complete restriction of child IP
* addresses. If so, allocate some more memory and try again.
*/
@ -2533,10 +2543,9 @@ prison_deref(struct prison *pr, int flags)
if (pr->pr_cpuset != NULL)
cpuset_rel(pr->pr_cpuset);
osd_jail_exit(pr);
#ifdef RCTL
rctl_racct_release(pr->pr_racct);
#ifdef RACCT
prison_racct_detach(pr);
#endif
racct_destroy(&pr->pr_racct);
free(pr, M_PRISON);
/* Removing a prison frees a reference on its parent. */
@ -4277,14 +4286,103 @@ void
prison_racct_foreach(void (*callback)(struct racct *racct,
void *arg2, void *arg3), void *arg2, void *arg3)
{
struct prison *pr;
struct prison_racct *prr;
sx_slock(&allprison_lock);
TAILQ_FOREACH(pr, &allprison, pr_list)
(callback)(pr->pr_racct, arg2, arg3);
LIST_FOREACH(prr, &allprison_racct, prr_next)
(callback)(prr->prr_racct, arg2, arg3);
sx_sunlock(&allprison_lock);
}
static struct prison_racct *
prison_racct_find_locked(const char *name)
{
struct prison_racct *prr;
sx_assert(&allprison_lock, SA_XLOCKED);
if (name[0] == '\0' || strlen(name) >= MAXHOSTNAMELEN)
return (NULL);
LIST_FOREACH(prr, &allprison_racct, prr_next) {
if (strcmp(name, prr->prr_name) != 0)
continue;
/* Found prison_racct with a matching name? */
prison_racct_hold(prr);
return (prr);
}
/* Add new prison_racct. */
prr = malloc(sizeof(*prr), M_PRISON_RACCT, M_ZERO | M_WAITOK);
racct_create(&prr->prr_racct);
strcpy(prr->prr_name, name);
refcount_init(&prr->prr_refcount, 1);
LIST_INSERT_HEAD(&allprison_racct, prr, prr_next);
return (prr);
}
struct prison_racct *
prison_racct_find(const char *name)
{
struct prison_racct *prr;
sx_xlock(&allprison_lock);
prr = prison_racct_find_locked(name);
sx_xunlock(&allprison_lock);
return (prr);
}
void
prison_racct_hold(struct prison_racct *prr)
{
refcount_acquire(&prr->prr_refcount);
}
void
prison_racct_free(struct prison_racct *prr)
{
int old;
old = prr->prr_refcount;
if (old > 1 && atomic_cmpset_int(&prr->prr_refcount, old, old - 1))
return;
sx_xlock(&allprison_lock);
if (refcount_release(&prr->prr_refcount)) {
racct_destroy(&prr->prr_racct);
LIST_REMOVE(prr, prr_next);
sx_xunlock(&allprison_lock);
free(prr, M_PRISON_RACCT);
return;
}
sx_xunlock(&allprison_lock);
}
#ifdef RACCT
static void
prison_racct_attach(struct prison *pr)
{
struct prison_racct *prr;
prr = prison_racct_find_locked(pr->pr_name);
KASSERT(prr != NULL, ("cannot find prison_racct"));
pr->pr_prison_racct = prr;
}
static void
prison_racct_detach(struct prison *pr)
{
prison_racct_free(pr->pr_prison_racct);
pr->pr_prison_racct = NULL;
}
#endif /* RACCT */
#ifdef DDB
static void

View File

@ -313,7 +313,8 @@ racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount)
racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, amount);
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent)
racct_alloc_resource(pr->pr_racct, resource, amount);
racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource,
amount);
racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, amount);
}
@ -522,7 +523,8 @@ racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount)
racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, -amount);
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent)
racct_alloc_resource(pr->pr_racct, resource, -amount);
racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource,
-amount);
racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, -amount);
}
@ -669,9 +671,11 @@ racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred,
}
if (newpr != oldpr) {
for (pr = oldpr; pr != NULL; pr = pr->pr_parent)
racct_sub_racct(pr->pr_racct, p->p_racct);
racct_sub_racct(pr->pr_prison_racct->prr_racct,
p->p_racct);
for (pr = newpr; pr != NULL; pr = pr->pr_parent)
racct_add_racct(pr->pr_racct, p->p_racct);
racct_add_racct(pr->pr_prison_racct->prr_racct,
p->p_racct);
}
mtx_unlock(&racct_lock);
@ -744,7 +748,7 @@ racct_init(void)
/*
* XXX: Move this somewhere.
*/
racct_create(&prison0.pr_racct);
prison0.pr_prison_racct = prison_racct_find("0");
}
SYSINIT(racct, SI_SUB_RACCT, SI_ORDER_FIRST, racct_init, NULL);

View File

@ -241,7 +241,8 @@ rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
break;
case RCTL_SUBJECT_TYPE_JAIL:
available = rule->rr_amount -
cred->cr_prison->pr_racct->r_resources[resource];
cred->cr_prison->pr_prison_racct->prr_racct->
r_resources[resource];
break;
default:
panic("rctl_compute_available: unknown per %d",
@ -327,7 +328,7 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount)
printf("rctl: rule \"%s\" matched by pid %d "
"(%s), uid %d, jail %s\n", sbuf_data(&sb),
p->p_pid, p->p_comm, p->p_ucred->cr_uid,
p->p_ucred->cr_prison->pr_name);
p->p_ucred->cr_prison->pr_prison_racct->prr_name);
sbuf_delete(&sb);
free(buf, M_RCTL);
link->rrl_exceeded = 1;
@ -346,7 +347,7 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount)
rctl_rule_to_sbuf(&sb, rule);
sbuf_printf(&sb, " pid=%d ruid=%d jail=%s",
p->p_pid, p->p_ucred->cr_ruid,
p->p_ucred->cr_prison->pr_name);
p->p_ucred->cr_prison->pr_prison_racct->prr_name);
sbuf_finish(&sb);
devctl_notify_f("RCTL", "rule", "matched",
sbuf_data(&sb), M_NOWAIT);
@ -481,9 +482,9 @@ rctl_rule_matches(const struct rctl_rule *rule, const struct rctl_rule *filter)
return (0);
break;
case RCTL_SUBJECT_TYPE_JAIL:
if (filter->rr_subject.rs_prison != NULL &&
rule->rr_subject.rs_prison !=
filter->rr_subject.rs_prison)
if (filter->rr_subject.rs_prison_racct != NULL &&
rule->rr_subject.rs_prison_racct !=
filter->rr_subject.rs_prison_racct)
return (0);
break;
default:
@ -635,7 +636,10 @@ rctl_rule_acquire_subject(struct rctl_rule *rule)
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
case RCTL_SUBJECT_TYPE_PROCESS:
break;
case RCTL_SUBJECT_TYPE_JAIL:
if (rule->rr_subject.rs_prison_racct != NULL)
prison_racct_hold(rule->rr_subject.rs_prison_racct);
break;
case RCTL_SUBJECT_TYPE_USER:
if (rule->rr_subject.rs_uip != NULL)
@ -658,7 +662,10 @@ rctl_rule_release_subject(struct rctl_rule *rule)
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
case RCTL_SUBJECT_TYPE_PROCESS:
break;
case RCTL_SUBJECT_TYPE_JAIL:
if (rule->rr_subject.rs_prison_racct != NULL)
prison_racct_free(rule->rr_subject.rs_prison_racct);
break;
case RCTL_SUBJECT_TYPE_USER:
if (rule->rr_subject.rs_uip != NULL)
@ -686,7 +693,7 @@ rctl_rule_alloc(int flags)
rule->rr_subject.rs_proc = NULL;
rule->rr_subject.rs_uip = NULL;
rule->rr_subject.rs_loginclass = NULL;
rule->rr_subject.rs_prison = NULL;
rule->rr_subject.rs_prison_racct = NULL;
rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED;
rule->rr_resource = RACCT_UNDEFINED;
rule->rr_action = RCTL_ACTION_UNDEFINED;
@ -708,7 +715,7 @@ rctl_rule_duplicate(const struct rctl_rule *rule, int flags)
copy->rr_subject.rs_proc = rule->rr_subject.rs_proc;
copy->rr_subject.rs_uip = rule->rr_subject.rs_uip;
copy->rr_subject.rs_loginclass = rule->rr_subject.rs_loginclass;
copy->rr_subject.rs_prison = rule->rr_subject.rs_prison;
copy->rr_subject.rs_prison_racct = rule->rr_subject.rs_prison_racct;
copy->rr_per = rule->rr_per;
copy->rr_resource = rule->rr_resource;
copy->rr_action = rule->rr_action;
@ -784,7 +791,7 @@ rctl_rule_fully_specified(const struct rctl_rule *rule)
return (0);
break;
case RCTL_SUBJECT_TYPE_JAIL:
if (rule->rr_subject.rs_prison == NULL)
if (rule->rr_subject.rs_prison_racct == NULL)
return (0);
break;
default:
@ -833,7 +840,7 @@ rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
rule->rr_subject.rs_proc = NULL;
rule->rr_subject.rs_uip = NULL;
rule->rr_subject.rs_loginclass = NULL;
rule->rr_subject.rs_prison = NULL;
rule->rr_subject.rs_prison_racct = NULL;
} else {
switch (rule->rr_subject_type) {
case RCTL_SUBJECT_TYPE_UNDEFINED:
@ -866,23 +873,12 @@ rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
}
break;
case RCTL_SUBJECT_TYPE_JAIL:
rule->rr_subject.rs_prison =
prison_find_name(&prison0, subject_idstr);
if (rule->rr_subject.rs_prison == NULL) {
/*
* No jail with that name; try with the JID.
*/
error = str2id(subject_idstr, &id);
if (error != 0)
goto out;
rule->rr_subject.rs_prison = prison_find(id);
if (rule->rr_subject.rs_prison == NULL) {
error = ESRCH;
goto out;
}
rule->rr_subject.rs_prison_racct =
prison_racct_find(subject_idstr);
if (rule->rr_subject.rs_prison_racct == NULL) {
error = ENAMETOOLONG;
goto out;
}
/* prison_find() returns with mutex held. */
mtx_unlock(&rule->rr_subject.rs_prison->pr_mtx);
break;
default:
panic("rctl_string_to_rule: unknown subject type %d",
@ -944,6 +940,7 @@ rctl_rule_add(struct rctl_rule *rule)
struct ucred *cred;
struct uidinfo *uip;
struct prison *pr;
struct prison_racct *prr;
struct loginclass *lc;
struct rctl_rule *rule2;
int match;
@ -1008,9 +1005,9 @@ rctl_rule_add(struct rctl_rule *rule)
break;
case RCTL_SUBJECT_TYPE_JAIL:
pr = rule->rr_subject.rs_prison;
KASSERT(pr != NULL, ("rctl_rule_add: NULL pr"));
rctl_racct_add_rule(pr->pr_racct, rule);
prr = rule->rr_subject.rs_prison_racct;
KASSERT(prr != NULL, ("rctl_rule_add: NULL pr"));
rctl_racct_add_rule(prr->prr_racct, rule);
break;
default:
@ -1040,7 +1037,7 @@ rctl_rule_add(struct rctl_rule *rule)
case RCTL_SUBJECT_TYPE_JAIL:
match = 0;
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) {
if (pr == rule->rr_subject.rs_prison) {
if (pr->pr_prison_racct == rule->rr_subject.rs_prison_racct) {
match = 1;
break;
}
@ -1144,11 +1141,11 @@ rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule)
rule->rr_subject.rs_loginclass->lc_name);
break;
case RCTL_SUBJECT_TYPE_JAIL:
if (rule->rr_subject.rs_prison == NULL)
if (rule->rr_subject.rs_prison_racct == NULL)
sbuf_printf(sb, ":");
else
sbuf_printf(sb, "%s:",
rule->rr_subject.rs_prison->pr_name);
rule->rr_subject.rs_prison_racct->prr_name);
break;
default:
panic("rctl_rule_to_sbuf: unknown subject type %d",
@ -1245,7 +1242,7 @@ rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
struct proc *p;
struct uidinfo *uip;
struct loginclass *lc;
struct prison *pr;
struct prison_racct *prr;
error = priv_check(td, PRIV_RCTL_GET_RACCT);
if (error != 0)
@ -1256,11 +1253,9 @@ rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
return (error);
sx_slock(&allproc_lock);
sx_slock(&allprison_lock);
error = rctl_string_to_rule(inputstr, &filter);
free(inputstr, M_RCTL);
if (error != 0) {
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
@ -1295,19 +1290,18 @@ rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
outputsbuf = rctl_racct_to_sbuf(lc->lc_racct, 1);
break;
case RCTL_SUBJECT_TYPE_JAIL:
pr = filter->rr_subject.rs_prison;
if (pr == NULL) {
prr = filter->rr_subject.rs_prison_racct;
if (prr == NULL) {
error = EINVAL;
goto out;
}
outputsbuf = rctl_racct_to_sbuf(pr->pr_racct, 1);
outputsbuf = rctl_racct_to_sbuf(prr->prr_racct, 1);
break;
default:
error = EINVAL;
}
out:
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
if (error != 0)
return (error);
@ -1354,11 +1348,9 @@ rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
return (error);
sx_slock(&allproc_lock);
sx_slock(&allprison_lock);
error = rctl_string_to_rule(inputstr, &filter);
free(inputstr, M_RCTL);
if (error != 0) {
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
@ -1406,7 +1398,6 @@ rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
free(buf, M_RCTL);
return (error);
@ -1431,30 +1422,25 @@ rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
return (error);
sx_slock(&allproc_lock);
sx_slock(&allprison_lock);
error = rctl_string_to_rule(inputstr, &filter);
free(inputstr, M_RCTL);
if (error != 0) {
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_UNDEFINED) {
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (EINVAL);
}
if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_PROCESS) {
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (EOPNOTSUPP);
}
if (filter->rr_subject.rs_proc == NULL) {
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (EINVAL);
}
@ -1486,7 +1472,6 @@ rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
free(buf, M_RCTL);
return (error);
@ -1508,11 +1493,9 @@ rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
return (error);
sx_slock(&allproc_lock);
sx_slock(&allprison_lock);
error = rctl_string_to_rule(inputstr, &rule);
free(inputstr, M_RCTL);
if (error != 0) {
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
@ -1532,7 +1515,6 @@ rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
out:
rctl_rule_release(rule);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
@ -1553,18 +1535,15 @@ rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
return (error);
sx_slock(&allproc_lock);
sx_slock(&allprison_lock);
error = rctl_string_to_rule(inputstr, &filter);
free(inputstr, M_RCTL);
if (error != 0) {
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
}
error = rctl_rule_remove(filter);
rctl_rule_release(filter);
sx_sunlock(&allprison_lock);
sx_sunlock(&allproc_lock);
return (error);
@ -1580,12 +1559,12 @@ rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
struct rctl_rule_link *link, *newlink;
struct uidinfo *newuip;
struct loginclass *newlc;
struct prison *newpr;
struct prison_racct *newprr;
LIST_HEAD(, rctl_rule_link) newrules;
newuip = newcred->cr_ruidinfo;
newlc = newcred->cr_loginclass;
newpr = newcred->cr_prison;
newprr = newcred->cr_prison->pr_prison_racct;
LIST_INIT(&newrules);
@ -1605,7 +1584,7 @@ rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
rulecnt++;
LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next)
rulecnt++;
LIST_FOREACH(link, &newpr->pr_racct->r_rule_links, rrl_next)
LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next)
rulecnt++;
rw_runlock(&rctl_lock);
@ -1655,7 +1634,7 @@ rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
rulecnt--;
}
LIST_FOREACH(link, &newpr->pr_racct->r_rule_links, rrl_next) {
LIST_FOREACH(link, &newprr->prr_racct->r_rule_links, rrl_next) {
if (newlink == NULL)
goto goaround;
rctl_rule_acquire(link->rrl_rule);

View File

@ -136,6 +136,7 @@ MALLOC_DECLARE(M_PRISON);
#define HOSTUUIDLEN 64
struct racct;
struct prison_racct;
/*
* This structure describes a prison. It is pointed to by all struct
@ -168,7 +169,7 @@ struct prison {
int pr_ip6s; /* (p) number of v6 IPs */
struct in_addr *pr_ip4; /* (p) v4 IPs of jail */
struct in6_addr *pr_ip6; /* (p) v6 IPs of jail */
struct racct *pr_racct; /* (c) resource accounting */
struct prison_racct *pr_prison_racct; /* (c) racct jail proxy */
void *pr_sparep[3];
int pr_childcount; /* (a) number of child jails */
int pr_childmax; /* (p) maximum child jails */
@ -183,6 +184,13 @@ struct prison {
char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */
char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */
};
struct prison_racct {
LIST_ENTRY(prison_racct) prr_next;
char prr_name[MAXHOSTNAMELEN];
u_int prr_refcount;
struct racct *prr_racct;
};
#endif /* _KERNEL || _WANT_PRISON */
#ifdef _KERNEL
@ -385,6 +393,9 @@ int prison_priv_check(struct ucred *cred, int priv);
int sysctl_jail_param(SYSCTL_HANDLER_ARGS);
void prison_racct_foreach(void (*callback)(struct racct *racct,
void *arg2, void *arg3), void *arg2, void *arg3);
struct prison_racct *prison_racct_find(const char *name);
void prison_racct_hold(struct prison_racct *prr);
void prison_racct_free(struct prison_racct *prr);
#endif /* _KERNEL */
#endif /* !_SYS_JAIL_H_ */

View File

@ -44,7 +44,7 @@
struct proc;
struct uidinfo;
struct loginclass;
struct prison;
struct prison_racct;
struct ucred;
struct rctl_rule_link;
@ -70,7 +70,7 @@ struct rctl_rule {
struct proc *rs_proc;
struct uidinfo *rs_uip;
struct loginclass *rs_loginclass;
struct prison *rs_prison;
struct prison_racct *rs_prison_racct;
} rr_subject;
int rr_per;
int rr_resource;

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 14, 2011
.Dd May 3, 2011
.Dt RCTL 8
.Os
.Sh NAME
@ -90,7 +90,7 @@ Subject defines the kind of entity the rule applies to.
It can be either process, user, login class, or jail.
.Pp
Subject ID identifies the subject. It can be user name,
numerical user ID, login class name, jail name, or numerical jail ID.
numerical user ID, login class name, or jail name.
.Pp
Resource identifies the resource the rule controls.
.Pp
@ -177,9 +177,9 @@ Prevent user "joe" from allocating more than 1GB of virtual memory.
.Pp
Remove all RCTL rules.
.Pp
.Dl rctl -hu jail:5
.Dl rctl -hu jail:www
.Pp
Display resource usage information for jail with JID 5.
Display resource usage information for jail named "www".
.Pp
.Dl rctl -l process:512
.Pp