#include "mds_client.h"
#include "metric.h"
+/* Export the g_registrations array for debugfs code */
+extern struct ceph_san_log_registration g_registrations[];
+
static int mdsmap_show(struct seq_file *s, void *p)
{
int i;
return 0;
}
-/* @buffer: The buffer to store the formatted date and time string.
- * @buffer_len: The length of the buffer.
- *
- * Returns: The number of characters written to the buffer, or a negative error code.
- */
-static int jiffies_to_formatted_time(unsigned long jiffies_value, char *buffer, size_t buffer_len)
+/* Simple wrapper to format jiffies to a human-readable timestamp */
+int jiffies_to_formatted_time(unsigned long jiffies_value, char *buffer, size_t buffer_len)
{
- unsigned long seconds;
+ struct timespec64 ts;
struct tm tm_time;
- // Convert jiffies to seconds
- seconds = jiffies_value / HZ;
-
- // Manually convert seconds to struct tm
- // This is a simplified conversion without timezone handling
- tm_time.tm_sec = seconds % 60;
- seconds /= 60;
- tm_time.tm_min = seconds % 60;
- seconds /= 60;
- tm_time.tm_hour = seconds % 24;
- seconds /= 24;
+ jiffies_to_timespec64(jiffies_value, &ts);
+ time64_to_tm(ts.tv_sec, 0, &tm_time);
- // Simplified date calculation (assuming Unix epoch start at 1970-01-01)
- tm_time.tm_mday = (seconds % 365) + 1; // Simplified day of month
- tm_time.tm_mon = (seconds / 365) % 12; // Simplified month
- tm_time.tm_year = (seconds / 365 / 12) + 70; // Simplified year since 1970
-
- // Format the time into the buffer
return snprintf(buffer, buffer_len, "%04ld-%02d-%02d %02d:%02d:%02d",
tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
static int ceph_san_tls_show(struct seq_file *s, void *p)
{
- struct ceph_san_tls_ctx *ctx;
- struct ceph_san_log_iter iter;
- struct ceph_san_log_entry *entry;
-
- /* Lock the logger to safely traverse the contexts list */
- spin_lock(&g_logger.lock);
-
- list_for_each_entry(ctx, &g_logger.contexts, list) {
-
- /* Initialize iterator for this context's pagefrag */
- ceph_san_log_iter_init(&iter, &ctx->pf);
- int pid = ctx->pid;
- char *comm = ctx->comm;
-
- /* Lock the pagefrag before accessing entries */
- spin_lock_bh(&ctx->pf.lock);
-
- /* Iterate through all log entries in this context */
- while ((entry = ceph_san_log_iter_next(&iter)) != NULL) {
- if (entry->debug_poison != CEPH_SAN_LOG_ENTRY_POISON) {
- seq_puts(s, " [Corrupted Entry]\n");
- continue;
- }
-
- char datetime_str[32];
- jiffies_to_formatted_time(entry->ts, datetime_str, sizeof(datetime_str));
-
- seq_printf(s, "[%d][%s][%s]:%s:%s:%u: %.*s",
- pid,
- comm,
- datetime_str,
- entry->file,
- entry->func,
- entry->line,
- entry->len,
- entry->buffer);
- }
-
- /* Unlock the pagefrag after we're done with this context */
- spin_unlock_bh(&ctx->pf.lock);
- }
-
- spin_unlock(&g_logger.lock);
- return 0;
+ struct ceph_san_tls_ctx *ctx;
+ struct ceph_san_log_iter iter;
+ struct ceph_san_log_entry *entry;
+ struct ceph_san_log_registration *reg;
+ char time_str[32];
+ char cmdline[TASK_COMM_LEN];
+ int count = 0;
+
+ ctx = ceph_san_get_tls_ctx();
+ if (!ctx)
+ return -ENOENT;
+
+ get_task_comm(cmdline, current);
+
+ seq_printf(s, "Thread: %s [%d]\n", cmdline, task_pid_nr(current));
+ seq_printf(s, "---------------------------------------------------------\n");
+
+ ceph_san_log_iter_init(&iter, &ctx->pf);
+
+ while ((entry = ceph_san_log_iter_next(&iter)) != NULL) {
+ if (entry->debug_poison != CEPH_SAN_LOG_ENTRY_POISON) {
+ seq_printf(s, "ERROR: Corrupted log entry at offset %llu\n", iter.prev_offset);
+ continue;
+ }
+
+ /* Get registration for this entry */
+ if (entry->reg_id >= CEPH_SAN_LOG_MAX_REGISTRATIONS) {
+ seq_printf(s, "ERROR: Invalid registration ID %u\n", entry->reg_id);
+ continue;
+ }
+
+ reg = &g_registrations[entry->reg_id];
+
+ /* Format timestamp */
+ jiffies_to_formatted_time(entry->ts, time_str, sizeof(time_str));
+
+ /* Output the log entry with all registration info */
+ seq_printf(s, "[%s] %s:%s:%u - %s\n",
+ time_str,
+ reg->file, reg->func, reg->line,
+ entry->buffer);
+ count++;
+ }
+
+ if (count == 0)
+ seq_printf(s, "No log entries found\n");
+ else
+ seq_printf(s, "----- End of log: %d entries -----\n", count);
+
+ return 0;
}
static int print_task_cgroup(struct task_struct *task, char *cgroup_path, size_t size)
#include <linux/spinlock.h>
#include <linux/ceph/ceph_san_batch.h>
#include <linux/ceph/ceph_san_pagefrag.h>
+#include <linux/stdarg.h>
/* Maximum length of a log entry buffer */
#define CEPH_SAN_LOG_MAX_LEN 256
#define CEPH_SAN_LOG_ENTRY_POISON 0xDEADBEEF
+#define CEPH_SAN_LOG_MAX_REGISTRATIONS 1024
+
+/* Helper function to format jiffies into human readable time */
+int jiffies_to_formatted_time(unsigned long jiffies_value, char *buffer, size_t buffer_len);
+
+/* Get TLS context for current task */
+struct ceph_san_tls_ctx *ceph_san_get_tls_ctx(void);
+
+/* Log a message with file, function, and line information */
+void ceph_san_log(const char *file, const char *func, unsigned int line, const char *fmt, ...);
+
+/* Log registration structure */
+struct ceph_san_log_registration {
+ const char *file; /* Source file - static pointer */
+ const char *func; /* Source function - static pointer */
+ unsigned int line; /* Line number */
+ const char *fmt; /* Format string - static pointer */
+ unsigned int id; /* Unique registration ID */
+ size_t params_size; /* Size of all parameters when compacted */
+};
+
/* Log entry structure */
struct ceph_san_log_entry {
u64 debug_poison; /* Debug poison value */
u64 ts; /* Timestamp (jiffies) */
- unsigned int line; /* Line number */
+ unsigned int reg_id; /* Registration ID */
unsigned int len; /* Length of the message */
- const char *file; /* Source file */
- const char *func; /* Source function */
- char *buffer; /* Flexible array for inline buffer */
+ char *buffer; /* Flexible array for inline buffer */
};
/* TLS context structure */
/* Clean up the logging system */
void ceph_san_logger_cleanup(void);
-/* Log a message */
-void ceph_san_log(const char *file, const char *func, unsigned int line, const char *fmt, ...);
+/* Register a log location and get unique ID */
+unsigned int ceph_san_log_register(const char *file, const char *func,
+ unsigned int line, const char *fmt);
-/* Get current TLS context, creating if necessary */
-struct ceph_san_tls_ctx *ceph_san_get_tls_ctx(void);
+/* Log a message using registration ID */
+void ceph_san_log_with_id(unsigned int reg_id, const char *fmt, ...);
/* Helper macro for logging */
#define CEPH_SAN_LOG(fmt, ...) \
- ceph_san_log(kbasename(__FILE__), __func__, __LINE__, fmt, ##__VA_ARGS__)
+ do { \
+ static unsigned int __log_id = 0; \
+ if (unlikely(!__log_id)) \
+ __log_id = ceph_san_log_register(kbasename(__FILE__), __func__, \
+ __LINE__, fmt); \
+ ceph_san_log_with_id(__log_id, fmt, ##__VA_ARGS__); \
+ } while (0)
/* Global logger instance */
extern struct ceph_san_logger g_logger;
+extern struct ceph_san_log_registration g_registrations[];
+
+extern void ceph_san_log_with_id_v(unsigned int reg_id, const char *fmt, va_list args);
#endif /* CEPH_SAN_LOGGER_H */
\ No newline at end of file
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _CEPH_SAN_PACKER_H
+#define _CEPH_SAN_PACKER_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+/*
+ * Elegant recursive packing macros
+ *
+ * These macros provide type-safe serialization and size calculation
+ * for arbitrary data with minimal recursion complexity.
+ */
+
+/* Special terminator value for recursion */
+#define _END _END_MARKER_
+
+/* SERIALIZATION MACROS - True recursion with direct pointer manipulation */
+
+#define SERIALIZE(buff, ...) _SERIALIZE(buff, ##__VA_ARGS__, _END)
+
+#define _SERIALIZE(buff, val, ...) \
+ do { \
+ typeof(val) *__ptr = (buff); \
+ *__ptr = (val); \
+ _SERIALIZE_CHECK((typeof(val) *)__ptr + 1, ##__VA_ARGS__); \
+ } while(0)
+
+#define _SERIALIZE_CHECK(buff, first, ...) \
+ _SERIALIZE_IF_NEMPTY(first)(buff, first, ##__VA_ARGS__)
+
+#define _SERIALIZE_IF_NEMPTY(first) \
+ _SERIALIZE_TEST(first, _END, _SERIALIZE_EMPTY, _SERIALIZE_RECURSE)
+
+#define _SERIALIZE_TEST(a, b, empty, recurse) \
+ _SERIALIZE_TEST_(a, b) (empty, recurse)
+
+#define _SERIALIZE_TEST_(a, b) \
+ _SERIALIZE_IS_ ## b
+
+#define _SERIALIZE_IS__END(empty, recurse) empty
+#define _SERIALIZE_IS__END_MARKER_(empty, recurse) empty
+#define _SERIALIZE_IS_default(empty, recurse) recurse
+
+#define _SERIALIZE_EMPTY(...)
+#define _SERIALIZE_RECURSE(buff, val, ...) \
+ _SERIALIZE(buff, val, ##__VA_ARGS__)
+
+/* SIZE CALCULATION MACROS - Elegant recursive calculation */
+
+#define CALC_SIZE(...) _CALC_SIZE(##__VA_ARGS__, _END)
+
+#define _CALC_SIZE(val, ...) \
+ _CALC_SIZE_CHECK(sizeof(typeof(val)), ##__VA_ARGS__)
+
+#define _CALC_SIZE_CHECK(current_size, first, ...) \
+ _CALC_SIZE_IF_NEMPTY(first)(current_size, first, ##__VA_ARGS__)
+
+#define _CALC_SIZE_IF_NEMPTY(first) \
+ _CALC_SIZE_TEST(first, _END, _CALC_SIZE_FINAL, _CALC_SIZE_CONTINUE)
+
+#define _CALC_SIZE_TEST(a, b, final, cont) \
+ _CALC_SIZE_TEST_(a, b) (final, cont)
+
+#define _CALC_SIZE_TEST_(a, b) \
+ _CALC_SIZE_IS_ ## b
+
+#define _CALC_SIZE_IS__END(final, cont) final
+#define _CALC_SIZE_IS__END_MARKER_(final, cont) final
+#define _CALC_SIZE_IS_default(final, cont) cont
+
+#define _CALC_SIZE_FINAL(size) (size)
+#define _CALC_SIZE_CONTINUE(size, val, ...) \
+ _CALC_SIZE_CHECK((size) + sizeof(typeof(val)), ##__VA_ARGS__)
+
+/* USAGE EXAMPLE:
+ *
+ * // Serialization
+ * int buffer[3];
+ * SERIALIZE(buffer, 1, 2, 3);
+ *
+ * // Size calculation
+ * size_t size = CALC_SIZE(int_val, u64_val, char_val);
+ *
+ */
+
+#endif /* _CEPH_SAN_PACKER_H */
\ No newline at end of file
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/seq_file.h>
#include <linux/ceph/ceph_san_logger.h>
#define CEPH_SAN_LOG_BATCH_MAX_FULL 128
struct ceph_san_logger g_logger;
EXPORT_SYMBOL(g_logger);
+/* Registration table */
+struct ceph_san_log_registration g_registrations[CEPH_SAN_LOG_MAX_REGISTRATIONS];
+EXPORT_SYMBOL(g_registrations);
+
+static unsigned int g_next_reg_id;
+static DEFINE_SPINLOCK(g_reg_lock);
+
static void *alloc_tls_ctx(void)
{
struct ceph_san_tls_ctx *ctx;
EXPORT_SYMBOL(ceph_san_get_tls_ctx);
/**
- * ceph_san_log - Log a message
- * @file: Source file name
+ * ceph_san_log - Log a message with file/func/line registration
+ * @file: Source file name (static string)
+ * @func: Function name (static string)
* @line: Line number
- * @fmt: Format string
+ * @fmt: Format string (static string)
*
- * Logs a message to the current TLS context's log buffer
+ * Registers the location on first call and reuses registration ID on subsequent calls.
+ * The static global ID is stored in the first word of the format string buffer.
*/
-void ceph_san_log(const char *file, const char *func, unsigned int line, const char *fmt, ...)
+void ceph_san_log(const char *file, const char *func, 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;
+ static unsigned int *p_reg_id = NULL;
+ unsigned int reg_id = 0;
va_list args;
- u64 alloc;
- int len, needed_size;
- ctx = ceph_san_get_tls_ctx();
- if (!ctx) {
- pr_err("Failed to get TLS context\n");
- return;
+ /* Check if we've registered this location before */
+ if (likely(p_reg_id)) {
+ reg_id = *p_reg_id;
+ } else {
+ /* First call - register this location */
+ reg_id = ceph_san_log_register(file, func, line, fmt);
+ if (!reg_id) {
+ /* Registration failed */
+ pr_err("ceph_san_log: registration failed for %s:%s:%d\n",
+ file, func, line);
+ return;
+ }
+
+ /* Store registration ID in the format string's first word */
+ p_reg_id = (unsigned int *)fmt;
+ *p_reg_id = reg_id;
}
-
+
+ /* Call the ID-based logger with the same arguments */
va_start(args, fmt);
- len = vsnprintf(buf, sizeof(buf), fmt, args);
+ ceph_san_log_with_id_v(reg_id, fmt, args);
va_end(args);
-
- needed_size = sizeof(*entry) + len + 1;
- /* Allocate entry from pagefrag - We need a spinlock here to protect access iterators */
- spin_lock_bh(&ctx->pf.lock);
- alloc = cephsan_pagefrag_alloc(&ctx->pf, needed_size);
- int loop_count = 0;
- while (!alloc) {
- entry = cephsan_pagefrag_get_ptr_from_tail(&ctx->pf);
- if (loop_count++ >= 32) {
- pr_err("ceph_san_log: pagefrag stats - head: %u, tail: %u, size: %u, free: %d\n",
- ctx->pf.head, ctx->pf.tail,
- CEPHSAN_PAGEFRAG_SIZE,
- (ctx->pf.tail > ctx->pf.head) ?
- ctx->pf.tail - ctx->pf.head :
- CEPHSAN_PAGEFRAG_SIZE - (ctx->pf.head - ctx->pf.tail));
-
- panic("ceph_san_log: failed to allocate entry after 8 retries");
- }
- if (entry->debug_poison != CEPH_SAN_LOG_ENTRY_POISON || entry->len == 0) {
- pr_err("ceph_san_log: pagefrag corruption detected\n");
- pr_err(" head: %u, tail: %u, size: %u\n",
- ctx->pf.head, ctx->pf.tail, CEPHSAN_PAGEFRAG_SIZE);
- pr_err(" active_elements: %u, alloc_count: %u\n",
- ctx->pf.active_elements, ctx->pf.alloc_count);
- pr_err(" entry poison: %llx, len: %u\n",
- entry->debug_poison, entry->len);
- pr_err(" wrap_to_end: %u, wrap_around: %u\n",
- ctx->pf.wrap_to_end, ctx->pf.wrap_around);
- BUG();
- }
- cephsan_pagefrag_free(&ctx->pf, entry->len);
- alloc = cephsan_pagefrag_alloc(&ctx->pf, needed_size);
- }
- entry = cephsan_pagefrag_get_ptr(&ctx->pf, alloc);
-
- /* Fill in entry details */
- entry->debug_poison = CEPH_SAN_LOG_ENTRY_POISON;
- entry->ts = jiffies;
- entry->line = line;
- entry->file = file;
- entry->func = func;
- if (unlikely(cephsan_pagefrag_is_wraparound(alloc))) {
- entry->buffer = cephsan_pagefrag_get_ptr(&ctx->pf, 0);
- } else {
- entry->buffer = (char *)(entry + 1);
- }
- entry->len = cephsan_pagefrag_get_alloc_size(alloc);
- spin_unlock_bh(&ctx->pf.lock);
-
- /* Copy to entry buffer */
- memcpy(entry->buffer, buf, len + 1);
- entry->buffer[len] = '\0';
}
EXPORT_SYMBOL(ceph_san_log);
/* Initialize global state */
INIT_LIST_HEAD(&g_logger.contexts);
spin_lock_init(&g_logger.lock);
+ g_next_reg_id = 1; /* Start IDs at 1, 0 is invalid */
/* Initialize allocation batch */
ret = ceph_san_batch_init(&g_logger.alloc_batch);
return entry;
}
-EXPORT_SYMBOL(ceph_san_log_iter_next);
\ No newline at end of file
+EXPORT_SYMBOL(ceph_san_log_iter_next);
+
+/**
+ * ceph_san_log_register - Register a logging location
+ * @file: Source file name (static string)
+ * @func: Function name (static string)
+ * @line: Line number
+ * @fmt: Format string (static string)
+ *
+ * Registers a logging location to avoid storing the same information in each log entry.
+ * Returns a registration ID or 0 on failure.
+ */
+unsigned int ceph_san_log_register(const char *file, const char *func,
+ unsigned int line, const char *fmt)
+{
+ unsigned int reg_id;
+ unsigned int params_size;
+
+ if (!file || !func || !fmt)
+ return 0;
+
+ spin_lock_bh(&g_reg_lock);
+
+ /* Check if this is a duplicate registration */
+ for (reg_id = 1; reg_id < g_next_reg_id; reg_id++) {
+ if (g_registrations[reg_id].file == file &&
+ g_registrations[reg_id].func == func &&
+ g_registrations[reg_id].line == line &&
+ g_registrations[reg_id].fmt == fmt) {
+ spin_unlock_bh(&g_reg_lock);
+ return reg_id;
+ }
+ }
+
+ /* Check if we have space for a new registration */
+ if (g_next_reg_id >= CEPH_SAN_LOG_MAX_REGISTRATIONS) {
+ spin_unlock_bh(&g_reg_lock);
+ pr_err("Too many log registrations\n");
+ return 0;
+ }
+
+ /* Calculate the size of parameters when compacted */
+ params_size = strlen(file) + 1 + strlen(func) + 1 + sizeof(unsigned int) + strlen(fmt) + 1;
+
+ /* Create a new registration */
+ reg_id = g_next_reg_id++;
+ g_registrations[reg_id].file = file;
+ g_registrations[reg_id].func = func;
+ g_registrations[reg_id].line = line;
+ g_registrations[reg_id].fmt = fmt;
+ g_registrations[reg_id].id = reg_id;
+ g_registrations[reg_id].params_size = params_size;
+
+ spin_unlock_bh(&g_reg_lock);
+ return reg_id;
+}
+EXPORT_SYMBOL(ceph_san_log_register);
+
+/**
+ * ceph_san_log_with_id_v - Log a message using registration ID with va_list
+ * @reg_id: Registration ID
+ * @fmt: Format string
+ * @args: Variable argument list
+ *
+ * Logs a message using a pre-registered ID. The parameters are compacted
+ * and stored efficiently.
+ */
+void ceph_san_log_with_id_v(unsigned int reg_id, const char *fmt, va_list args)
+{
+ char buf[256];
+ struct ceph_san_tls_ctx *ctx;
+ struct ceph_san_log_entry *entry;
+ struct ceph_san_log_registration *reg;
+ u64 alloc;
+ int len, needed_size;
+
+ /* Validate registration ID */
+ if (!reg_id || reg_id >= g_next_reg_id) {
+ pr_err("ceph_san_log: invalid registration ID %u\n", reg_id);
+ return;
+ }
+
+ /* Get registration info */
+ reg = &g_registrations[reg_id];
+ if (reg->fmt != fmt) {
+ pr_err("ceph_san_log: format string mismatch for ID %u\n", reg_id);
+ return;
+ }
+
+ /* Get TLS context */
+ ctx = ceph_san_get_tls_ctx();
+ if (!ctx) {
+ pr_err("Failed to get TLS context\n");
+ return;
+ }
+
+ /* Format message with arguments */
+ len = vsnprintf(buf, sizeof(buf), fmt, args);
+
+ /* Allocate log entry with compacted parameters */
+ needed_size = sizeof(*entry) + len + 1;
+
+ spin_lock_bh(&ctx->pf.lock);
+ alloc = cephsan_pagefrag_alloc(&ctx->pf, needed_size);
+
+ /* Handle allocation failures by freeing older entries */
+ int loop_count = 0;
+ while (!alloc) {
+ entry = cephsan_pagefrag_get_ptr_from_tail(&ctx->pf);
+ if (loop_count++ >= 32) {
+ pr_err("ceph_san_log: pagefrag stats - head: %u, tail: %u, size: %u, free: %d\n",
+ ctx->pf.head, ctx->pf.tail,
+ CEPHSAN_PAGEFRAG_SIZE,
+ (ctx->pf.tail > ctx->pf.head) ?
+ ctx->pf.tail - ctx->pf.head :
+ CEPHSAN_PAGEFRAG_SIZE - (ctx->pf.head - ctx->pf.tail));
+
+ panic("ceph_san_log: failed to allocate entry after 32 retries");
+ }
+
+ /* Check for corruption */
+ if (entry->debug_poison != CEPH_SAN_LOG_ENTRY_POISON || entry->len == 0) {
+ struct ceph_san_log_registration *reg = &g_registrations[entry->reg_id];
+ pr_err("ceph_san_log: pagefrag corruption detected\n");
+ pr_err(" head: %u, tail: %u, size: %u\n",
+ ctx->pf.head, ctx->pf.tail, CEPHSAN_PAGEFRAG_SIZE);
+ pr_err(" active_elements: %u, alloc_count: %u\n",
+ ctx->pf.active_elements, ctx->pf.alloc_count);
+ pr_err(" entry poison: %llx, len: %u\n",
+ entry->debug_poison, entry->len);
+ pr_err(" wrap_to_end: %u, wrap_around: %u\n",
+ ctx->pf.wrap_to_end, ctx->pf.wrap_around);
+ pr_err(" location: %s:%s:%u\n",
+ reg->file, reg->func, reg->line);
+ BUG();
+ }
+
+ /* Free the entry and try again */
+ cephsan_pagefrag_free(&ctx->pf, entry->len);
+ alloc = cephsan_pagefrag_alloc(&ctx->pf, needed_size);
+ }
+
+ /* Get pointer to the allocated entry */
+ entry = cephsan_pagefrag_get_ptr(&ctx->pf, alloc);
+
+ /* Fill in entry details */
+ entry->debug_poison = CEPH_SAN_LOG_ENTRY_POISON;
+ entry->ts = jiffies;
+ entry->reg_id = reg_id;
+
+ /* Handle buffer wraparound */
+ if (unlikely(cephsan_pagefrag_is_wraparound(alloc))) {
+ entry->buffer = cephsan_pagefrag_get_ptr(&ctx->pf, 0);
+ } else {
+ entry->buffer = (char *)(entry + 1);
+ }
+
+ entry->len = len;
+ spin_unlock_bh(&ctx->pf.lock);
+
+ /* Copy the formatted message to the buffer */
+ memcpy(entry->buffer, buf, len + 1);
+ entry->buffer[len] = '\0';
+}
+
+/**
+ * ceph_san_log_with_id - Log a message using registration ID
+ * @reg_id: Registration ID
+ * @fmt: Format string
+ *
+ * Logs a message using a pre-registered ID. The parameters are compacted
+ * and stored efficiently.
+ */
+void ceph_san_log_with_id(unsigned int reg_id, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ ceph_san_log_with_id_v(reg_id, fmt, args);
+ va_end(args);
+}
+EXPORT_SYMBOL(ceph_san_log_with_id);
\ No newline at end of file