This is a more extendable version than traditional hashinit(9). It allows
different kinds of slot headers with optional locks.
Implement traditional hashinit()/hashdestroy() on top of it.
Differential D55904
hash(9): introduce hashalloc()/hashfree() KPI Authored by glebius on Tue, Mar 17, 7:27 PM. Tags None Referenced Files
Details
This is a more extendable version than traditional hashinit(9). It allows Implement traditional hashinit()/hashdestroy() on top of it.
Diff Detail
Event TimelineComment Actions Do you need to validate the enum value is know? Can the lock and list types be automatically detected with _Generic somehow? Comment Actions Do you mean if somebody passes a numeric instead of one of enum values? I think our compiler flags will forbid that.
I don't see a way to use _Generic facing outside of the KPI. It might be possible to make some use of it internally, I'll look into that. Comment Actions I'm thinking default: would make sure.
Sure.
Comment Actions I've had a quick look at making pf use this, and I have a minor annoyance. Pf allocates a state table per vnet, and might have different hash table sizes in different vnets. All other settings (name, lock type, ..) are the same, but the size may be different, so that leads to this: diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 87ed701f66a7..0c061ac22c37 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -40,6 +40,7 @@ #include <sys/cpuset.h> #include <sys/epoch.h> #include <sys/malloc.h> +#include <sys/hash.h> #include <sys/nv.h> #include <sys/refcount.h> #include <sys/sdt.h> @@ -2632,6 +2633,14 @@ struct pf_keyhash { struct mtx lock; }; +static const struct hashalloc_args PF_KEYHASH_ARGS = { + .mflags = M_NOWAIT | M_ZERO, + .mtype = M_PFHASH, + .head = HASH_HEAD_LIST, + .lock = HASH_LOCK_MTX, + .lname = "bucket of pf keys", +}; struct pf_idhash { LIST_HEAD(, pf_kstate) states; struct mtx lock; diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 90342f045763..4ee6ba3140cd 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -1455,20 +1455,22 @@ pf_initialize(void) sizeof(struct pf_state_key), pf_state_key_ctor, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - V_pf_keyhash = mallocarray(V_pf_hashsize, sizeof(struct pf_keyhash), - M_PFHASH, M_NOWAIT | M_ZERO); + struct hashalloc_args keyhash_args = PF_KEYHASH_ARGS; + keyhash_args.size = V_pf_hashsize; + V_pf_keyhash = hashalloc(&keyhash_args); V_pf_idhash = mallocarray(V_pf_hashsize, sizeof(struct pf_idhash), M_PFHASH, M_NOWAIT | M_ZERO); if (V_pf_keyhash == NULL || V_pf_idhash == NULL) { printf("pf: Unable to allocate memory for " "state_hashsize %lu.\n", V_pf_hashsize); - free(V_pf_keyhash, M_PFHASH); + hashfree(V_pf_keyhash, &keyhash_args); free(V_pf_idhash, M_PFHASH); It'd be cleaner if the size was a separate argument, then we could use V_pf_hashsize directly, and not bother with copies of the const PF_KEYHASH_ARGS. Comment Actions Thanks for feedback, Kristof! I don't think this is a common pattern. I think the cleanest way for pf would be to a wrapper function that has hashalloc_args on its stack and has size argument. It shall also return the allocated size. This will not spend data on bss for hashalloc_args. Lines of code wise it should be just 4 lines extra: 3 for the function header one for }. Also in case of pf the wrapper can be used to allocate/init different hash tables, if it also takes an argument for the lock name. Comment Actions Looking into that for a second time, I do not see a problem at all. When you enter pf_initialize() the V_pf_hashsize is already set. So just put the hashalloc_args on the stack of pf_initialize() and that's it. Comment Actions
Comment Actions Ok, this is how it looks like for pf(4): https://reviews.freebsd.org/D56113 Running tests now, good so far.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||