From: Shachar Sharon Date: Mon, 28 Apr 2025 09:05:25 +0000 (+0300) Subject: profile: dynamic per-share in-memory counters X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0733f232f49944fee8371b6db4adb949d59aa965;p=thirdparty%2Fsamba.git profile: dynamic per-share in-memory counters Mechanism to support per-share per-process run-time profiling counters. Use in-memory cache for storing run-time entries, using 'snum' as key. When storing in TDB file, uses unique key for each per-share profile entry. Signed-off-by: Shachar Sharon Signed-off-by: Avan Thakkar Reviewed-by: Volker Lendecke Reviewed-by: Anoop C S --- diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h index c8d2696884e..3aaa112a19d 100644 --- a/source3/include/smbprofile.h +++ b/source3/include/smbprofile.h @@ -485,6 +485,14 @@ struct profile_stats { DO_PROFILE_INC(authentication); \ DO_PROFILE_INC(authentication_failed); \ +struct profile_stats_persvc { + struct profile_stats stats; + int snum; + int refcnt; + bool active; + char dbkey[]; +}; + extern struct profile_stats *profile_p; struct smbprofile_global_state { @@ -503,6 +511,10 @@ struct smbprofile_global_state { struct { struct profile_stats global; } stats; + + struct { + struct profile_stats_persvc **tbl; + } persvc; }; extern struct smbprofile_global_state smbprofile_state; @@ -727,4 +739,32 @@ void set_profile_level(int level, const struct server_id *src); struct messaging_context; bool profile_setup(struct messaging_context *msg_ctx, bool rdonly); +/* Per-share profiling */ +#ifdef WITH_PROFILE + +void smbprofile_persvc_mkref(int snum, const char *svc, const char *remote); +void smbprofile_persvc_unref(int snum); +struct profile_stats *smbprofile_persvc_get(int snum); + +#else /* WITH_PROFILE */ + +static inline void smbprofile_persvc_mkref(int snum, + const char *svc, + const char *remote) +{ + return; +} + +static inline void smbprofile_persvc_unref(int snum) +{ + return; +} + +static inline struct profile_stats *smbprofile_persvc_get(int snum) +{ + return NULL; +} + +#endif /* WITH_PROFILE */ + #endif diff --git a/source3/profile/profile.c b/source3/profile/profile.c index d24a6382c92..f01fa999b05 100644 --- a/source3/profile/profile.c +++ b/source3/profile/profile.c @@ -25,6 +25,7 @@ #include "messages.h" #include "smbprofile.h" #include "lib/tdb_wrap/tdb_wrap.h" +#include "lib/util/util_tdb.h" #include #include "../lib/crypto/crypto.h" #include "source3/smbd/globals.h" @@ -33,6 +34,8 @@ #include #endif +static void smbprofile_persvc_dump(void); + struct profile_stats *profile_p; struct smbprofile_global_state smbprofile_state; @@ -281,6 +284,8 @@ void smbprofile_dump(struct smbd_server_connection *sconn) tdb_chainunlock(smbprofile_state.internal.db->tdb, key); ZERO_STRUCT(profile_p->values); + smbprofile_persvc_dump(); + return; } @@ -353,3 +358,185 @@ void smbprofile_collect(struct profile_stats *stats) profile_p->magic, stats); } + +/* Per-share profiling */ + +static bool smbprofile_persvc_grow(int snum) +{ + struct profile_stats_persvc **new_tbl = NULL; + const size_t cur_cap = talloc_array_length(smbprofile_state.persvc.tbl); + size_t new_cap = 0; + + if ((size_t)snum < cur_cap) { + return true; + } + + new_cap = (size_t)snum + 1; + new_tbl = talloc_realloc(NULL, + smbprofile_state.persvc.tbl, + struct profile_stats_persvc *, + new_cap); + + if (new_tbl == NULL) { + DBG_ERR("Failed to realloc persvc table for snum %d\n", snum); + return false; + } + + memset(&new_tbl[cur_cap], 0, (new_cap - cur_cap) * sizeof(*new_tbl)); + + smbprofile_state.persvc.tbl = new_tbl; + return true; +} + +static struct profile_stats_persvc *smbprofile_persvc_lookup(int snum) +{ + if (!smbprofile_active() || (snum < 0) || + (snum >= (int)talloc_array_length(smbprofile_state.persvc.tbl))) { + return NULL; + } + + return smbprofile_state.persvc.tbl[snum]; +} + +static struct profile_stats_persvc *smbprofile_persvc_insert(int snum, + const char *svc, + const char *remote) +{ + struct profile_stats_persvc *entry = NULL; + char *dbkey = NULL; + size_t len = 0; + bool ok; + + ok = smbprofile_persvc_grow(snum); + if (!ok) { + return NULL; + } + + dbkey = talloc_asprintf(talloc_tos(), + "%s:%d.%d[%s]", + svc, + (int)tevent_cached_getpid(), + snum, + remote); + if (dbkey == NULL) { + return NULL; + } + + len = strlen(dbkey); + entry = talloc_zero_size(NULL, sizeof(*entry) + len + 1); + if (entry == NULL) { + TALLOC_FREE(dbkey); + DBG_ERR("Failed to allocate entry for snum %d\n", snum); + return NULL; + } + + entry->snum = snum; + entry->refcnt = 0; + memcpy(entry->dbkey, dbkey, len); + TALLOC_FREE(dbkey); + + smbprofile_state.persvc.tbl[snum] = entry; + return entry; +} + +static void smbprofile_persvc_delete(struct profile_stats_persvc *entry) +{ + SMB_ASSERT(entry->snum >= 0); + SMB_ASSERT(smbprofile_state.persvc.tbl[entry->snum] == entry); + + smbprofile_state.persvc.tbl[entry->snum] = NULL; + TALLOC_FREE(entry); +} + +void smbprofile_persvc_mkref(int snum, const char *svc, const char *remote) +{ + struct profile_stats_persvc *persvc = NULL; + + if (!smbprofile_active() || (snum < 0) || (svc == NULL)) { + return; + } + + persvc = smbprofile_persvc_lookup(snum); + if (persvc == NULL) { + persvc = smbprofile_persvc_insert(snum, svc, remote); + } + + if (persvc != NULL) { + persvc->refcnt++; + persvc->active = true; + } +} + +void smbprofile_persvc_unref(int snum) +{ + struct profile_stats_persvc *persvc = NULL; + + persvc = smbprofile_persvc_lookup(snum); + if (persvc != NULL) { + persvc->refcnt--; + } +} + +struct profile_stats *smbprofile_persvc_get(int snum) +{ + struct profile_stats_persvc *persvc = NULL; + + if (!smbprofile_active() || (snum < 0)) { + return NULL; + } + + persvc = smbprofile_persvc_lookup(snum); + if (persvc == NULL) { + return NULL; + } + + persvc->active = true; + return &persvc->stats; +} + +static TDB_DATA tdb_keyof(struct profile_stats_persvc *persvc) +{ + return string_tdb_data(persvc->dbkey); +} + +static void smbprofile_persvc_store(struct profile_stats_persvc *persvc) +{ + TDB_DATA val = {.dptr = (uint8_t *)(&persvc->stats), + .dsize = sizeof(persvc->stats)}; + + tdb_store(smbprofile_state.internal.db->tdb, tdb_keyof(persvc), val, 0); +} + +static void smbprofile_persvc_clear(struct profile_stats_persvc *persvc) +{ + tdb_delete(smbprofile_state.internal.db->tdb, tdb_keyof(persvc)); + smbprofile_persvc_delete(persvc); +} + +static void smbprofile_persvc_dump(void) +{ + struct profile_stats_persvc *entry = NULL; + size_t i, cap; + + if (!smbprofile_active()) { + return; + } + + if (smbprofile_state.internal.db == NULL) { + return; + } + + cap = talloc_array_length(smbprofile_state.persvc.tbl); + for (i = 0; i < cap; ++i) { + entry = smbprofile_state.persvc.tbl[i]; + if (entry != NULL) { + if (entry->refcnt == 0) { + smbprofile_persvc_clear(entry); + } else if (entry->active) { + smbprofile_persvc_store(entry); + entry->active = false; + } + } + } +} +