Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_rctl.c
Show First 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
FEATURE(rctl, "Resource Limits"); | FEATURE(rctl, "Resource Limits"); | ||||
#define HRF_DEFAULT 0 | #define HRF_DEFAULT 0 | ||||
#define HRF_DONT_INHERIT 1 | #define HRF_DONT_INHERIT 1 | ||||
#define HRF_DONT_ACCUMULATE 2 | #define HRF_DONT_ACCUMULATE 2 | ||||
/* Default buffer size for rctl_get_rules(2). */ | #define RCTL_MAX_INBUFLEN 4 * 1024 | ||||
#define RCTL_DEFAULT_BUFSIZE 4096 | #define RCTL_MAX_OUTBUFLEN 16 * 1024 * 1024 | ||||
#define RCTL_MAX_INBUFLEN 4096 | |||||
#define RCTL_LOG_BUFSIZE 128 | #define RCTL_LOG_BUFSIZE 128 | ||||
#define RCTL_PCPU_SHIFT (10 * 1000000) | #define RCTL_PCPU_SHIFT (10 * 1000000) | ||||
unsigned int rctl_maxbufsize = RCTL_MAX_OUTBUFLEN; | |||||
SYSCTL_NODE(_kern_racct, OID_AUTO, rctl, CTLFLAG_RW, 0, "Resource Limits"); | |||||
SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, maxbufsize, CTLFLAG_RWTUN, | |||||
&rctl_maxbufsize, 0, "Maximum output buffer size"); | |||||
/* | /* | ||||
* 'rctl_rule_link' connects a rule with every racct it's related to. | * 'rctl_rule_link' connects a rule with every racct it's related to. | ||||
* For example, rule 'user:X:openfiles:deny=N/process' is linked | * For example, rule 'user:X:openfiles:deny=N/process' is linked | ||||
* with uidinfo for user X, and to each process of that user. | * with uidinfo for user X, and to each process of that user. | ||||
*/ | */ | ||||
struct rctl_rule_link { | struct rctl_rule_link { | ||||
LIST_ENTRY(rctl_rule_link) rrl_next; | LIST_ENTRY(rctl_rule_link) rrl_next; | ||||
struct rctl_rule *rrl_rule; | struct rctl_rule *rrl_rule; | ||||
▲ Show 20 Lines • Show All 1,341 Lines • ▼ Show 20 Lines | rctl_get_rules_callback(struct racct *racct, void *arg2, void *arg3) | ||||
} | } | ||||
rw_runlock(&rctl_lock); | rw_runlock(&rctl_lock); | ||||
} | } | ||||
int | int | ||||
sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap) | sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap) | ||||
{ | { | ||||
int error; | int error; | ||||
size_t bufsize = RCTL_DEFAULT_BUFSIZE; | size_t bufsize; | ||||
char *inputstr, *buf; | char *inputstr, *buf; | ||||
struct sbuf *sb; | struct sbuf *sb; | ||||
struct rctl_rule *filter; | struct rctl_rule *filter; | ||||
struct rctl_rule_link *link; | struct rctl_rule_link *link; | ||||
struct proc *p; | struct proc *p; | ||||
if (!racct_enable) | if (!racct_enable) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
Show All 9 Lines | sys_rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap) | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
error = rctl_string_to_rule(inputstr, &filter); | error = rctl_string_to_rule(inputstr, &filter); | ||||
free(inputstr, M_RCTL); | free(inputstr, M_RCTL); | ||||
if (error != 0) { | if (error != 0) { | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
again: | bufsize = uap->outbuflen; | ||||
if (bufsize > rctl_maxbufsize) { | |||||
sx_sunlock(&allproc_lock); | |||||
return (E2BIG); | |||||
} | |||||
buf = malloc(bufsize, M_RCTL, M_WAITOK); | buf = malloc(bufsize, M_RCTL, M_WAITOK); | ||||
sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); | sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); | ||||
KASSERT(sb != NULL, ("sbuf_new failed")); | KASSERT(sb != NULL, ("sbuf_new failed")); | ||||
sx_assert(&allproc_lock, SA_LOCKED); | |||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
rw_rlock(&rctl_lock); | rw_rlock(&rctl_lock); | ||||
LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { | LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) { | ||||
/* | /* | ||||
* Non-process rules will be added to the buffer later. | * Non-process rules will be added to the buffer later. | ||||
* Adding them here would result in duplicated output. | * Adding them here would result in duplicated output. | ||||
*/ | */ | ||||
if (link->rrl_rule->rr_subject_type != | if (link->rrl_rule->rr_subject_type != | ||||
RCTL_SUBJECT_TYPE_PROCESS) | RCTL_SUBJECT_TYPE_PROCESS) | ||||
continue; | continue; | ||||
if (!rctl_rule_matches(link->rrl_rule, filter)) | if (!rctl_rule_matches(link->rrl_rule, filter)) | ||||
continue; | continue; | ||||
rctl_rule_to_sbuf(sb, link->rrl_rule); | rctl_rule_to_sbuf(sb, link->rrl_rule); | ||||
sbuf_printf(sb, ","); | sbuf_printf(sb, ","); | ||||
} | } | ||||
rw_runlock(&rctl_lock); | rw_runlock(&rctl_lock); | ||||
} | } | ||||
loginclass_racct_foreach(rctl_get_rules_callback, filter, sb); | loginclass_racct_foreach(rctl_get_rules_callback, filter, sb); | ||||
ui_racct_foreach(rctl_get_rules_callback, filter, sb); | ui_racct_foreach(rctl_get_rules_callback, filter, sb); | ||||
prison_racct_foreach(rctl_get_rules_callback, filter, sb); | prison_racct_foreach(rctl_get_rules_callback, filter, sb); | ||||
if (sbuf_error(sb) == ENOMEM) { | if (sbuf_error(sb) == ENOMEM) { | ||||
sbuf_delete(sb); | error = ERANGE; | ||||
free(buf, M_RCTL); | goto out; | ||||
bufsize *= 4; | |||||
goto again; | |||||
} | } | ||||
/* | /* | ||||
* Remove trailing ",". | * Remove trailing ",". | ||||
*/ | */ | ||||
if (sbuf_len(sb) > 0) | if (sbuf_len(sb) > 0) | ||||
sbuf_setpos(sb, sbuf_len(sb) - 1); | sbuf_setpos(sb, sbuf_len(sb) - 1); | ||||
error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); | error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); | ||||
out: | |||||
rctl_rule_release(filter); | rctl_rule_release(filter); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
free(buf, M_RCTL); | free(buf, M_RCTL); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap) | sys_rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap) | ||||
{ | { | ||||
int error; | int error; | ||||
size_t bufsize = RCTL_DEFAULT_BUFSIZE; | size_t bufsize; | ||||
char *inputstr, *buf; | char *inputstr, *buf; | ||||
struct sbuf *sb; | struct sbuf *sb; | ||||
struct rctl_rule *filter; | struct rctl_rule *filter; | ||||
struct rctl_rule_link *link; | struct rctl_rule_link *link; | ||||
if (!racct_enable) | if (!racct_enable) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
Show All 24 Lines | if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_PROCESS) { | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
if (filter->rr_subject.rs_proc == NULL) { | if (filter->rr_subject.rs_proc == NULL) { | ||||
rctl_rule_release(filter); | rctl_rule_release(filter); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
again: | bufsize = uap->outbuflen; | ||||
if (bufsize > rctl_maxbufsize) { | |||||
rctl_rule_release(filter); | |||||
sx_sunlock(&allproc_lock); | |||||
return (E2BIG); | |||||
} | |||||
buf = malloc(bufsize, M_RCTL, M_WAITOK); | buf = malloc(bufsize, M_RCTL, M_WAITOK); | ||||
sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); | sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN); | ||||
KASSERT(sb != NULL, ("sbuf_new failed")); | KASSERT(sb != NULL, ("sbuf_new failed")); | ||||
rw_rlock(&rctl_lock); | rw_rlock(&rctl_lock); | ||||
LIST_FOREACH(link, &filter->rr_subject.rs_proc->p_racct->r_rule_links, | LIST_FOREACH(link, &filter->rr_subject.rs_proc->p_racct->r_rule_links, | ||||
rrl_next) { | rrl_next) { | ||||
rctl_rule_to_sbuf(sb, link->rrl_rule); | rctl_rule_to_sbuf(sb, link->rrl_rule); | ||||
sbuf_printf(sb, ","); | sbuf_printf(sb, ","); | ||||
} | } | ||||
rw_runlock(&rctl_lock); | rw_runlock(&rctl_lock); | ||||
if (sbuf_error(sb) == ENOMEM) { | if (sbuf_error(sb) == ENOMEM) { | ||||
sbuf_delete(sb); | error = ERANGE; | ||||
free(buf, M_RCTL); | goto out; | ||||
bufsize *= 4; | |||||
goto again; | |||||
} | } | ||||
/* | /* | ||||
* Remove trailing ",". | * Remove trailing ",". | ||||
*/ | */ | ||||
if (sbuf_len(sb) > 0) | if (sbuf_len(sb) > 0) | ||||
sbuf_setpos(sb, sbuf_len(sb) - 1); | sbuf_setpos(sb, sbuf_len(sb) - 1); | ||||
error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); | error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen); | ||||
out: | |||||
rctl_rule_release(filter); | rctl_rule_release(filter); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
free(buf, M_RCTL); | free(buf, M_RCTL); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap) | sys_rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap) | ||||
▲ Show 20 Lines • Show All 349 Lines • Show Last 20 Lines |