[PATCH v2 01/15] ceph: add BLOG public headers
Alex Markuze <[email protected]> Mon, 6 Jul 2026 14:38:29 +0000
| Newsgroups | org.kernel.vger.ceph-devel |
|---|---|
| Message-ID | <[email protected]> |
Add the public header files for the binary logging (BLOG) subsystem:
blog.h - core types: blog_logger, blog_log_entry,
blog_tls_ctx, blog_source_info, blog_log_iter,
blog_source_id_cache; core API prototypes
blog_ser.h - type-safe serialization macros (blog_ser,
blog_cnt) with compile-time type dispatch
blog_des.h - deserialization prototypes
blog_batch.h - per-CPU magazine batch allocator types
blog_pagefrag.h - page-fragment allocator types
blog_module.h - per-module context types (blog_task_entry,
blog_module_context) and the __BLOG_LOG_CTX
macro that drives the per-callsite fast path
All headers live under include/linux/ceph/ since BLOG is consumed
exclusively by the CephFS client.
Signed-off-by: Alex Markuze <[email protected]>
---
include/linux/ceph/blog.h | 196 +++++++++++++++++++++
include/linux/ceph/blog_batch.h | 44 +++++
include/linux/ceph/blog_des.h | 16 ++
include/linux/ceph/blog_module.h | 91 ++++++++++
include/linux/ceph/blog_pagefrag.h | 32 ++++
include/linux/ceph/blog_ser.h | 270 +++++++++++++++++++++++++++++
6 files changed, 649 insertions(+)
create mode 100644 include/linux/ceph/blog.h
create mode 100644 include/linux/ceph/blog_batch.h
create mode 100644 include/linux/ceph/blog_des.h
create mode 100644 include/linux/ceph/blog_module.h
create mode 100644 include/linux/ceph/blog_pagefrag.h
create mode 100644 include/linux/ceph/blog_ser.h
diff --git a/include/linux/ceph/blog.h b/include/linux/ceph/blog.h
new file mode 100644
index 000000000000..edc0e1aa05bf
--- /dev/null
+++ b/include/linux/ceph/blog.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Infrastructure (BLOG)
+ *
+ * Generic binary logging infrastructure for kernel subsystems.
+ * Modules maintain their own client mappings and debugfs interfaces.
+ */
+#ifndef _LINUX_CEPH_BLOG_H
+#define _LINUX_CEPH_BLOG_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rhashtable-types.h>
+#include <linux/ceph/blog_batch.h>
+#include <linux/ceph/blog_pagefrag.h>
+#include <linux/ceph/blog_ser.h>
+#include <linux/ceph/blog_des.h>
+
+struct blog_module_context;
+
+#ifdef CONFIG_BLOG_DEBUG
+#define BLOG_DEBUG_POISON 1
+#else
+#define BLOG_DEBUG_POISON 0
+#endif
+
+#ifdef CONFIG_BLOG_TRACK_USAGE
+#define BLOG_TRACK_USAGE 1
+#else
+#define BLOG_TRACK_USAGE 0
+#endif
+
+#if BLOG_DEBUG_POISON
+#define BLOG_LOG_ENTRY_POISON 0xD1E7C0DE
+#define BLOG_CTX_POISON 0xCAFEBABE
+#endif
+
+#define BLOG_MAX_PAYLOAD 255
+#ifdef CONFIG_BLOG_MAX_SOURCES
+#define BLOG_MAX_SOURCE_IDS CONFIG_BLOG_MAX_SOURCES
+#else
+#define BLOG_MAX_SOURCE_IDS 4096
+#endif
+#ifdef CONFIG_BLOG_MAX_CLIENTS
+#define BLOG_MAX_CLIENT_IDS CONFIG_BLOG_MAX_CLIENTS
+#else
+#define BLOG_MAX_CLIENT_IDS 256
+#endif
+
+struct blog_source_info {
+ const char *file;
+ const char *func;
+ unsigned int line;
+ const char *fmt;
+ int warn_count;
+#if BLOG_TRACK_USAGE
+ atomic_t napi_usage;
+ atomic_t task_usage;
+ atomic_t napi_bytes;
+ atomic_t task_bytes;
+#endif
+};
+
+struct blog_log_entry {
+#if BLOG_DEBUG_POISON
+ u64 debug_poison;
+#endif
+ u32 ts_delta;
+ u16 source_id;
+ u8 len;
+ u8 client_id;
+ u8 flags;
+ char buffer[];
+};
+
+#define BLOG_CTX_NEEDS_RESET 0
+
+struct blog_tls_ctx {
+ struct list_head list;
+ void (*release)(void *data);
+ atomic_t refcount;
+ struct task_struct *task;
+ pid_t pid;
+ char comm[TASK_COMM_LEN];
+ u64 id;
+#if BLOG_DEBUG_POISON
+ u64 debug_poison;
+#endif
+ unsigned long base_jiffies;
+ struct blog_logger *logger;
+ int pending_offset;
+ size_t pending_size;
+ unsigned long flags;
+};
+
+struct blog_tls_pagefrag {
+ struct blog_tls_ctx ctx;
+ struct blog_pagefrag pf;
+ unsigned char buf[];
+};
+
+#define BLOG_TLS_PAGEFRAG_ALLOC_SIZE BLOG_PAGEFRAG_SIZE
+#define BLOG_TLS_PAGEFRAG_BUFFER_SIZE \
+ (BLOG_PAGEFRAG_SIZE - sizeof(struct blog_tls_pagefrag))
+
+struct blog_logger {
+ struct list_head contexts;
+ spinlock_t lock;
+ struct rhashtable task_map;
+ struct blog_batch alloc_batch;
+ struct blog_batch log_batch;
+ struct kmem_cache *magazine_cache;
+ struct blog_source_info *source_map;
+ atomic_t next_source_id;
+ spinlock_t source_lock;
+ unsigned long total_contexts_allocated;
+ u64 next_ctx_id;
+ spinlock_t ctx_id_lock;
+ struct blog_tls_ctx *__percpu
+ *napi_ctxs;
+ struct blog_module_context *owner_ctx;
+ u64 generation;
+};
+
+/**
+ * struct blog_source_id_cache - per-callsite source ID fast cache
+ * @logger: logger that owns the cached ID
+ * @generation: logger generation at cache-fill time
+ * @id: cached source ID (0 = not yet cached)
+ */
+struct blog_source_id_cache {
+ struct blog_logger *logger;
+ u64 generation;
+ u32 id;
+};
+
+struct blog_log_iter {
+ struct blog_pagefrag *pf;
+ u64 current_offset;
+ u64 end_offset;
+ u64 prev_offset;
+ u64 steps;
+};
+
+typedef int (*blog_client_des_fn)(char *buf, size_t size, u8 client_id);
+
+u32 blog_get_source_id(struct blog_logger *logger, const char *file,
+ const char *func, unsigned int line, const char *fmt);
+u32 blog_get_source_id_cached(struct blog_logger *logger,
+ struct blog_source_id_cache *cache,
+ const char *file, const char *func,
+ unsigned int line, const char *fmt);
+struct blog_source_info *blog_get_source_info(struct blog_logger *logger,
+ u32 id);
+void *blog_log(struct blog_logger *logger, u32 source_id, u8 client_id,
+ size_t needed_size);
+int blog_log_commit(struct blog_logger *logger, size_t actual_size);
+struct blog_tls_ctx *blog_get_tls_ctx(struct blog_logger *logger);
+struct blog_tls_ctx *blog_get_napi_ctx(struct blog_logger *logger);
+void blog_set_napi_ctx(struct blog_logger *logger, struct blog_tls_ctx *ctx);
+struct blog_tls_ctx *blog_get_ctx(struct blog_logger *logger);
+void blog_log_iter_init(struct blog_log_iter *iter, struct blog_pagefrag *pf,
+ u64 head_snapshot);
+struct blog_log_entry *blog_log_iter_next(struct blog_log_iter *iter);
+int blog_des_entry(struct blog_logger *logger, struct blog_log_entry *entry,
+ char *output, size_t out_size,
+ blog_client_des_fn client_cb);
+bool blog_is_valid_kernel_addr(const void *addr);
+
+static inline void blog_logger_print_stats(struct blog_logger *logger)
+{
+ pr_debug(
+ "blog: total_contexts=%lu, alloc_batch={empty=%d, full=%d}, log_batch={empty=%d, full=%d}\n",
+ logger->total_contexts_allocated, logger->alloc_batch.nr_empty,
+ logger->alloc_batch.nr_full, logger->log_batch.nr_empty,
+ logger->log_batch.nr_full);
+}
+
+static inline struct blog_tls_pagefrag *blog_ctx_container(struct blog_tls_ctx *ctx)
+{
+ return container_of(ctx, struct blog_tls_pagefrag, ctx);
+}
+
+static inline void *blog_ctx_buffer(struct blog_tls_ctx *ctx)
+{
+ return blog_ctx_container(ctx)->buf;
+}
+
+static inline struct blog_pagefrag *blog_ctx_pf(struct blog_tls_ctx *ctx)
+{
+ return &blog_ctx_container(ctx)->pf;
+}
+
+#endif /* _LINUX_CEPH_BLOG_H */
diff --git a/include/linux/ceph/blog_batch.h b/include/linux/ceph/blog_batch.h
new file mode 100644
index 000000000000..be61ebd37c17
--- /dev/null
+++ b/include/linux/ceph/blog_batch.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Batch Management
+ */
+#ifndef _LINUX_CEPH_BLOG_BATCH_H
+#define _LINUX_CEPH_BLOG_BATCH_H
+
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define BLOG_MAGAZINE_SIZE 16
+
+struct blog_magazine {
+ struct list_head list;
+ unsigned int count;
+ void *elements[BLOG_MAGAZINE_SIZE];
+};
+
+struct blog_cpu_magazine {
+ struct blog_magazine *mag;
+};
+
+struct blog_batch {
+ struct list_head full_magazines;
+ struct list_head empty_magazines;
+ spinlock_t full_lock;
+ spinlock_t empty_lock;
+ unsigned int nr_full;
+ unsigned int nr_empty;
+ struct blog_cpu_magazine __percpu *cpu_magazines;
+ struct kmem_cache *magazine_cache;
+ bool external_cache;
+ unsigned int retain_limit;
+};
+
+int blog_batch_init(struct blog_batch *batch, struct kmem_cache *mag_cache,
+ unsigned int nr_prealloc, unsigned int retain_limit);
+void blog_batch_cleanup(struct blog_batch *batch);
+void *blog_batch_get(struct blog_batch *batch);
+void blog_batch_put(struct blog_batch *batch, void *element);
+
+#endif /* _LINUX_CEPH_BLOG_BATCH_H */
diff --git a/include/linux/ceph/blog_des.h b/include/linux/ceph/blog_des.h
new file mode 100644
index 000000000000..a5ce1ed6290a
--- /dev/null
+++ b/include/linux/ceph/blog_des.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Deserialization
+ */
+#ifndef _LINUX_CEPH_BLOG_DES_H
+#define _LINUX_CEPH_BLOG_DES_H
+
+#include <linux/types.h>
+
+struct blog_log_entry;
+struct blog_logger;
+
+int blog_des_reconstruct(const char *fmt, const void *buffer,
+ size_t size, char *out, size_t out_size);
+
+#endif /* _LINUX_CEPH_BLOG_DES_H */
diff --git a/include/linux/ceph/blog_module.h b/include/linux/ceph/blog_module.h
new file mode 100644
index 000000000000..41651f6bc742
--- /dev/null
+++ b/include/linux/ceph/blog_module.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Infrastructure (BLOG) - Per-Module Support
+ *
+ * Each kernel module can have its own isolated logging context.
+ * Per-task context association uses an rhashtable keyed by task pointer,
+ * with PID validation for stale-entry detection.
+ */
+#ifndef _LINUX_CEPH_BLOG_MODULE_H
+#define _LINUX_CEPH_BLOG_MODULE_H
+
+#include <linux/ceph/blog.h>
+#include <linux/rhashtable.h>
+
+struct blog_task_entry {
+ struct rhash_head node;
+ struct task_struct *task;
+ pid_t pid;
+ char comm[TASK_COMM_LEN];
+ struct blog_tls_ctx *ctx;
+ struct rcu_head rcu;
+};
+
+struct blog_module_context {
+ char name[32];
+ struct blog_logger *logger;
+ void *module_private;
+ struct list_head list;
+ atomic_t refcount;
+ atomic_t allocated_contexts;
+ bool initialized;
+};
+
+struct blog_module_context *blog_module_init(const char *module_name);
+void blog_module_cleanup(struct blog_module_context *ctx);
+void blog_module_get(struct blog_module_context *ctx);
+void blog_module_put(struct blog_module_context *ctx);
+
+struct blog_tls_ctx *blog_get_tls_ctx_ctx(struct blog_module_context *ctx);
+struct blog_tls_ctx *blog_get_napi_ctx_ctx(struct blog_module_context *ctx);
+void blog_set_napi_ctx_ctx(struct blog_module_context *ctx,
+ struct blog_tls_ctx *tls_ctx);
+struct blog_tls_ctx *blog_get_ctx_ctx(struct blog_module_context *ctx);
+
+u32 blog_get_source_id_ctx(struct blog_module_context *ctx, const char *file,
+ const char *func, unsigned int line, const char *fmt);
+struct blog_source_info *blog_get_source_info_ctx(struct blog_module_context *ctx,
+ u32 id);
+
+void *blog_log_with_ctx(struct blog_logger *logger,
+ struct blog_tls_ctx *tls_ctx,
+ u32 source_id, u8 client_id, size_t needed_size);
+int blog_log_commit_with_ctx(struct blog_logger *logger,
+ struct blog_tls_ctx *tls_ctx,
+ size_t actual_size);
+
+#define BLOG_LOG_CTX(ctx, fmt, ...) \
+ __BLOG_LOG_CTX(ctx, 0, 0, fmt, ##__VA_ARGS__)
+
+#define BLOG_LOG_CLIENT_CTX(ctx, client_id, fmt, ...) \
+ __BLOG_LOG_CTX(ctx, 0, client_id, fmt, ##__VA_ARGS__)
+
+#define __BLOG_LOG_CTX(__ctx, dbg, __client_id, fmt, ...) \
+ do { \
+ static u32 __source_id; \
+ static size_t __size; \
+ struct blog_tls_ctx *__tls; \
+ void *___buffer = NULL; \
+ (void)(dbg); \
+ if (unlikely(!(__ctx) || !(__ctx)->logger)) \
+ break; \
+ __tls = blog_get_ctx_ctx(__ctx); \
+ if (unlikely(!__tls)) \
+ break; \
+ if (unlikely(__source_id == 0)) { \
+ __source_id = blog_get_source_id_ctx(__ctx, \
+ kbasename(__FILE__), __func__, __LINE__, fmt); \
+ __size = blog_cnt(__VA_ARGS__); \
+ } \
+ ___buffer = blog_log_with_ctx((__ctx)->logger, __tls, \
+ __source_id, __client_id, __size); \
+ if (likely(___buffer)) { \
+ void *___tmp = ___buffer; \
+ if (__size > 0) \
+ blog_ser(___buffer, ##__VA_ARGS__); \
+ blog_log_commit_with_ctx((__ctx)->logger, __tls, \
+ ___buffer - ___tmp); \
+ } \
+ } while (0)
+
+#endif /* _LINUX_CEPH_BLOG_MODULE_H */
diff --git a/include/linux/ceph/blog_pagefrag.h b/include/linux/ceph/blog_pagefrag.h
new file mode 100644
index 000000000000..b48095d9690c
--- /dev/null
+++ b/include/linux/ceph/blog_pagefrag.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Page Fragment Management
+ */
+#ifndef _LINUX_CEPH_BLOG_PAGEFRAG_H
+#define _LINUX_CEPH_BLOG_PAGEFRAG_H
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+
+#define BLOG_PAGEFRAG_SIZE (1<<17) /* 128KB */
+#define BLOG_PAGEFRAG_MASK (BLOG_PAGEFRAG_SIZE - 1)
+
+struct blog_pagefrag {
+ struct page *pages;
+ void *buffer;
+ size_t capacity;
+ spinlock_t lock;
+ unsigned int head;
+ unsigned int alloc_count;
+ int active_elements;
+ void *last_entry;
+};
+
+int blog_pagefrag_init_with_buffer(struct blog_pagefrag *pf, void *buffer, size_t size);
+int blog_pagefrag_reserve(struct blog_pagefrag *pf, unsigned int n);
+void blog_pagefrag_publish(struct blog_pagefrag *pf, u64 publish_head);
+void blog_pagefrag_reset(struct blog_pagefrag *pf);
+void *blog_pagefrag_get_ptr(struct blog_pagefrag *pf, u64 val);
+
+#endif /* _LINUX_CEPH_BLOG_PAGEFRAG_H */
diff --git a/include/linux/ceph/blog_ser.h b/include/linux/ceph/blog_ser.h
new file mode 100644
index 000000000000..1d570388ff09
--- /dev/null
+++ b/include/linux/ceph/blog_ser.h
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Binary Logging Serialization
+ */
+#ifndef _LINUX_CEPH_BLOG_SER_H
+#define _LINUX_CEPH_BLOG_SER_H
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#define IS_CONST_STR_PTR(t) \
+ __builtin_types_compatible_p(typeof(t), const char *)
+
+#define IS_STR_PTR(t) \
+ __builtin_types_compatible_p(typeof(t), char *)
+
+#define IS_STR(t) \
+ (__builtin_types_compatible_p(typeof(t), const char *) || \
+ __builtin_types_compatible_p(typeof(t), char *))
+
+#define __suppress_cast_warning(type, value) \
+({ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wint-to-pointer-cast\"") \
+ _Pragma("GCC diagnostic ignored \"-Wpointer-to-int-cast\"") \
+ type __scw_result; \
+ __scw_result = ((type)(value)); \
+ _Pragma("GCC diagnostic pop") \
+ __scw_result; \
+})
+
+#define ___blog_concat(__a, __b) __a ## __b
+#define ___blog_apply(__fn, __n) ___blog_concat(__fn, __n)
+
+#define ___blog_nth(_, __1, __2, __3, __4, __5, __6, __7, __8, __9, \
+ __10, __11, __12, __13, __14, __15, __16, __17, __18, __19, __20, \
+ __21, __22, __23, __24, __25, __26, __27, __28, __29, __30, __31, \
+ __32, __N, ...) __N
+#define ___blog_narg(...) ___blog_nth(_, ##__VA_ARGS__, \
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+#define blog_narg(...) ___blog_narg(__VA_ARGS__)
+
+#define STR_MAX_SIZE 255
+#define __sizeof(x) \
+ (IS_STR(x) ? STR_MAX_SIZE : \
+ (sizeof(x) < 4) ? 4 : sizeof(x))
+
+/* Size calculation macros */
+#define ___blog_cnt0() (0)
+#define ___blog_cnt1(__t) (__sizeof(__t))
+#define ___blog_cnt2(__t, __args...) (___blog_cnt1(__args) + __sizeof(__t))
+#define ___blog_cnt3(__t, __args...) (___blog_cnt2(__args) + __sizeof(__t))
+#define ___blog_cnt4(__t, __args...) (___blog_cnt3(__args) + __sizeof(__t))
+#define ___blog_cnt5(__t, __args...) (___blog_cnt4(__args) + __sizeof(__t))
+#define ___blog_cnt6(__t, __args...) (___blog_cnt5(__args) + __sizeof(__t))
+#define ___blog_cnt7(__t, __args...) (___blog_cnt6(__args) + __sizeof(__t))
+#define ___blog_cnt8(__t, __args...) (___blog_cnt7(__args) + __sizeof(__t))
+#define ___blog_cnt9(__t, __args...) (___blog_cnt8(__args) + __sizeof(__t))
+#define ___blog_cnt10(__t, __args...) (___blog_cnt9(__args) + __sizeof(__t))
+#define ___blog_cnt11(__t, __args...) (___blog_cnt10(__args) + __sizeof(__t))
+#define ___blog_cnt12(__t, __args...) (___blog_cnt11(__args) + __sizeof(__t))
+#define ___blog_cnt13(__t, __args...) (___blog_cnt12(__args) + __sizeof(__t))
+#define ___blog_cnt14(__t, __args...) (___blog_cnt13(__args) + __sizeof(__t))
+#define ___blog_cnt15(__t, __args...) (___blog_cnt14(__args) + __sizeof(__t))
+#define ___blog_cnt16(__t, __args...) (___blog_cnt15(__args) + __sizeof(__t))
+#define ___blog_cnt17(__t, __args...) (___blog_cnt16(__args) + __sizeof(__t))
+#define ___blog_cnt18(__t, __args...) (___blog_cnt17(__args) + __sizeof(__t))
+#define ___blog_cnt19(__t, __args...) (___blog_cnt18(__args) + __sizeof(__t))
+#define ___blog_cnt20(__t, __args...) (___blog_cnt19(__args) + __sizeof(__t))
+#define ___blog_cnt21(__t, __args...) (___blog_cnt20(__args) + __sizeof(__t))
+#define ___blog_cnt22(__t, __args...) (___blog_cnt21(__args) + __sizeof(__t))
+#define ___blog_cnt23(__t, __args...) (___blog_cnt22(__args) + __sizeof(__t))
+#define ___blog_cnt24(__t, __args...) (___blog_cnt23(__args) + __sizeof(__t))
+#define ___blog_cnt25(__t, __args...) (___blog_cnt24(__args) + __sizeof(__t))
+#define ___blog_cnt26(__t, __args...) (___blog_cnt25(__args) + __sizeof(__t))
+#define ___blog_cnt27(__t, __args...) (___blog_cnt26(__args) + __sizeof(__t))
+#define ___blog_cnt28(__t, __args...) (___blog_cnt27(__args) + __sizeof(__t))
+#define ___blog_cnt29(__t, __args...) (___blog_cnt28(__args) + __sizeof(__t))
+#define ___blog_cnt30(__t, __args...) (___blog_cnt29(__args) + __sizeof(__t))
+#define ___blog_cnt31(__t, __args...) (___blog_cnt30(__args) + __sizeof(__t))
+#define ___blog_cnt32(__t, __args...) (___blog_cnt31(__args) + __sizeof(__t))
+#define blog_cnt(...) ___blog_apply(___blog_cnt, blog_narg(__VA_ARGS__))(__VA_ARGS__)
+
+#define IS_STR_ARRAY(t) \
+ __builtin_types_compatible_p(typeof(t), char [])
+
+#define IS_DYNAMIC_CHAR_PTR(t) \
+ (__builtin_classify_type((t)) == 14 && \
+ __builtin_types_compatible_p(typeof(t), char *) && \
+ !__builtin_constant_p((t)))
+
+#define IS_STATIC_CHAR_ARRAY(t) \
+ (__builtin_classify_type((t)) == 5 && \
+ __builtin_types_compatible_p(typeof(t), char[]) && \
+ __builtin_constant_p((t)))
+
+#define IS_DYNAMIC_CHAR_ARRAY(t) \
+ (__builtin_classify_type((t)) == 5 && \
+ __builtin_types_compatible_p(typeof(t), char[]) && \
+ !__builtin_constant_p((t)))
+
+#define char_ptr(str) __suppress_cast_warning(char *, (str))
+
+#ifndef _BLOG_SER_HELPERS_DEFINED
+#define _BLOG_SER_HELPERS_DEFINED
+
+union null_str_u {
+ char str[8];
+ unsigned long force_align;
+};
+
+static const union null_str_u null_str = {
+ .str = "(NULL) \0"
+};
+
+static inline size_t write_null_str(char *dst)
+{
+ *(union null_str_u *)dst = null_str;
+ static_assert(sizeof(null_str.str) == sizeof(unsigned long),
+ "null_str.str size must match unsigned long for proper alignment");
+ return __builtin_strlen(null_str.str);
+}
+
+static inline size_t strscpy_n(char *dst, const char *src)
+{
+ size_t count = 0;
+
+ while (count < STR_MAX_SIZE - 1) {
+ dst[count] = src[count];
+ if (src[count] == '\0')
+ goto out;
+ count++;
+ }
+
+ dst[count] = '\0';
+ pr_warn("blog_ser: string truncated, exceeded max size %d\n", STR_MAX_SIZE);
+out:
+ return count + 1;
+}
+
+static inline ssize_t __strscpy(char *dst, const char *src)
+{
+ if (src != NULL)
+ return strscpy_n(dst, src);
+ return write_null_str(dst);
+}
+
+static inline void *strscpy_n_update(char *dst, const char *src, const char *file, int line)
+{
+ ssize_t ret = __strscpy(dst, src);
+
+ if (unlikely(ret <= 0 || ret >= STR_MAX_SIZE)) {
+ pr_err("blog_ser: string handling error ret=%zd at %s:%d :: dst='%s' src='%s'\n",
+ ret, file, line, dst, src ? src : "(null)");
+ if (ret >= STR_MAX_SIZE) {
+ dst[STR_MAX_SIZE - 1] = '\0';
+ ret = STR_MAX_SIZE;
+ } else {
+ dst[0] = '\0';
+ ret = 1;
+ }
+ }
+ return dst + round_up(ret, 4);
+}
+
+#endif /* _BLOG_SER_HELPERS_DEFINED */
+
+#define __blog_ser_type(__buffer, __t) \
+ (__builtin_choose_expr(IS_STATIC_CHAR_ARRAY((__t)), \
+ ((__buffer) = (void *)strscpy_n_update((__buffer), \
+ char_ptr(__t), \
+ kbasename(__FILE__), \
+ __LINE__)), \
+ __builtin_choose_expr(IS_STR((__t)), \
+ ((__buffer) = (void *)strscpy_n_update((__buffer), \
+ char_ptr(__t), \
+ kbasename(__FILE__), \
+ __LINE__)), \
+ __builtin_choose_expr(IS_STR_ARRAY((__t)), \
+ ((__buffer) = (void *)strscpy_n_update((__buffer), \
+ char_ptr(__t), \
+ kbasename(__FILE__), \
+ __LINE__)), \
+ __builtin_choose_expr(sizeof((__t)) == 1, \
+ (*(u32 *)(__buffer) = __suppress_cast_warning(u32, (__t)), \
+ (__buffer) = (void *)((char *)(__buffer) + 4)), \
+ __builtin_choose_expr(sizeof((__t)) == 2, \
+ (*(u32 *)(__buffer) = __suppress_cast_warning(u32, (__t)), \
+ (__buffer) = (void *)((char *)(__buffer) + 4)), \
+ __builtin_choose_expr(sizeof((__t)) == 4, \
+ (*(u32 *)(__buffer) = __suppress_cast_warning(u32, (__t)), \
+ (__buffer) = (void *)((char *)(__buffer) + 4)), \
+ __builtin_choose_expr(sizeof((__t)) == 8, \
+ (*(u64 *)(__buffer) = __suppress_cast_warning(u64, (__t)), \
+ (__buffer) = (void *)((char *)(__buffer) + 8)), \
+ (pr_err("UNSUPPORTED_TYPE: %s:%d: unsupported type size %zu\n", \
+ kbasename(__FILE__), __LINE__, sizeof(__t))) \
+ ))))))))
+
+/* Serialization macros */
+#define ___blog_ser0(__buffer)
+#define ___blog_ser1(__buffer, __t) (__blog_ser_type(__buffer, __t))
+#define ___blog_ser2(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser1(__buffer, __args))
+#define ___blog_ser3(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser2(__buffer, __args))
+#define ___blog_ser4(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser3(__buffer, __args))
+#define ___blog_ser5(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser4(__buffer, __args))
+#define ___blog_ser6(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser5(__buffer, __args))
+#define ___blog_ser7(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser6(__buffer, __args))
+#define ___blog_ser8(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser7(__buffer, __args))
+#define ___blog_ser9(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser8(__buffer, __args))
+#define ___blog_ser10(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser9(__buffer, __args))
+#define ___blog_ser11(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser10(__buffer, __args))
+#define ___blog_ser12(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser11(__buffer, __args))
+#define ___blog_ser13(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser12(__buffer, __args))
+#define ___blog_ser14(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser13(__buffer, __args))
+#define ___blog_ser15(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser14(__buffer, __args))
+#define ___blog_ser16(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser15(__buffer, __args))
+#define ___blog_ser17(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser16(__buffer, __args))
+#define ___blog_ser18(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser17(__buffer, __args))
+#define ___blog_ser19(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser18(__buffer, __args))
+#define ___blog_ser20(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser19(__buffer, __args))
+#define ___blog_ser21(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser20(__buffer, __args))
+#define ___blog_ser22(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser21(__buffer, __args))
+#define ___blog_ser23(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser22(__buffer, __args))
+#define ___blog_ser24(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser23(__buffer, __args))
+#define ___blog_ser25(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser24(__buffer, __args))
+#define ___blog_ser26(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser25(__buffer, __args))
+#define ___blog_ser27(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser26(__buffer, __args))
+#define ___blog_ser28(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser27(__buffer, __args))
+#define ___blog_ser29(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser28(__buffer, __args))
+#define ___blog_ser30(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser29(__buffer, __args))
+#define ___blog_ser31(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser30(__buffer, __args))
+#define ___blog_ser32(__buffer, __t, __args...) \
+ (__blog_ser_type(__buffer, __t), ___blog_ser31(__buffer, __args))
+#define ___blog_ser(__buffer, ...) \
+ ___blog_apply(___blog_ser, blog_narg(__VA_ARGS__))(__buffer, ##__VA_ARGS__)
+#define blog_ser(...) ___blog_ser(__VA_ARGS__)
+
+#endif /* _LINUX_CEPH_BLOG_SER_H */
--
2.34.1