diff options
author | alfred <alfred@FreeBSD.org> | 2000-11-30 19:15:22 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2000-11-30 19:15:22 +0000 |
commit | 259d62f4d89d01ef3c3cfece16aaf8c1cc802cd6 (patch) | |
tree | 4a2b08ffdc9db69004816679f4aee3cb74347c22 /sys/kern/kern_resource.c | |
parent | 4577a7a206bbe5c28d07b0517c8b07b0ee1df2ed (diff) | |
download | FreeBSD-src-259d62f4d89d01ef3c3cfece16aaf8c1cc802cd6.zip FreeBSD-src-259d62f4d89d01ef3c3cfece16aaf8c1cc802cd6.tar.gz |
use a oppurtunistic locking strategy with the uidinfo structures to avoid
locking the global hash on each uifree()
make struct uidinfo only visible to the kernel
make uihold() a function rather than a macro to reduce bloat
swap the order of a spl/mutex to maintain consistancy
Diffstat (limited to 'sys/kern/kern_resource.c')
-rw-r--r-- | sys/kern/kern_resource.c | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 0dee361..24cecf1 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -51,6 +51,7 @@ #include <sys/malloc.h> #include <sys/proc.h> #include <sys/time.h> +#include <sys/mutex.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -728,16 +729,68 @@ uifind(uid) } /* + * place another refcount on a uidinfo struct + */ +void +uihold(uip) +struct uidinfo *uip; +{ + + mtx_enter(&uip->ui_mtx, MTX_DEF); + uip->ui_ref++; + mtx_exit(&uip->ui_mtx, MTX_DEF); +} + +/* * subtract one from the refcount in the struct uidinfo, if 0 free it + * since uidinfo structs have a long lifetime we use a + * opportunistic refcounting scheme to avoid locking the lookup hash + * for each release. + * + * if the refcount hits 0 we need to free the structure + * which means we need to lock the hash. + * optimal case: + * After locking the struct and lowering the refcount, we find + * that we don't need to free, simply unlock and return + * suboptimal case: + * refcount lowering results in need to free, bump the count + * back up, loose the lock and aquire the locks in the proper + * order to try again. */ void uifree(uip) struct uidinfo *uip; { + /* + * try for optimal, recucing the refcount doesn't make us free it. + */ + mtx_enter(&uip->ui_mtx, MTX_DEF); + if (--uip->ui_ref != 0) { + mtx_exit(&uip->ui_mtx, MTX_DEF); + return; + } + /* + * ok, we need to free, before we release the mutex to get + * the lock ordering correct we need to + * backout our change to the refcount so that no one else + * races to free it. + */ + uip->ui_ref++; + mtx_exit(&uip->ui_mtx, MTX_DEF); + + /* get the locks in order */ mtx_enter(&uihashtbl_mtx, MTX_DEF); mtx_enter(&uip->ui_mtx, MTX_DEF); + /* + * it's possible that someone has referenced it after we dropped the + * initial lock, if so it's thier responsiblity to free it, but + * we still must remove one from the count because we backed out + * our change above. + */ if (--uip->ui_ref == 0) { + LIST_REMOVE(uip, ui_hash); + mtx_exit(&uihashtbl_mtx, MTX_DEF); if (uip->ui_sbsize != 0) /* XXX no %qd in kernel. Truncate. */ printf("freeing uidinfo: uid = %d, sbsize = %ld\n", @@ -745,14 +798,12 @@ uifree(uip) if (uip->ui_proccnt != 0) printf("freeing uidinfo: uid = %d, proccnt = %ld\n", uip->ui_uid, uip->ui_proccnt); - LIST_REMOVE(uip, ui_hash); - mtx_exit(&uihashtbl_mtx, MTX_DEF); mtx_destroy(&uip->ui_mtx); FREE(uip, M_UIDINFO); return; } - mtx_exit(&uip->ui_mtx, MTX_DEF); mtx_exit(&uihashtbl_mtx, MTX_DEF); + mtx_exit(&uip->ui_mtx, MTX_DEF); return; } @@ -793,8 +844,8 @@ chgsbsize(uip, hiwat, to, max) rlim_t new; int s; - mtx_enter(&uip->ui_mtx, MTX_DEF); s = splnet(); + mtx_enter(&uip->ui_mtx, MTX_DEF); new = uip->ui_sbsize + to - *hiwat; /* don't allow them to exceed max, but allow subtraction */ if (to > *hiwat && new > max) { |