summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/os/system-maps/cached-gid-groupname.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:33:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:34:10 +0000
commit83ba6762cc43d9db581b979bb5e3445669e46cc2 (patch)
tree2e69833b43f791ed253a7a20318b767ebe56cdb8 /src/libnetdata/os/system-maps/cached-gid-groupname.c
parentReleasing debian version 1.47.5-1. (diff)
downloadnetdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.tar.xz
netdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.zip
Merging upstream version 2.0.3+dfsg (Closes: #923993, #1042533, #1045145).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libnetdata/os/system-maps/cached-gid-groupname.c')
-rw-r--r--src/libnetdata/os/system-maps/cached-gid-groupname.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/libnetdata/os/system-maps/cached-gid-groupname.c b/src/libnetdata/os/system-maps/cached-gid-groupname.c
new file mode 100644
index 000000000..3fabe94a2
--- /dev/null
+++ b/src/libnetdata/os/system-maps/cached-gid-groupname.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "cached-gid-groupname.h"
+
+// --------------------------------------------------------------------------------------------------------------------
+// hashtable for caching gid to groupname mappings
+// key is the gid, value is groupname (STRING)
+
+#define SIMPLE_HASHTABLE_KEY_TYPE gid_t
+#define SIMPLE_HASHTABLE_VALUE_TYPE CACHED_GROUPNAME
+#define SIMPLE_HASHTABLE_VALUE2KEY_FUNCTION cached_groupname_to_gid_ptr
+#define SIMPLE_HASHTABLE_COMPARE_KEYS_FUNCTION compar_gid_ptr
+#define SIMPLE_HASHTABLE_NAME _GROUPNAMES_CACHE
+#include "libnetdata/simple_hashtable/simple_hashtable.h"
+
+static struct {
+ bool initialized;
+ SPINLOCK spinlock;
+ SIMPLE_HASHTABLE_GROUPNAMES_CACHE ht;
+} group_cache = {
+ .initialized = false,
+ .spinlock = NETDATA_SPINLOCK_INITIALIZER,
+ .ht = { 0 },
+};
+
+static gid_t *cached_groupname_to_gid_ptr(CACHED_GROUPNAME *cu) {
+ return &cu->gid;
+}
+
+static bool compar_gid_ptr(gid_t *a, gid_t *b) {
+ return *a == *b;
+}
+
+void cached_groupname_populate_by_gid(gid_t gid, const char *groupname, uint32_t version) {
+ internal_fatal(!group_cache.initialized, "system-users cache needs to be initialized");
+ if(!groupname || !*groupname) return;
+
+ spinlock_lock(&group_cache.spinlock);
+
+ XXH64_hash_t hash = XXH3_64bits(&gid, sizeof(gid));
+ SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_get_slot_GROUPNAMES_CACHE(&group_cache.ht, hash, &gid, true);
+ CACHED_GROUPNAME *cg = SIMPLE_HASHTABLE_SLOT_DATA(sl);
+ if(!cg || (cg->version && version > cg->version)) {
+ internal_fatal(cg && cg->gid != gid, "invalid gid matched from cache");
+
+ if(cg)
+ string_freez(cg->groupname);
+ else
+ cg = callocz(1, sizeof(*cg));
+
+ cg->version = version;
+ cg->gid = gid;
+ cg->groupname = string_strdupz(groupname);
+ simple_hashtable_set_slot_GROUPNAMES_CACHE(&group_cache.ht, sl, hash, cg);
+ }
+
+ spinlock_unlock(&group_cache.spinlock);
+}
+
+CACHED_GROUPNAME cached_groupname_get_by_gid(gid_t gid) {
+ internal_fatal(!group_cache.initialized, "system-users cache needs to be initialized");
+
+ spinlock_lock(&group_cache.spinlock);
+
+ XXH64_hash_t hash = XXH3_64bits(&gid, sizeof(gid));
+ SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_get_slot_GROUPNAMES_CACHE(&group_cache.ht, hash, &gid, true);
+ CACHED_GROUPNAME *cg = SIMPLE_HASHTABLE_SLOT_DATA(sl);
+ if(!cg) {
+ cg = callocz(1, sizeof(*cg));
+
+ static char tmp[1024]; // we are inside a global spinlock - it is ok to be static
+ struct group gr, *result = NULL;
+
+ if (getgrgid_r(gid, &gr, tmp, sizeof(tmp), &result) != 0 || !result || !gr.gr_name || !(*gr.gr_name)) {
+ char name[UINT64_MAX_LENGTH];
+ print_uint64(name, gid);
+ cg->groupname = string_strdupz(name);
+ }
+ else
+ cg->groupname = string_strdupz(gr.gr_name);
+
+ cg->gid = gid;
+ simple_hashtable_set_slot_GROUPNAMES_CACHE(&group_cache.ht, sl, hash, cg);
+ }
+
+ internal_fatal(cg->gid != gid, "invalid gid matched from cache");
+
+ CACHED_GROUPNAME rc = {
+ .version = cg->version,
+ .gid = cg->gid,
+ .groupname = string_dup(cg->groupname),
+ };
+
+ spinlock_unlock(&group_cache.spinlock);
+ return rc;
+}
+
+void cached_groupname_release(CACHED_GROUPNAME cg) {
+ string_freez(cg.groupname);
+}
+
+void cached_groupnames_init(void) {
+ if(group_cache.initialized) return;
+ group_cache.initialized = true;
+
+ spinlock_init(&group_cache.spinlock);
+ simple_hashtable_init_GROUPNAMES_CACHE(&group_cache.ht, 100);
+}
+
+void cached_groupnames_destroy(void) {
+ if(!group_cache.initialized) return;
+
+ spinlock_lock(&group_cache.spinlock);
+
+ for(SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_first_read_only_GROUPNAMES_CACHE(&group_cache.ht);
+ sl;
+ sl = simple_hashtable_next_read_only_GROUPNAMES_CACHE(&group_cache.ht, sl)) {
+ CACHED_GROUPNAME *u = SIMPLE_HASHTABLE_SLOT_DATA(sl);
+ if(u) {
+ string_freez(u->groupname);
+ freez(u);
+ // simple_hashtable_del_slot_GROUPNAMES_CACHE(&uc.ht, sl);
+ }
+ }
+
+ simple_hashtable_destroy_GROUPNAMES_CACHE(&group_cache.ht);
+ group_cache.initialized = false;
+
+ spinlock_unlock(&group_cache.spinlock);
+}
+
+void cached_groupnames_delete_old_versions(uint32_t version) {
+ if(!group_cache.initialized) return;
+
+ spinlock_lock(&group_cache.spinlock);
+
+ for(SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_first_read_only_GROUPNAMES_CACHE(&group_cache.ht);
+ sl;
+ sl = simple_hashtable_next_read_only_GROUPNAMES_CACHE(&group_cache.ht, sl)) {
+ CACHED_GROUPNAME *cg = SIMPLE_HASHTABLE_SLOT_DATA(sl);
+ if(cg && cg->version && cg->version < version) {
+ string_freez(cg->groupname);
+ freez(cg);
+ simple_hashtable_del_slot_GROUPNAMES_CACHE(&group_cache.ht, sl);
+ }
+ }
+
+ spinlock_unlock(&group_cache.spinlock);
+}