]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
profile: dynamic per-share in-memory counters
authorShachar Sharon <ssharon@redhat.com>
Mon, 28 Apr 2025 09:05:25 +0000 (12:05 +0300)
committerAnoop C S <anoopcs@samba.org>
Mon, 23 Jun 2025 13:04:31 +0000 (13:04 +0000)
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 <ssharon@redhat.com>
Signed-off-by: Avan Thakkar <athakkar@redhat.com>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Anoop C S <anoopcs@samba.org>
source3/include/smbprofile.h
source3/profile/profile.c

index c8d2696884e462634d88329c30733700d992aacc..3aaa112a19d226bdce4abc906fb7c25456883717 100644 (file)
@@ -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
index d24a6382c920b972022ad6b1b3a74eb12095b874..f01fa999b054ca7ec17248cf4dba1d61d8459848 100644 (file)
@@ -25,6 +25,7 @@
 #include "messages.h"
 #include "smbprofile.h"
 #include "lib/tdb_wrap/tdb_wrap.h"
+#include "lib/util/util_tdb.h"
 #include <tevent.h>
 #include "../lib/crypto/crypto.h"
 #include "source3/smbd/globals.h"
@@ -33,6 +34,8 @@
 #include <sys/resource.h>
 #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;
+                       }
+               }
+       }
+}
+