From fe53724a0f9a9f079a03567634311f70202b6152 Mon Sep 17 00:00:00 2001 From: alfred Date: Sun, 26 Nov 2000 12:08:17 +0000 Subject: Make uidinfo subsystem mpsafe use a mutex lock when looking up/deleting entries on the hashlist use a mutex lock on each uidinfo when updating fields make uifree() a void function rather than 'int' since no one cares allocate uidinfo structs with the M_ZERO flag and don't explicitly initialize them Assisted by: eivind, jhb, jakeb --- sys/kern/kern_resource.c | 67 ++++++++++++++++++++++++++++++++---------------- sys/sys/resourcevar.h | 12 +++++++-- 2 files changed, 55 insertions(+), 24 deletions(-) (limited to 'sys') diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index f37d49d..0dee361 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -64,6 +64,7 @@ int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp)); static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures"); #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) +static struct mtx uihashtbl_mtx; static LIST_HEAD(uihashhead, uidinfo) *uihashtbl; static u_long uihash; /* size of hash table - 1 */ @@ -663,9 +664,15 @@ limcopy(lim) void uihashinit() { + uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash); + mtx_init(&uihashtbl_mtx, "uidinfo hash", MTX_DEF); } +/* + * lookup a uidinfo struct for the parameter uid. + * uihashtbl_mtx must be locked. + */ static struct uidinfo * uilookup(uid) uid_t uid; @@ -673,6 +680,7 @@ uilookup(uid) struct uihashhead *uipp; struct uidinfo *uip; + mtx_assert(&uihashtbl_mtx, MA_OWNED); uipp = UIHASH(uid); LIST_FOREACH(uip, uipp, ui_hash) if (uip->ui_uid == uid) @@ -681,51 +689,54 @@ uilookup(uid) return (uip); } +/* + * Create a uidinfo struct for the parameter uid. + * uihashtbl_mtx must be locked. + */ static struct uidinfo * uicreate(uid) uid_t uid; { - struct uidinfo *uip, *norace; + struct uidinfo *uip; - MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT); - if (uip == NULL) { - MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK); - /* - * if we M_WAITOK we must look afterwards or risk - * redundant entries - */ - norace = uilookup(uid); - if (norace != NULL) { - FREE(uip, M_UIDINFO); - return (norace); - } - } + mtx_assert(&uihashtbl_mtx, MA_OWNED); + MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK|M_ZERO); LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash); uip->ui_uid = uid; - uip->ui_proccnt = 0; - uip->ui_sbsize = 0; - uip->ui_ref = 0; + mtx_init(&uip->ui_mtx, "uidinfo struct", MTX_DEF); return (uip); } +/* + * find or allocate a struct uidinfo for a particular uid + * increases refcount on uidinfo struct returned. + * uifree() should be called on a struct uidinfo when released. + */ struct uidinfo * uifind(uid) uid_t uid; { struct uidinfo *uip; + mtx_enter(&uihashtbl_mtx, MTX_DEF); uip = uilookup(uid); if (uip == NULL) uip = uicreate(uid); - uip->ui_ref++; + uihold(uip); + mtx_exit(&uihashtbl_mtx, MTX_DEF); return (uip); } -int +/* + * subtract one from the refcount in the struct uidinfo, if 0 free it + */ +void uifree(uip) struct uidinfo *uip; { + mtx_enter(&uihashtbl_mtx, MTX_DEF); + mtx_enter(&uip->ui_mtx, MTX_DEF); if (--uip->ui_ref == 0) { if (uip->ui_sbsize != 0) /* XXX no %qd in kernel. Truncate. */ @@ -735,10 +746,14 @@ uifree(uip) 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 (1); + return; } - return (0); + mtx_exit(&uip->ui_mtx, MTX_DEF); + mtx_exit(&uihashtbl_mtx, MTX_DEF); + return; } /* @@ -751,12 +766,17 @@ chgproccnt(uip, diff, max) int diff; int max; { + + mtx_enter(&uip->ui_mtx, MTX_DEF); /* don't allow them to exceed max, but allow subtraction */ - if (diff > 0 && uip->ui_proccnt + diff > max && max != 0) + if (diff > 0 && uip->ui_proccnt + diff > max && max != 0) { + mtx_exit(&uip->ui_mtx, MTX_DEF); return (0); + } uip->ui_proccnt += diff; if (uip->ui_proccnt < 0) printf("negative proccnt for uid = %d\n", uip->ui_uid); + mtx_exit(&uip->ui_mtx, MTX_DEF); return (1); } @@ -773,11 +793,13 @@ chgsbsize(uip, hiwat, to, max) rlim_t new; int s; + mtx_enter(&uip->ui_mtx, MTX_DEF); s = splnet(); new = uip->ui_sbsize + to - *hiwat; /* don't allow them to exceed max, but allow subtraction */ if (to > *hiwat && new > max) { splx(s); + mtx_exit(&uip->ui_mtx, MTX_DEF); return (0); } uip->ui_sbsize = new; @@ -785,5 +807,6 @@ chgsbsize(uip, hiwat, to, max) if (uip->ui_sbsize < 0) printf("negative sbsize for uid = %d\n", uip->ui_uid); splx(s); + mtx_exit(&uip->ui_mtx, MTX_DEF); return (1); } diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index 8931f74..d093543 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -39,6 +39,7 @@ #include #include +#include /* XXX */ /* * Kernel per-process accounting / statistics @@ -90,10 +91,17 @@ struct uidinfo { long ui_proccnt; /* number of processes */ uid_t ui_uid; /* uid */ u_short ui_ref; /* reference count */ + struct mtx ui_mtx; /* protect counts */ }; #ifdef _KERNEL -#define uihold(uip) (uip)->ui_ref++ +#define uihold(uip) \ + do { \ + mtx_enter(&(uip)->ui_mtx, MTX_DEF); \ + (uip)->ui_ref++; \ + mtx_exit(&(uip)->ui_mtx, MTX_DEF); \ + } while(0) + struct proc; void addupc_intr __P((struct proc *p, u_long pc, u_int ticks)); @@ -110,7 +118,7 @@ void ruadd __P((struct rusage *ru, struct rusage *ru2)); int suswintr __P((void *base, int word)); struct uidinfo *uifind __P((uid_t uid)); -int uifree __P((struct uidinfo *uip)); +void uifree __P((struct uidinfo *uip)); void uihashinit __P((void)); #endif -- cgit v1.1