--- /dev/null
+#ifndef CEPH_SAN_LOGGER_H
+#define CEPH_SAN_LOGGER_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/ceph/ceph_san_batch.h>
+#include <linux/ceph/ceph_san_pagefrag.h>
+
+/* Maximum length of a log entry buffer */
+#define CEPH_SAN_LOG_MAX_LEN 256
+
+/* Log entry structure */
+struct ceph_san_log_entry {
+ u64 ts; /* Timestamp (jiffies) */
+ unsigned int line; /* Line number */
+ unsigned int len; /* Length of the message */
+ const char *file; /* Source file */
+ char buffer[0]; /* Flexible array for inline buffer */
+};
+
+/* TLS context structure */
+struct ceph_san_tls_ctx {
+ char comm[TASK_COMM_LEN]; /* Task command name */
+ pid_t pid; /* Process ID */
+ struct task_struct *task; /* Pointer to task struct */
+ struct cephsan_pagefrag pf; /* Pagefrag for this context */
+ struct list_head list; /* For global list of contexts */
+};
+
+/* Global logger state */
+struct ceph_san_logger {
+ struct list_head contexts; /* List of all TLS contexts */
+ spinlock_t lock; /* Protects contexts list */
+ struct ceph_san_batch alloc_batch; /* Batch for allocating new entries */
+ struct ceph_san_batch log_batch; /* Batch for storing log entries */
+};
+
+/* Initialize the logging system */
+int ceph_san_logger_init(void);
+
+/* Clean up the logging system */
+void ceph_san_logger_cleanup(void);
+
+/* Log a message */
+void ceph_san_log(const char *file, unsigned int line, const char *fmt, ...);
+
+/* Get current TLS context, creating if necessary */
+struct ceph_san_tls_ctx *ceph_san_get_tls_ctx(void);
+
+/* Helper macro for logging */
+#define CEPH_SAN_LOG(fmt, ...) \
+ ceph_san_log(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
+
+#endif /* CEPH_SAN_LOGGER_H */
\ No newline at end of file
--- /dev/null
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ceph/ceph_san_logger.h>
+
+/* Global logger instance */
+static struct ceph_san_logger g_logger;
+
+static void *alloc_tls_ctx(void)
+{
+ struct ceph_san_tls_ctx *ctx;
+ ctx = kmem_cache_alloc(g_logger.alloc_batch.magazine_cache, GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ /* Initialize pagefrag */
+ memset(&ctx->pf, 0, sizeof(ctx->pf));
+ if (cephsan_pagefrag_init(&ctx->pf)) {
+ kmem_cache_free(g_logger.alloc_batch.magazine_cache, ctx);
+ return NULL;
+ }
+ return ctx;
+}
+
+static void free_tls_ctx(void *ptr)
+{
+ struct ceph_san_tls_ctx *ctx = ptr;
+ cephsan_pagefrag_deinit(&ctx->pf);
+ kmem_cache_free(g_logger.alloc_batch.magazine_cache, ctx);
+}
+
+/* Release function for TLS storage */
+static void ceph_san_tls_release(void *ptr)
+{
+ struct ceph_san_tls_ctx *ctx = ptr;
+
+ if (!ctx)
+ return;
+
+ /* Add context to log batch */
+ ceph_san_batch_put(&g_logger.log_batch, ctx);
+
+ current->tls.state = NULL;
+}
+
+/**
+ * ceph_san_get_tls_ctx - Get or create TLS context for current task
+ *
+ * Returns pointer to TLS context or NULL on error
+ */
+struct ceph_san_tls_ctx *ceph_san_get_tls_ctx(void)
+{
+ struct ceph_san_tls_ctx *ctx;
+
+ ctx = current->tls.state;
+ if (ctx)
+ return ctx;
+
+ /* Try to get context from batch first */
+ ctx = ceph_san_batch_get(&g_logger.alloc_batch);
+ if (!ctx) {
+ /* Create new context if batch is empty */
+ ctx = alloc_tls_ctx();
+ if (!ctx)
+ return NULL;
+ /* Add to global list */
+ spin_lock(&g_logger.lock);
+ list_add(&ctx->list, &g_logger.contexts);
+ spin_unlock(&g_logger.lock);
+ }
+
+ /* Set up TLS */
+ current->tls.state = ctx;
+ current->tls.release = ceph_san_tls_release;
+
+ return ctx;
+}
+EXPORT_SYMBOL(ceph_san_get_tls_ctx);
+
+/**
+ * ceph_san_log - Log a message
+ * @file: Source file name
+ * @line: Line number
+ * @fmt: Format string
+ *
+ * Logs a message to the current TLS context's log buffer
+ */
+void ceph_san_log(const char *file, unsigned int line, const char *fmt, ...)
+{
+ /* Format the message into local buffer first */
+ char buf[256];
+ struct ceph_san_tls_ctx *ctx;
+ struct ceph_san_log_entry *entry;
+ va_list args;
+ int len;
+
+ ctx = ceph_san_get_tls_ctx();
+ if (!ctx)
+ return;
+
+ va_start(args, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ /* Allocate entry from pagefrag */
+ u64 alloc = cephsan_pagefrag_alloc(&ctx->pf, sizeof(*entry) + len + 1);
+ if (!alloc)
+ return;
+ entry = cephsan_pagefrag_get_ptr(&ctx->pf, alloc);
+
+ /* Copy to entry buffer */
+ memcpy(entry->buffer, buf, len + 1);
+ entry->buffer[len] = '\0';
+
+ /* Fill in entry details */
+ entry->ts = jiffies;
+ entry->line = line;
+ entry->file = file;
+ entry->len = len;
+}
+EXPORT_SYMBOL(ceph_san_log);
+
+/**
+ * ceph_san_logger_init - Initialize the logging system
+ *
+ * Returns 0 on success, negative error code on failure
+ */
+int ceph_san_logger_init(void)
+{
+ int ret;
+
+ /* Initialize global state */
+ INIT_LIST_HEAD(&g_logger.contexts);
+ spin_lock_init(&g_logger.lock);
+
+ /* Initialize allocation batch */
+ ret = ceph_san_batch_init(&g_logger.alloc_batch,
+ alloc_tls_ctx,
+ free_tls_ctx);
+ if (ret)
+ return ret;
+
+ /* Initialize log batch */
+ ret = ceph_san_batch_init(&g_logger.log_batch,
+ NULL,
+ NULL);
+ if (ret)
+ goto cleanup_alloc;
+
+ return 0;
+
+cleanup_alloc:
+ ceph_san_batch_cleanup(&g_logger.alloc_batch);
+ return ret;
+}
+EXPORT_SYMBOL(ceph_san_logger_init);
+
+/**
+ * ceph_san_logger_cleanup - Clean up the logging system
+ */
+void ceph_san_logger_cleanup(void)
+{
+ struct ceph_san_tls_ctx *ctx, *tmp;
+
+ /* Clean up all TLS contexts */
+ spin_lock(&g_logger.lock);
+ list_for_each_entry_safe(ctx, tmp, &g_logger.contexts, list) {
+ list_del(&ctx->list);
+ cephsan_pagefrag_deinit(&ctx->pf);
+ kfree(ctx);
+ }
+ spin_unlock(&g_logger.lock);
+
+ /* Clean up batches */
+ ceph_san_batch_cleanup(&g_logger.alloc_batch);
+ ceph_san_batch_cleanup(&g_logger.log_batch);
+}
+EXPORT_SYMBOL(ceph_san_logger_cleanup);
\ No newline at end of file