Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_racct.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#ifdef RACCT | #ifdef RACCT | ||||
FEATURE(racct, "Resource Accounting"); | FEATURE(racct, "Resource Accounting"); | ||||
/* | /* | ||||
* Do not block processes that have their %cpu usage <= pcpu_threshold. | * Do not block processes that have their %cpu usage <= pcpu_threshold. | ||||
*/ | */ | ||||
static int pcpu_threshold = 1; | static int pcpu_threshold = 1; | ||||
#ifdef RACCT_DISABLED | |||||
int racct_enable = 0; | |||||
#else | |||||
int racct_enable = 1; | |||||
#endif | |||||
SYSCTL_NODE(_kern, OID_AUTO, racct, CTLFLAG_RW, 0, "Resource Accounting"); | SYSCTL_NODE(_kern, OID_AUTO, racct, CTLFLAG_RW, 0, "Resource Accounting"); | ||||
SYSCTL_UINT(_kern_racct, OID_AUTO, enable, CTLFLAG_RDTUN, &racct_enable, | |||||
0, "Enable RACCT/RCTL"); | |||||
op: Ahh, I see now. That's a RO sysctl.
Could you please add a comment here, to explain, that this… | |||||
SYSCTL_UINT(_kern_racct, OID_AUTO, pcpu_threshold, CTLFLAG_RW, &pcpu_threshold, | SYSCTL_UINT(_kern_racct, OID_AUTO, pcpu_threshold, CTLFLAG_RW, &pcpu_threshold, | ||||
0, "Processes with higher %cpu usage than this value can be throttled."); | 0, "Processes with higher %cpu usage than this value can be throttled."); | ||||
/* | /* | ||||
* How many seconds it takes to use the scheduler %cpu calculations. When a | * How many seconds it takes to use the scheduler %cpu calculations. When a | ||||
* process starts, we compute its %cpu usage by dividing its runtime by the | * process starts, we compute its %cpu usage by dividing its runtime by the | ||||
* process wall clock time. After RACCT_PCPU_SECS pass, we use the value | * process wall clock time. After RACCT_PCPU_SECS pass, we use the value | ||||
* provided by the scheduler. | * provided by the scheduler. | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
#ifdef SMP | #ifdef SMP | ||||
struct pcpu *pc; | struct pcpu *pc; | ||||
int found; | int found; | ||||
#endif | #endif | ||||
fixpt_t p_pctcpu; | fixpt_t p_pctcpu; | ||||
struct thread *td; | struct thread *td; | ||||
ASSERT_RACCT_ENABLED(); | |||||
/* | /* | ||||
* If the process is swapped out, we count its %cpu usage as zero. | * If the process is swapped out, we count its %cpu usage as zero. | ||||
* This behaviour is consistent with the userland ps(1) tool. | * This behaviour is consistent with the userland ps(1) tool. | ||||
*/ | */ | ||||
if ((p->p_flag & P_INMEM) == 0) | if ((p->p_flag & P_INMEM) == 0) | ||||
return (0); | return (0); | ||||
swtime = (ticks - p->p_swtick) / hz; | swtime = (ticks - p->p_swtick) / hz; | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
return ((100 * (uint64_t)p_pctcpu * 1000000) / FSCALE); | return ((100 * (uint64_t)p_pctcpu * 1000000) / FSCALE); | ||||
} | } | ||||
static void | static void | ||||
racct_add_racct(struct racct *dest, const struct racct *src) | racct_add_racct(struct racct *dest, const struct racct *src) | ||||
{ | { | ||||
int i; | int i; | ||||
ASSERT_RACCT_ENABLED(); | |||||
mtx_assert(&racct_lock, MA_OWNED); | mtx_assert(&racct_lock, MA_OWNED); | ||||
/* | /* | ||||
* Update resource usage in dest. | * Update resource usage in dest. | ||||
*/ | */ | ||||
for (i = 0; i <= RACCT_MAX; i++) { | for (i = 0; i <= RACCT_MAX; i++) { | ||||
KASSERT(dest->r_resources[i] >= 0, | KASSERT(dest->r_resources[i] >= 0, | ||||
("%s: resource %d propagation meltdown: dest < 0", | ("%s: resource %d propagation meltdown: dest < 0", | ||||
__func__, i)); | __func__, i)); | ||||
KASSERT(src->r_resources[i] >= 0, | KASSERT(src->r_resources[i] >= 0, | ||||
("%s: resource %d propagation meltdown: src < 0", | ("%s: resource %d propagation meltdown: src < 0", | ||||
__func__, i)); | __func__, i)); | ||||
dest->r_resources[i] += src->r_resources[i]; | dest->r_resources[i] += src->r_resources[i]; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
racct_sub_racct(struct racct *dest, const struct racct *src) | racct_sub_racct(struct racct *dest, const struct racct *src) | ||||
{ | { | ||||
int i; | int i; | ||||
ASSERT_RACCT_ENABLED(); | |||||
mtx_assert(&racct_lock, MA_OWNED); | mtx_assert(&racct_lock, MA_OWNED); | ||||
/* | /* | ||||
* Update resource usage in dest. | * Update resource usage in dest. | ||||
*/ | */ | ||||
for (i = 0; i <= RACCT_MAX; i++) { | for (i = 0; i <= RACCT_MAX; i++) { | ||||
if (!RACCT_IS_SLOPPY(i) && !RACCT_IS_DECAYING(i)) { | if (!RACCT_IS_SLOPPY(i) && !RACCT_IS_DECAYING(i)) { | ||||
KASSERT(dest->r_resources[i] >= 0, | KASSERT(dest->r_resources[i] >= 0, | ||||
Show All 17 Lines | for (i = 0; i <= RACCT_MAX; i++) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void | void | ||||
racct_create(struct racct **racctp) | racct_create(struct racct **racctp) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
SDT_PROBE(racct, kernel, racct, create, racctp, 0, 0, 0, 0); | SDT_PROBE(racct, kernel, racct, create, racctp, 0, 0, 0, 0); | ||||
KASSERT(*racctp == NULL, ("racct already allocated")); | KASSERT(*racctp == NULL, ("racct already allocated")); | ||||
*racctp = uma_zalloc(racct_zone, M_WAITOK | M_ZERO); | *racctp = uma_zalloc(racct_zone, M_WAITOK | M_ZERO); | ||||
} | } | ||||
static void | static void | ||||
racct_destroy_locked(struct racct **racctp) | racct_destroy_locked(struct racct **racctp) | ||||
{ | { | ||||
int i; | int i; | ||||
struct racct *racct; | struct racct *racct; | ||||
ASSERT_RACCT_ENABLED(); | |||||
opUnsubmitted Not Done Inline ActionsThis is useless, if my theory not wrong. op: This is useless, if my theory not wrong. | |||||
SDT_PROBE(racct, kernel, racct, destroy, racctp, 0, 0, 0, 0); | SDT_PROBE(racct, kernel, racct, destroy, racctp, 0, 0, 0, 0); | ||||
mtx_assert(&racct_lock, MA_OWNED); | mtx_assert(&racct_lock, MA_OWNED); | ||||
KASSERT(racctp != NULL, ("NULL racctp")); | KASSERT(racctp != NULL, ("NULL racctp")); | ||||
KASSERT(*racctp != NULL, ("NULL racct")); | KASSERT(*racctp != NULL, ("NULL racct")); | ||||
racct = *racctp; | racct = *racctp; | ||||
Show All 10 Lines | racct_destroy_locked(struct racct **racctp) | ||||
uma_zfree(racct_zone, racct); | uma_zfree(racct_zone, racct); | ||||
*racctp = NULL; | *racctp = NULL; | ||||
} | } | ||||
void | void | ||||
racct_destroy(struct racct **racct) | racct_destroy(struct racct **racct) | ||||
{ | { | ||||
if (!racct_enable) | |||||
opUnsubmitted Not Done Inline ActionsSame here. op: Same here. | |||||
opUnsubmitted Not Done Inline ActionsThis expression should be against "*racct == NULL" instead of "racct_enable". op: This expression should be against "*racct == NULL" instead of "racct_enable". | |||||
return; | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_destroy_locked(racct); | racct_destroy_locked(racct); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
/* | /* | ||||
* Increase consumption of 'resource' by 'amount' for 'racct' | * Increase consumption of 'resource' by 'amount' for 'racct' | ||||
* and all its parents. Differently from other cases, 'amount' here | * and all its parents. Differently from other cases, 'amount' here | ||||
* may be less than zero. | * may be less than zero. | ||||
*/ | */ | ||||
static void | static void | ||||
racct_alloc_resource(struct racct *racct, int resource, | racct_alloc_resource(struct racct *racct, int resource, | ||||
uint64_t amount) | uint64_t amount) | ||||
{ | { | ||||
ASSERT_RACCT_ENABLED(); | |||||
mtx_assert(&racct_lock, MA_OWNED); | mtx_assert(&racct_lock, MA_OWNED); | ||||
KASSERT(racct != NULL, ("NULL racct")); | KASSERT(racct != NULL, ("NULL racct")); | ||||
racct->r_resources[resource] += amount; | racct->r_resources[resource] += amount; | ||||
if (racct->r_resources[resource] < 0) { | if (racct->r_resources[resource] < 0) { | ||||
KASSERT(RACCT_IS_SLOPPY(resource) || RACCT_IS_DECAYING(resource), | KASSERT(RACCT_IS_SLOPPY(resource) || RACCT_IS_DECAYING(resource), | ||||
("%s: resource %d usage < 0", __func__, resource)); | ("%s: resource %d usage < 0", __func__, resource)); | ||||
racct->r_resources[resource] = 0; | racct->r_resources[resource] = 0; | ||||
Show All 15 Lines | |||||
static int | static int | ||||
racct_add_locked(struct proc *p, int resource, uint64_t amount) | racct_add_locked(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
#ifdef RCTL | #ifdef RCTL | ||||
int error; | int error; | ||||
#endif | #endif | ||||
ASSERT_RACCT_ENABLED(); | |||||
SDT_PROBE(racct, kernel, rusage, add, p, resource, amount, 0, 0); | SDT_PROBE(racct, kernel, rusage, add, p, resource, amount, 0, 0); | ||||
/* | /* | ||||
* We need proc lock to dereference p->p_ucred. | * We need proc lock to dereference p->p_ucred. | ||||
*/ | */ | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
#ifdef RCTL | #ifdef RCTL | ||||
Show All 14 Lines | |||||
* Increase allocation of 'resource' by 'amount' for process 'p'. | * Increase allocation of 'resource' by 'amount' for process 'p'. | ||||
* Return 0 if it's below limits, or errno, if it's not. | * Return 0 if it's below limits, or errno, if it's not. | ||||
*/ | */ | ||||
int | int | ||||
racct_add(struct proc *p, int resource, uint64_t amount) | racct_add(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
int error; | int error; | ||||
if (!racct_enable) | |||||
return (0); | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
error = racct_add_locked(p, resource, amount); | error = racct_add_locked(p, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount) | racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount) | ||||
{ | { | ||||
struct prison *pr; | struct prison *pr; | ||||
ASSERT_RACCT_ENABLED(); | |||||
SDT_PROBE(racct, kernel, rusage, add__cred, cred, resource, amount, | SDT_PROBE(racct, kernel, rusage, add__cred, cred, resource, amount, | ||||
0, 0); | 0, 0); | ||||
racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, amount); | racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, amount); | ||||
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) | for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) | ||||
racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, | racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, | ||||
amount); | amount); | ||||
racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, amount); | racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, amount); | ||||
} | } | ||||
/* | /* | ||||
* Increase allocation of 'resource' by 'amount' for credential 'cred'. | * Increase allocation of 'resource' by 'amount' for credential 'cred'. | ||||
* Doesn't check for limits and never fails. | * Doesn't check for limits and never fails. | ||||
* | * | ||||
* XXX: Shouldn't this ever return an error? | * XXX: Shouldn't this ever return an error? | ||||
*/ | */ | ||||
void | void | ||||
racct_add_cred(struct ucred *cred, int resource, uint64_t amount) | racct_add_cred(struct ucred *cred, int resource, uint64_t amount) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_add_cred_locked(cred, resource, amount); | racct_add_cred_locked(cred, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
/* | /* | ||||
* Increase allocation of 'resource' by 'amount' for process 'p'. | * Increase allocation of 'resource' by 'amount' for process 'p'. | ||||
* Doesn't check for limits and never fails. | * Doesn't check for limits and never fails. | ||||
*/ | */ | ||||
void | void | ||||
racct_add_force(struct proc *p, int resource, uint64_t amount) | racct_add_force(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
SDT_PROBE(racct, kernel, rusage, add__force, p, resource, amount, 0, 0); | SDT_PROBE(racct, kernel, rusage, add__force, p, resource, amount, 0, 0); | ||||
/* | /* | ||||
* We need proc lock to dereference p->p_ucred. | * We need proc lock to dereference p->p_ucred. | ||||
*/ | */ | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_alloc_resource(p->p_racct, resource, amount); | racct_alloc_resource(p->p_racct, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
racct_add_cred(p->p_ucred, resource, amount); | racct_add_cred(p->p_ucred, resource, amount); | ||||
} | } | ||||
static int | static int | ||||
racct_set_locked(struct proc *p, int resource, uint64_t amount) | racct_set_locked(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
int64_t old_amount, decayed_amount; | int64_t old_amount, decayed_amount; | ||||
int64_t diff_proc, diff_cred; | int64_t diff_proc, diff_cred; | ||||
#ifdef RCTL | #ifdef RCTL | ||||
int error; | int error; | ||||
#endif | #endif | ||||
ASSERT_RACCT_ENABLED(); | |||||
SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); | SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); | ||||
/* | /* | ||||
* We need proc lock to dereference p->p_ucred. | * We need proc lock to dereference p->p_ucred. | ||||
*/ | */ | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
old_amount = p->p_racct->r_resources[resource]; | old_amount = p->p_racct->r_resources[resource]; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
* Note that decreasing the allocation always returns 0, | * Note that decreasing the allocation always returns 0, | ||||
* even if it's above the limit. | * even if it's above the limit. | ||||
*/ | */ | ||||
int | int | ||||
racct_set(struct proc *p, int resource, uint64_t amount) | racct_set(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
int error; | int error; | ||||
if (!racct_enable) | |||||
return (0); | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
error = racct_set_locked(p, resource, amount); | error = racct_set_locked(p, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
racct_set_force_locked(struct proc *p, int resource, uint64_t amount) | racct_set_force_locked(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
int64_t old_amount, decayed_amount; | int64_t old_amount, decayed_amount; | ||||
int64_t diff_proc, diff_cred; | int64_t diff_proc, diff_cred; | ||||
ASSERT_RACCT_ENABLED(); | |||||
SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); | SDT_PROBE(racct, kernel, rusage, set, p, resource, amount, 0, 0); | ||||
/* | /* | ||||
* We need proc lock to dereference p->p_ucred. | * We need proc lock to dereference p->p_ucred. | ||||
*/ | */ | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
old_amount = p->p_racct->r_resources[resource]; | old_amount = p->p_racct->r_resources[resource]; | ||||
Show All 18 Lines | if (diff_cred > 0) | ||||
racct_add_cred_locked(p->p_ucred, resource, diff_cred); | racct_add_cred_locked(p->p_ucred, resource, diff_cred); | ||||
else if (diff_cred < 0) | else if (diff_cred < 0) | ||||
racct_sub_cred_locked(p->p_ucred, resource, -diff_cred); | racct_sub_cred_locked(p->p_ucred, resource, -diff_cred); | ||||
} | } | ||||
void | void | ||||
racct_set_force(struct proc *p, int resource, uint64_t amount) | racct_set_force(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_set_force_locked(p, resource, amount); | racct_set_force_locked(p, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
/* | /* | ||||
* Returns amount of 'resource' the process 'p' can keep allocated. | * Returns amount of 'resource' the process 'p' can keep allocated. | ||||
* Allocating more than that would be denied, unless the resource | * Allocating more than that would be denied, unless the resource | ||||
* is marked undeniable. Amount of already allocated resource does | * is marked undeniable. Amount of already allocated resource does | ||||
* not matter. | * not matter. | ||||
*/ | */ | ||||
uint64_t | uint64_t | ||||
racct_get_limit(struct proc *p, int resource) | racct_get_limit(struct proc *p, int resource) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return (UINT64_MAX); | |||||
#ifdef RCTL | #ifdef RCTL | ||||
return (rctl_get_limit(p, resource)); | return (rctl_get_limit(p, resource)); | ||||
#else | #else | ||||
return (UINT64_MAX); | return (UINT64_MAX); | ||||
#endif | #endif | ||||
} | } | ||||
/* | /* | ||||
* Returns amount of 'resource' the process 'p' can keep allocated. | * Returns amount of 'resource' the process 'p' can keep allocated. | ||||
* Allocating more than that would be denied, unless the resource | * Allocating more than that would be denied, unless the resource | ||||
* is marked undeniable. Amount of already allocated resource does | * is marked undeniable. Amount of already allocated resource does | ||||
* matter. | * matter. | ||||
*/ | */ | ||||
uint64_t | uint64_t | ||||
racct_get_available(struct proc *p, int resource) | racct_get_available(struct proc *p, int resource) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return (UINT64_MAX); | |||||
#ifdef RCTL | #ifdef RCTL | ||||
return (rctl_get_available(p, resource)); | return (rctl_get_available(p, resource)); | ||||
#else | #else | ||||
return (UINT64_MAX); | return (UINT64_MAX); | ||||
#endif | #endif | ||||
} | } | ||||
/* | /* | ||||
* Returns amount of the %cpu resource that process 'p' can add to its %cpu | * Returns amount of the %cpu resource that process 'p' can add to its %cpu | ||||
* utilization. Adding more than that would lead to the process being | * utilization. Adding more than that would lead to the process being | ||||
* throttled. | * throttled. | ||||
*/ | */ | ||||
static int64_t | static int64_t | ||||
racct_pcpu_available(struct proc *p) | racct_pcpu_available(struct proc *p) | ||||
{ | { | ||||
ASSERT_RACCT_ENABLED(); | |||||
#ifdef RCTL | #ifdef RCTL | ||||
return (rctl_pcpu_available(p)); | return (rctl_pcpu_available(p)); | ||||
#else | #else | ||||
return (INT64_MAX); | return (INT64_MAX); | ||||
#endif | #endif | ||||
} | } | ||||
/* | /* | ||||
* Decrease allocation of 'resource' by 'amount' for process 'p'. | * Decrease allocation of 'resource' by 'amount' for process 'p'. | ||||
*/ | */ | ||||
void | void | ||||
racct_sub(struct proc *p, int resource, uint64_t amount) | racct_sub(struct proc *p, int resource, uint64_t amount) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
SDT_PROBE(racct, kernel, rusage, sub, p, resource, amount, 0, 0); | SDT_PROBE(racct, kernel, rusage, sub, p, resource, amount, 0, 0); | ||||
/* | /* | ||||
* We need proc lock to dereference p->p_ucred. | * We need proc lock to dereference p->p_ucred. | ||||
*/ | */ | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
KASSERT(RACCT_CAN_DROP(resource), | KASSERT(RACCT_CAN_DROP(resource), | ||||
("%s: called for non-droppable resource %d", __func__, resource)); | ("%s: called for non-droppable resource %d", __func__, resource)); | ||||
Show All 9 Lines | racct_sub(struct proc *p, int resource, uint64_t amount) | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
static void | static void | ||||
racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount) | racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount) | ||||
{ | { | ||||
struct prison *pr; | struct prison *pr; | ||||
ASSERT_RACCT_ENABLED(); | |||||
SDT_PROBE(racct, kernel, rusage, sub__cred, cred, resource, amount, | SDT_PROBE(racct, kernel, rusage, sub__cred, cred, resource, amount, | ||||
0, 0); | 0, 0); | ||||
#ifdef notyet | #ifdef notyet | ||||
KASSERT(RACCT_CAN_DROP(resource), | KASSERT(RACCT_CAN_DROP(resource), | ||||
("%s: called for resource %d which can not drop", __func__, | ("%s: called for resource %d which can not drop", __func__, | ||||
resource)); | resource)); | ||||
#endif | #endif | ||||
racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, -amount); | racct_alloc_resource(cred->cr_ruidinfo->ui_racct, resource, -amount); | ||||
for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) | for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) | ||||
racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, | racct_alloc_resource(pr->pr_prison_racct->prr_racct, resource, | ||||
-amount); | -amount); | ||||
racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, -amount); | racct_alloc_resource(cred->cr_loginclass->lc_racct, resource, -amount); | ||||
} | } | ||||
/* | /* | ||||
* Decrease allocation of 'resource' by 'amount' for credential 'cred'. | * Decrease allocation of 'resource' by 'amount' for credential 'cred'. | ||||
*/ | */ | ||||
void | void | ||||
racct_sub_cred(struct ucred *cred, int resource, uint64_t amount) | racct_sub_cred(struct ucred *cred, int resource, uint64_t amount) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_sub_cred_locked(cred, resource, amount); | racct_sub_cred_locked(cred, resource, amount); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
/* | /* | ||||
* Inherit resource usage information from the parent process. | * Inherit resource usage information from the parent process. | ||||
*/ | */ | ||||
int | int | ||||
racct_proc_fork(struct proc *parent, struct proc *child) | racct_proc_fork(struct proc *parent, struct proc *child) | ||||
{ | { | ||||
int i, error = 0; | int i, error = 0; | ||||
if (!racct_enable) | |||||
return (0); | |||||
/* | /* | ||||
* Create racct for the child process. | * Create racct for the child process. | ||||
*/ | */ | ||||
racct_create(&child->p_racct); | racct_create(&child->p_racct); | ||||
PROC_LOCK(parent); | PROC_LOCK(parent); | ||||
PROC_LOCK(child); | PROC_LOCK(child); | ||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
Show All 40 Lines | |||||
* Called at the end of fork1(), to handle rules that require the process | * Called at the end of fork1(), to handle rules that require the process | ||||
* to be fully initialized. | * to be fully initialized. | ||||
*/ | */ | ||||
void | void | ||||
racct_proc_fork_done(struct proc *child) | racct_proc_fork_done(struct proc *child) | ||||
{ | { | ||||
#ifdef RCTL | #ifdef RCTL | ||||
if (!racct_enable) | |||||
return; | |||||
PROC_LOCK(child); | PROC_LOCK(child); | ||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
rctl_enforce(child, RACCT_NPROC, 0); | rctl_enforce(child, RACCT_NPROC, 0); | ||||
rctl_enforce(child, RACCT_NTHR, 0); | rctl_enforce(child, RACCT_NTHR, 0); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
PROC_UNLOCK(child); | PROC_UNLOCK(child); | ||||
#endif | #endif | ||||
} | } | ||||
void | void | ||||
racct_proc_exit(struct proc *p) | racct_proc_exit(struct proc *p) | ||||
{ | { | ||||
int i; | int i; | ||||
uint64_t runtime; | uint64_t runtime; | ||||
struct timeval wallclock; | struct timeval wallclock; | ||||
uint64_t pct_estimate, pct; | uint64_t pct_estimate, pct; | ||||
if (!racct_enable) | |||||
return; | |||||
opUnsubmitted Not Done Inline ActionsThis does not cause memory leak? The steps in theory:
Before this change, the racct_destroy() was always gets running. op: This does not cause memory leak?
The steps in theory:
1. enable the resource accounting
2. | |||||
traszAuthorUnsubmitted Not Done Inline ActionsThe step #3 cannot ever happen; racct_enable is a tunable, not a sysctl - for this and several others, quite fundamental, reasons. trasz: The step #3 cannot ever happen; racct_enable is a tunable, not a sysctl - for this and several… | |||||
opUnsubmitted Not Done Inline ActionsFine. I missed that the sysctl is RO only. op: Fine. I missed that the sysctl is RO only. | |||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
/* | /* | ||||
* We don't need to calculate rux, proc_reap() has already done this. | * We don't need to calculate rux, proc_reap() has already done this. | ||||
*/ | */ | ||||
runtime = cputick2usec(p->p_rux.rux_runtime); | runtime = cputick2usec(p->p_rux.rux_runtime); | ||||
#ifdef notyet | #ifdef notyet | ||||
KASSERT(runtime >= p->p_prev_runtime, ("runtime < p_prev_runtime")); | KASSERT(runtime >= p->p_prev_runtime, ("runtime < p_prev_runtime")); | ||||
#else | #else | ||||
Show All 38 Lines | |||||
void | void | ||||
racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, | racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred, | ||||
struct ucred *newcred) | struct ucred *newcred) | ||||
{ | { | ||||
struct uidinfo *olduip, *newuip; | struct uidinfo *olduip, *newuip; | ||||
struct loginclass *oldlc, *newlc; | struct loginclass *oldlc, *newlc; | ||||
struct prison *oldpr, *newpr, *pr; | struct prison *oldpr, *newpr, *pr; | ||||
if (!racct_enable) | |||||
return; | |||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||
newuip = newcred->cr_ruidinfo; | newuip = newcred->cr_ruidinfo; | ||||
olduip = oldcred->cr_ruidinfo; | olduip = oldcred->cr_ruidinfo; | ||||
newlc = newcred->cr_loginclass; | newlc = newcred->cr_loginclass; | ||||
oldlc = oldcred->cr_loginclass; | oldlc = oldcred->cr_loginclass; | ||||
newpr = newcred->cr_prison; | newpr = newcred->cr_prison; | ||||
oldpr = oldcred->cr_prison; | oldpr = oldcred->cr_prison; | ||||
Show All 21 Lines | #ifdef RCTL | ||||
rctl_proc_ucred_changed(p, newcred); | rctl_proc_ucred_changed(p, newcred); | ||||
#endif | #endif | ||||
} | } | ||||
void | void | ||||
racct_move(struct racct *dest, struct racct *src) | racct_move(struct racct *dest, struct racct *src) | ||||
{ | { | ||||
ASSERT_RACCT_ENABLED(); | |||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
racct_add_racct(dest, src); | racct_add_racct(dest, src); | ||||
racct_sub_racct(src, src); | racct_sub_racct(src, src); | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
static void | static void | ||||
racct_proc_throttle(struct proc *p) | racct_proc_throttle(struct proc *p) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
#ifdef SMP | #ifdef SMP | ||||
int cpuid; | int cpuid; | ||||
#endif | #endif | ||||
ASSERT_RACCT_ENABLED(); | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
/* | /* | ||||
* Do not block kernel processes. Also do not block processes with | * Do not block kernel processes. Also do not block processes with | ||||
* low %cpu utilization to improve interactivity. | * low %cpu utilization to improve interactivity. | ||||
*/ | */ | ||||
if (((p->p_flag & (P_SYSTEM | P_KTHREAD)) != 0) || | if (((p->p_flag & (P_SYSTEM | P_KTHREAD)) != 0) || | ||||
(p->p_racct->r_resources[RACCT_PCTCPU] <= pcpu_threshold)) | (p->p_racct->r_resources[RACCT_PCTCPU] <= pcpu_threshold)) | ||||
Show All 29 Lines | #endif | ||||
} | } | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
racct_proc_wakeup(struct proc *p) | racct_proc_wakeup(struct proc *p) | ||||
{ | { | ||||
ASSERT_RACCT_ENABLED(); | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
if (p->p_throttled) { | if (p->p_throttled) { | ||||
p->p_throttled = 0; | p->p_throttled = 0; | ||||
wakeup(p->p_racct); | wakeup(p->p_racct); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
racct_decay_resource(struct racct *racct, void * res, void* dummy) | racct_decay_resource(struct racct *racct, void * res, void* dummy) | ||||
{ | { | ||||
int resource; | int resource; | ||||
int64_t r_old, r_new; | int64_t r_old, r_new; | ||||
ASSERT_RACCT_ENABLED(); | |||||
resource = *(int *)res; | resource = *(int *)res; | ||||
r_old = racct->r_resources[resource]; | r_old = racct->r_resources[resource]; | ||||
/* If there is nothing to decay, just exit. */ | /* If there is nothing to decay, just exit. */ | ||||
if (r_old <= 0) | if (r_old <= 0) | ||||
return; | return; | ||||
mtx_lock(&racct_lock); | mtx_lock(&racct_lock); | ||||
r_new = r_old * RACCT_DECAY_FACTOR / FSCALE; | r_new = r_old * RACCT_DECAY_FACTOR / FSCALE; | ||||
racct->r_resources[resource] = r_new; | racct->r_resources[resource] = r_new; | ||||
mtx_unlock(&racct_lock); | mtx_unlock(&racct_lock); | ||||
} | } | ||||
static void | static void | ||||
racct_decay(int resource) | racct_decay(int resource) | ||||
{ | { | ||||
ASSERT_RACCT_ENABLED(); | |||||
ui_racct_foreach(racct_decay_resource, &resource, NULL); | ui_racct_foreach(racct_decay_resource, &resource, NULL); | ||||
loginclass_racct_foreach(racct_decay_resource, &resource, NULL); | loginclass_racct_foreach(racct_decay_resource, &resource, NULL); | ||||
prison_racct_foreach(racct_decay_resource, &resource, NULL); | prison_racct_foreach(racct_decay_resource, &resource, NULL); | ||||
} | } | ||||
static void | static void | ||||
racctd(void) | racctd(void) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
struct proc *p; | struct proc *p; | ||||
struct timeval wallclock; | struct timeval wallclock; | ||||
uint64_t runtime; | uint64_t runtime; | ||||
uint64_t pct, pct_estimate; | uint64_t pct, pct_estimate; | ||||
ASSERT_RACCT_ENABLED(); | |||||
for (;;) { | for (;;) { | ||||
racct_decay(RACCT_PCTCPU); | racct_decay(RACCT_PCTCPU); | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
LIST_FOREACH(p, &zombproc, p_list) { | LIST_FOREACH(p, &zombproc, p_list) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
racct_set(p, RACCT_PCTCPU, 0); | racct_set(p, RACCT_PCTCPU, 0); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
static struct kproc_desc racctd_kp = { | static struct kproc_desc racctd_kp = { | ||||
"racctd", | "racctd", | ||||
racctd, | racctd, | ||||
NULL | NULL | ||||
}; | }; | ||||
SYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, kproc_start, &racctd_kp); | |||||
static void | static void | ||||
racctd_init(void) | |||||
{ | |||||
if (!racct_enable) | |||||
return; | |||||
kproc_start(&racctd_kp); | |||||
} | |||||
SYSINIT(racctd, SI_SUB_RACCTD, SI_ORDER_FIRST, racctd_init, NULL); | |||||
static void | |||||
racct_init(void) | racct_init(void) | ||||
{ | { | ||||
if (!racct_enable) | |||||
return; | |||||
racct_zone = uma_zcreate("racct", sizeof(struct racct), | racct_zone = uma_zcreate("racct", sizeof(struct racct), | ||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); | NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); | ||||
/* | /* | ||||
* XXX: Move this somewhere. | * XXX: Move this somewhere. | ||||
*/ | */ | ||||
prison0.pr_prison_racct = prison_racct_find("0"); | prison0.pr_prison_racct = prison_racct_find("0"); | ||||
} | } | ||||
SYSINIT(racct, SI_SUB_RACCT, SI_ORDER_FIRST, racct_init, NULL); | SYSINIT(racct, SI_SUB_RACCT, SI_ORDER_FIRST, racct_init, NULL); | ||||
#endif /* !RACCT */ | #endif /* !RACCT */ |
Ahh, I see now. That's a RO sysctl.
Could you please add a comment here, to explain, that this never should be RW?