thread: batch credential freeing

This commit is contained in:
Mateusz Guzik 2020-11-14 19:22:02 +00:00
parent fb8ab68084
commit f34a2f56c3
3 changed files with 102 additions and 2 deletions

View File

@ -86,6 +86,7 @@ static MALLOC_DEFINE(M_CRED, "cred", "credentials");
SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"BSD security policy");
static void crfree_final(struct ucred *cr);
static void crsetgroups_locked(struct ucred *cr, int ngrp,
gid_t *groups);
@ -1902,6 +1903,31 @@ crunuse(struct thread *td)
return (crold);
}
static void
crunusebatch(struct ucred *cr, int users, int ref)
{
KASSERT(users > 0, ("%s: passed users %d not > 0 ; cred %p",
__func__, users, cr));
mtx_lock(&cr->cr_mtx);
KASSERT(cr->cr_users >= users, ("%s: users %d not > %d on cred %p",
__func__, cr->cr_users, users, cr));
cr->cr_users -= users;
cr->cr_ref += ref;
cr->cr_ref -= users;
if (cr->cr_users > 0) {
mtx_unlock(&cr->cr_mtx);
return;
}
KASSERT(cr->cr_ref >= 0, ("%s: ref %d not >= 0 on cred %p",
__func__, cr->cr_ref, cr));
if (cr->cr_ref > 0) {
mtx_unlock(&cr->cr_mtx);
return;
}
crfree_final(cr);
}
void
crcowfree(struct thread *td)
{
@ -1934,6 +1960,44 @@ crcowsync(void)
return (crold);
}
/*
* Batching.
*/
void
credbatch_add(struct credbatch *crb, struct thread *td)
{
struct ucred *cr;
MPASS(td->td_realucred != NULL);
MPASS(td->td_realucred == td->td_ucred);
MPASS(td->td_state == TDS_INACTIVE);
cr = td->td_realucred;
KASSERT(cr->cr_users > 0, ("%s: users %d not > 0 on cred %p",
__func__, cr->cr_users, cr));
if (crb->cred != cr) {
if (crb->users > 0) {
MPASS(crb->cred != NULL);
crunusebatch(crb->cred, crb->users, crb->ref);
crb->users = 0;
crb->ref = 0;
}
}
crb->cred = cr;
crb->users++;
crb->ref += td->td_ucredref;
td->td_ucredref = 0;
td->td_realucred = NULL;
}
void
credbatch_final(struct credbatch *crb)
{
MPASS(crb->cred != NULL);
MPASS(crb->users > 0);
crunusebatch(crb->cred, crb->users, crb->ref);
}
/*
* Allocate a zeroed cred structure.
*/
@ -2007,6 +2071,17 @@ crfree(struct ucred *cr)
mtx_unlock(&cr->cr_mtx);
return;
}
crfree_final(cr);
}
static void
crfree_final(struct ucred *cr)
{
KASSERT(cr->cr_users == 0, ("%s: users %d not == 0 on cred %p",
__func__, cr->cr_users, cr));
KASSERT(cr->cr_ref == 0, ("%s: ref %d not == 0 on cred %p",
__func__, cr->cr_ref, cr));
/*
* Some callers of crget(), such as nfs_statfs(), allocate a temporary
* credential, but don't allocate a uidinfo structure.

View File

@ -536,6 +536,7 @@ thread_reap(void)
{
struct thread *itd, *ntd;
struct tidbatch tidbatch;
struct credbatch credbatch;
int tdcount;
struct plimit *lim;
int limcount;
@ -553,6 +554,7 @@ thread_reap(void)
return;
tidbatch_prep(&tidbatch);
credbatch_prep(&credbatch);
tdcount = 0;
lim = NULL;
limcount = 0;
@ -560,8 +562,7 @@ thread_reap(void)
ntd = itd->td_zombie;
EVENTHANDLER_DIRECT_INVOKE(thread_dtor, itd);
tidbatch_add(&tidbatch, itd);
MPASS(itd->td_realucred != NULL);
crcowfree(itd);
credbatch_add(&credbatch, itd);
MPASS(itd->td_limit != NULL);
if (lim != itd->td_limit) {
if (limcount != 0) {
@ -573,6 +574,7 @@ thread_reap(void)
limcount++;
thread_free_batched(itd);
tidbatch_process(&tidbatch);
credbatch_process(&credbatch);
tdcount++;
if (tdcount == 32) {
thread_count_sub(tdcount);
@ -582,6 +584,7 @@ thread_reap(void)
}
tidbatch_final(&tidbatch);
credbatch_final(&credbatch);
if (tdcount != 0) {
thread_count_sub(tdcount);
}

View File

@ -114,6 +114,28 @@ struct xucred {
struct proc;
struct thread;
struct credbatch {
struct ucred *cred;
int users;
int ref;
};
static inline void
credbatch_prep(struct credbatch *crb)
{
crb->cred = NULL;
crb->users = 0;
crb->ref = 0;
}
void credbatch_add(struct credbatch *crb, struct thread *td);
static inline void
credbatch_process(struct credbatch *crb)
{
}
void credbatch_add(struct credbatch *crb, struct thread *td);
void credbatch_final(struct credbatch *crb);
void change_egid(struct ucred *newcred, gid_t egid);
void change_euid(struct ucred *newcred, struct uidinfo *euip);
void change_rgid(struct ucred *newcred, gid_t rgid);