[PATCH 07/15] ceph: add Ceph BLOG scaffolding

From: Alex Markuze

Date: Wed Jun 17 2026 - 11:07:20 EST


Wire BLOG into CephFS: ceph_blog.h (journal_info, enter/exit, logging
macros), blog_client.c (per-fsc context lifecycle, client-ID), super.h
(blog_enabled, blog_ctx, debugfs_blog), libceph.h (blog_client_id),
and Makefile (link all BLOG objects into ceph.ko).

Signed-off-by: Alex Markuze <amarkuze@xxxxxxxxxx>
---
fs/ceph/Makefile | 3 +
fs/ceph/blog_client.c | 266 ++++++++++++++++++++++++++++++
fs/ceph/super.h | 5 +
include/linux/ceph/ceph_blog.h | 284 +++++++++++++++++++++++++++++++++
include/linux/ceph/libceph.h | 2 +
5 files changed, 560 insertions(+)
create mode 100644 fs/ceph/blog_client.c
create mode 100644 include/linux/ceph/ceph_blog.h

diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile
index ebb29d11ac22..d1177badef00 100644
--- a/fs/ceph/Makefile
+++ b/fs/ceph/Makefile
@@ -10,6 +10,9 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
mds_client.o mdsmap.o strings.o ceph_frag.o \
debugfs.o util.o metric.o subvolume_metrics.o

+ceph-y += blog_core.o blog_module.o blog_batch.o blog_pagefrag.o blog_des.o
+ceph-y += blog_client.o
+
ceph-$(CONFIG_CEPH_FSCACHE) += cache.o
ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o
ceph-$(CONFIG_FS_ENCRYPTION) += crypto.o
diff --git a/fs/ceph/blog_client.c b/fs/ceph/blog_client.c
new file mode 100644
index 000000000000..be92b97d2903
--- /dev/null
+++ b/fs/ceph/blog_client.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ceph client ID management for BLOG integration
+ *
+ * Maintains mapping between Ceph's fsid/global_id and BLOG client IDs
+ */
+
+#include <linux/ceph/ceph_debug.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/ceph_blog.h>
+#include <linux/ceph/blog.h>
+
+#include "super.h"
+
+/* Global client mapping state */
+static struct {
+ struct ceph_blog_client_info client_map[CEPH_BLOG_MAX_CLIENTS];
+ u32 next_client_id;
+ spinlock_t lock; /* protects client_map */
+ bool initialized;
+} ceph_blog_state = {
+ .next_client_id = 1, /* Start from 1, 0 is reserved */
+ .lock = __SPIN_LOCK_UNLOCKED(ceph_blog_state.lock),
+ .initialized = false,
+};
+
+static bool ceph_blog_ids_match(const struct ceph_blog_client_info *entry,
+ const char *fsid, u64 global_id)
+{
+ if (!entry)
+ return false;
+ if (entry->global_id != global_id)
+ return false;
+ return !memcmp(entry->fsid, fsid, sizeof(entry->fsid));
+}
+
+/**
+ * ceph_blog_init - Initialize Ceph BLOG integration
+ *
+ * Initializes the shared client ID mapping state used by per-superblock
+ * BLOG instances.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int ceph_blog_init(void)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return 0;
+ if (ceph_blog_state.initialized)
+ return 0;
+
+ /* Initialize client mapping state */
+ memset(ceph_blog_state.client_map, 0, sizeof(ceph_blog_state.client_map));
+ ceph_blog_state.next_client_id = 1;
+ ceph_blog_state.initialized = true;
+
+ pr_debug("ceph: BLOG client mapping initialized\n");
+ return 0;
+}
+
+/**
+ * ceph_blog_cleanup - Clean up Ceph BLOG integration
+ *
+ * Cleans up Ceph's module-specific BLOG context and client mappings.
+ */
+void ceph_blog_cleanup(void)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return;
+ if (!ceph_blog_state.initialized)
+ return;
+
+ /* Clean up client mapping state */
+ spin_lock(&ceph_blog_state.lock);
+ memset(ceph_blog_state.client_map, 0, sizeof(ceph_blog_state.client_map));
+ ceph_blog_state.next_client_id = 1;
+ ceph_blog_state.initialized = false;
+ spin_unlock(&ceph_blog_state.lock);
+
+ pr_debug("ceph: BLOG client mapping cleaned up\n");
+}
+
+int ceph_blog_fsc_init(struct ceph_fs_client *fsc)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return 0;
+ if (!fsc)
+ return -EINVAL;
+ if (fsc->blog_ctx)
+ return 0;
+
+ fsc->blog_ctx = blog_module_init("ceph");
+ if (!fsc->blog_ctx) {
+ pr_err("ceph: Failed to initialize BLOG context for fs client\n");
+ return -ENOMEM;
+ }
+
+ WRITE_ONCE(fsc->blog_enabled, false);
+ return 0;
+}
+
+void ceph_blog_fsc_cleanup(struct ceph_fs_client *fsc)
+{
+ if (!IS_ENABLED(CONFIG_DEBUG_FS) || !fsc)
+ return;
+
+ WRITE_ONCE(fsc->blog_enabled, false);
+ if (fsc->blog_ctx) {
+ blog_module_cleanup(fsc->blog_ctx);
+ fsc->blog_ctx = NULL;
+ }
+}
+
+bool ceph_blog_is_enabled(struct ceph_fs_client *fsc)
+{
+ return fsc && READ_ONCE(fsc->blog_enabled) &&
+ fsc->blog_ctx && fsc->blog_ctx->logger;
+}
+
+struct blog_tls_ctx *ceph_blog_acquire_ctx(struct ceph_fs_client *fsc)
+{
+ if (!ceph_blog_is_enabled(fsc))
+ return NULL;
+
+ return blog_get_ctx_ctx(fsc->blog_ctx);
+}
+
+/**
+ * ceph_blog_check_client_id - Check if a client ID matches the given fsid:global_id pair
+ * @id: Client ID to check
+ * @fsid: Client FSID to compare
+ * @global_id: Client global ID to compare
+ *
+ * Returns the actual ID of the pair. If the given ID doesn't match, scans for
+ * existing matches or allocates a new ID if no match is found.
+ *
+ * Return: Client ID for this fsid/global_id pair
+ */
+u32 ceph_blog_check_client_id(u32 id, const char *fsid, u64 global_id)
+{
+ u32 found_id = 0;
+ struct ceph_blog_client_info *entry;
+
+ if (unlikely(!ceph_blog_state.initialized)) {
+ WARN_ON_ONCE(1); /* Should never happen - init_ceph() initializes BLOG */
+ return 0; /* Drop the log entry */
+ }
+
+ spin_lock(&ceph_blog_state.lock);
+
+ /* Reuse caller-provided hint when it still matches */
+ if (id != 0 && id < CEPH_BLOG_MAX_CLIENTS) {
+ entry = &ceph_blog_state.client_map[id];
+ if (ceph_blog_ids_match(entry, fsid, global_id)) {
+ found_id = id;
+ goto out;
+ }
+ }
+
+ /* Search for an existing entry with matching identity */
+ for (id = 1; id < CEPH_BLOG_MAX_CLIENTS; id++) {
+ entry = &ceph_blog_state.client_map[id];
+ if (ceph_blog_ids_match(entry, fsid, global_id)) {
+ found_id = id;
+ goto out;
+ }
+ }
+
+ /* Assign new identifier; refuse on overflow rather than aliasing */
+ if (ceph_blog_state.next_client_id >= CEPH_BLOG_MAX_CLIENTS - 1) {
+ pr_warn_once("ceph: BLOG client ID space exhausted\n");
+ found_id = 0;
+ goto out;
+ }
+
+ found_id = ceph_blog_state.next_client_id++;
+ entry = &ceph_blog_state.client_map[found_id];
+ memset(entry, 0, sizeof(*entry));
+ memcpy(entry->fsid, fsid, sizeof(entry->fsid));
+ entry->global_id = global_id;
+
+out:
+ spin_unlock(&ceph_blog_state.lock);
+ return found_id;
+}
+
+/**
+ * ceph_blog_get_client_info - Get client info for a given ID
+ * @id: Client ID
+ *
+ * Reads client_map[] without holding ceph_blog_state.lock.
+ * Writers store fields under the lock. Callers accept the benign
+ * race: a torn read may see a partially-updated fsid or global_id,
+ * which only affects the cosmetic prefix in deserialized output.
+ *
+ * Return: Client information for this ID, or NULL if invalid
+ */
+const struct ceph_blog_client_info *ceph_blog_get_client_info(u32 id)
+{
+ if (!READ_ONCE(ceph_blog_state.initialized) ||
+ id == 0 || id >= CEPH_BLOG_MAX_CLIENTS)
+ return NULL;
+ return &ceph_blog_state.client_map[id];
+}
+
+/**
+ * ceph_blog_client_des_callback - Deserialization callback for Ceph client info
+ * @buf: Output buffer
+ * @size: Buffer size
+ * @client_id: Client ID to deserialize
+ *
+ * This is the callback that BLOG will use to deserialize client information.
+ *
+ * Return: Number of bytes written to buffer
+ */
+int ceph_blog_client_des_callback(char *buf, size_t size, u8 client_id)
+{
+ const struct ceph_blog_client_info *info;
+
+ if (!buf || !size)
+ return -EINVAL;
+ if (client_id == 0)
+ return 0;
+
+ info = ceph_blog_get_client_info(client_id);
+ if (!info)
+ return snprintf(buf, size, "[unknown_client_%u]", client_id);
+
+ /* Use %pU to format fsid, matching boutc and other Ceph client logging */
+ return snprintf(buf, size, "[%pU %llu] ",
+ info->fsid, info->global_id);
+}
+
+/**
+ * ceph_blog_get_client_id - Get or allocate client ID for a Ceph client
+ * @client: Ceph client structure
+ *
+ * Return: Client ID for this client
+ */
+u32 ceph_blog_get_client_id(struct ceph_client *client)
+{
+ u32 cached;
+ u32 id;
+
+ if (!client)
+ return 0;
+ if (!client->monc.auth)
+ return 0;
+
+ cached = READ_ONCE(client->blog_client_id);
+
+ id = ceph_blog_check_client_id(cached,
+ client->fsid.fsid,
+ client->monc.auth->global_id);
+ if (!id)
+ return 0;
+
+ if (READ_ONCE(client->blog_client_id) != id)
+ WRITE_ONCE(client->blog_client_id, id);
+
+ return id;
+}
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 1d6aab060780..ecb72c482d0e 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -3,6 +3,7 @@
#define _FS_CEPH_SUPER_H

#include <linux/ceph/ceph_debug.h>
+#include <linux/ceph/ceph_blog.h>
#include <linux/ceph/osd_client.h>

#include <linux/unaligned.h>
@@ -154,6 +155,7 @@ struct ceph_fs_client {
int mount_state;

bool blocklisted;
+ bool blog_enabled;

bool have_copy_from2;

@@ -171,6 +173,8 @@ struct ceph_fs_client {
DECLARE_HASHTABLE(async_unlink_conflict, CEPH_ASYNC_CREATE_CONFLICT_BITS);
spinlock_t async_unlink_conflict_lock;

+ struct blog_module_context *blog_ctx;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dentry_lru, *debugfs_caps;
struct dentry *debugfs_congestion_kb;
@@ -180,6 +184,7 @@ struct ceph_fs_client {
struct dentry *debugfs_mds_sessions;
struct dentry *debugfs_metrics_dir;
struct dentry *debugfs_reset_dir;
+ struct dentry *debugfs_blog;
struct dentry *debugfs_subvolume_metrics;
#endif

diff --git a/include/linux/ceph/ceph_blog.h b/include/linux/ceph/ceph_blog.h
new file mode 100644
index 000000000000..29df4f662a2f
--- /dev/null
+++ b/include/linux/ceph/ceph_blog.h
@@ -0,0 +1,284 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Ceph integration with BLOG (Binary LOGging)
+ *
+ * Provides a shared per-call context (struct ceph_journal_info) cached
+ * in current->journal_info that carries both the BLOG TLS context and
+ * the MDS request pointer used by the xattr / security-label paths.
+ */
+#ifndef CEPH_BLOG_H
+#define CEPH_BLOG_H
+
+#include <linux/ceph/blog.h>
+#include <linux/ceph/blog_module.h>
+#include <linux/ceph/libceph.h>
+
+/* ---------- shared journal_info carrier ---------- */
+
+#define CEPH_JI_MAGIC 0xCE9B7081UL
+
+struct ceph_fs_client;
+
+/**
+ * struct ceph_journal_info - per-call context stashed in journal_info
+ * @magic: CEPH_JI_MAGIC, for safe type-checking when reading journal_info
+ * @saved_ji: previous value of current->journal_info (restored on exit)
+ * @blog_ctx: BLOG TLS context for binary logging, or NULL
+ * @mds_req: MDS request during ceph_fill_trace / readdir_prepopulate,
+ * or NULL. Read by xattr.c to avoid deadlocking RPCs and
+ * to discover which capabilities were already fetched.
+ *
+ * Allocated on the caller's stack at every Ceph VFS entry point.
+ * ceph_blog_enter() installs it in current->journal_info;
+ * ceph_blog_exit() restores the previous value.
+ */
+struct ceph_journal_info {
+ unsigned long magic;
+ void *saved_ji;
+ struct ceph_fs_client *fsc;
+ struct blog_tls_ctx *blog_ctx;
+ struct ceph_mds_request *mds_req;
+};
+
+/**
+ * ceph_ji_from_current - safely retrieve ceph_journal_info from journal_info
+ *
+ * Returns the ceph_journal_info pointer if journal_info currently holds
+ * one (magic matches), NULL otherwise.
+ */
+static inline struct ceph_journal_info *ceph_ji_from_current(void)
+{
+ struct ceph_journal_info *ji = current->journal_info;
+
+ if (ji && READ_ONCE(ji->magic) == CEPH_JI_MAGIC)
+ return ji;
+ return NULL;
+}
+
+static inline bool ceph_ji_matches_fsc(const struct ceph_journal_info *ji,
+ struct ceph_fs_client *fsc)
+{
+ return ji && ji->fsc == fsc;
+}
+
+/**
+ * ceph_current_mds_request - get the in-flight MDS request, if any
+ *
+ * Used by xattr.c to detect whether we are inside ceph_fill_trace()
+ * and to inspect the request's capability mask. Returns NULL when
+ * called outside that window.
+ */
+static inline struct ceph_mds_request *
+ceph_current_mds_request(struct ceph_fs_client *fsc)
+{
+ struct ceph_journal_info *ji = ceph_ji_from_current();
+
+ return ceph_ji_matches_fsc(ji, fsc) ? ji->mds_req : NULL;
+}
+
+/* ---------- client ID mapping ---------- */
+
+struct ceph_blog_client_info {
+ char fsid[16];
+ u64 global_id;
+};
+
+#define CEPH_BLOG_MAX_CLIENTS 256
+
+struct ceph_client;
+struct ceph_fs_client;
+
+#if IS_ENABLED(CONFIG_CEPH_FS)
+
+int ceph_blog_init(void);
+void ceph_blog_cleanup(void);
+int ceph_blog_fsc_init(struct ceph_fs_client *fsc);
+void ceph_blog_fsc_cleanup(struct ceph_fs_client *fsc);
+u32 ceph_blog_check_client_id(u32 id, const char *fsid, u64 global_id);
+u32 ceph_blog_get_client_id(struct ceph_client *client);
+const struct ceph_blog_client_info *ceph_blog_get_client_info(u32 id);
+int ceph_blog_client_des_callback(char *buf, size_t size, u8 client_id);
+bool ceph_blog_is_enabled(struct ceph_fs_client *fsc);
+struct blog_tls_ctx *ceph_blog_acquire_ctx(struct ceph_fs_client *fsc);
+
+/* ---------- entry / exit helpers ---------- */
+
+/**
+ * ceph_blog_enter - call at every Ceph VFS entry point
+ * @fsc: CephFS client that owns this VFS operation
+ * @ji: caller-allocated struct ceph_journal_info (typically on the stack)
+ *
+ * Saves the current journal_info, inherits any active Ceph request
+ * state from the parent frame, and installs @ji as journal_info.
+ * When BLOG tracing is enabled, the outermost Ceph entry acquires and
+ * caches the BLOG context for nested bout()/boutc() callsites.
+ */
+static inline void ceph_blog_enter(struct ceph_fs_client *fsc,
+ struct ceph_journal_info *ji)
+{
+ struct ceph_journal_info *parent = ceph_ji_from_current();
+
+ ji->magic = CEPH_JI_MAGIC;
+ ji->saved_ji = current->journal_info;
+ ji->fsc = fsc;
+ ji->mds_req = ceph_ji_matches_fsc(parent, fsc) ? parent->mds_req : NULL;
+ ji->blog_ctx = ceph_ji_matches_fsc(parent, fsc) ? parent->blog_ctx : NULL;
+
+ if (!ji->blog_ctx && ceph_blog_is_enabled(fsc))
+ ji->blog_ctx = ceph_blog_acquire_ctx(fsc);
+
+ current->journal_info = ji;
+}
+
+/**
+ * ceph_blog_exit - call at every Ceph VFS exit point
+ * @ji: the same struct passed to ceph_blog_enter()
+ */
+static inline void ceph_blog_exit(struct ceph_journal_info *ji)
+{
+ current->journal_info = ji->saved_ji;
+}
+
+/* ---------- cached-context accessor for boutc hot path ---------- */
+
+static inline struct blog_tls_ctx *ceph_blog_get_cached_ctx(void)
+{
+ struct ceph_journal_info *ji = ceph_ji_from_current();
+
+ if (!ji || !ceph_blog_is_enabled(ji->fsc))
+ return NULL;
+ return ji->blog_ctx;
+}
+
+/* ---------- logging macros ---------- */
+
+#define CEPH_BLOG_LOG(fmt, ...) \
+ do { \
+ static struct blog_source_id_cache __source_cache; \
+ size_t __size = blog_cnt(__VA_ARGS__); \
+ struct blog_tls_ctx *__ctx; \
+ struct blog_logger *__logger; \
+ void *___buffer; \
+ u32 __sid; \
+ __ctx = ceph_blog_get_cached_ctx(); \
+ if (unlikely(!__ctx)) \
+ break; \
+ __logger = __ctx->logger; \
+ if (unlikely(!__logger)) \
+ break; \
+ __sid = blog_get_source_id_cached(__logger, &__source_cache, \
+ kbasename(__FILE__), __func__, \
+ __LINE__, fmt); \
+ if (unlikely(__sid == 0)) { \
+ WRITE_ONCE(__source_cache.logger, NULL); \
+ WRITE_ONCE(__source_cache.id, 0); \
+ break; \
+ } \
+ ___buffer = blog_log_with_ctx(__logger, __ctx, \
+ __sid, 0, __size); \
+ if (likely(___buffer)) { \
+ void *___tmp = ___buffer; \
+ if (__size > 0) { \
+ blog_ser(___buffer, ##__VA_ARGS__); \
+ } \
+ blog_log_commit_with_ctx(__logger, __ctx, \
+ ___buffer - ___tmp); \
+ } \
+ } while (0)
+
+#define CEPH_BLOG_LOG_CLIENT(client, fmt, ...) \
+ do { \
+ static struct blog_source_id_cache __source_cache; \
+ size_t __size = blog_cnt(__VA_ARGS__); \
+ struct blog_tls_ctx *__ctx; \
+ struct blog_logger *__logger; \
+ void *___buffer; \
+ u32 __client_id; \
+ u32 __sid; \
+ __ctx = ceph_blog_get_cached_ctx(); \
+ if (unlikely(!__ctx)) \
+ break; \
+ __logger = __ctx->logger; \
+ if (unlikely(!__logger)) \
+ break; \
+ __sid = blog_get_source_id_cached(__logger, &__source_cache, \
+ kbasename(__FILE__), __func__, \
+ __LINE__, fmt); \
+ if (unlikely(__sid == 0)) { \
+ WRITE_ONCE(__source_cache.logger, NULL); \
+ WRITE_ONCE(__source_cache.id, 0); \
+ break; \
+ } \
+ __client_id = ceph_blog_get_client_id(client); \
+ ___buffer = blog_log_with_ctx(__logger, __ctx, \
+ __sid, __client_id, __size); \
+ if (likely(___buffer)) { \
+ void *___tmp = ___buffer; \
+ if (__size > 0) { \
+ blog_ser(___buffer, ##__VA_ARGS__); \
+ } \
+ blog_log_commit_with_ctx(__logger, __ctx, \
+ ___buffer - ___tmp); \
+ } \
+ } while (0)
+
+#else /* !CONFIG_CEPH_FS */
+
+#define CEPH_BLOG_LOG(fmt, ...) do {} while (0)
+#define CEPH_BLOG_LOG_CLIENT(client, fmt, ...) do {} while (0)
+
+static inline int ceph_blog_init(void) { return 0; }
+static inline void ceph_blog_cleanup(void) { }
+static inline int ceph_blog_fsc_init(struct ceph_fs_client *fsc) { return 0; }
+static inline void ceph_blog_fsc_cleanup(struct ceph_fs_client *fsc) {}
+static inline u32 ceph_blog_get_client_id(struct ceph_client *c) { return 0; }
+static inline u32 ceph_blog_check_client_id(u32 id, const char *fsid,
+ u64 global_id) { return 0; }
+static inline const struct ceph_blog_client_info *
+ceph_blog_get_client_info(u32 id) { return NULL; }
+static inline int ceph_blog_client_des_callback(char *buf, size_t size,
+ u8 client_id) { return 0; }
+static inline bool ceph_blog_is_enabled(struct ceph_fs_client *fsc) { return false; }
+static inline struct blog_tls_ctx *
+ceph_blog_acquire_ctx(struct ceph_fs_client *fsc) { return NULL; }
+
+/*
+ * When BLOG is disabled, ceph_blog_enter/exit still install the
+ * ceph_journal_info so that the mds_req path works unconditionally.
+ */
+static inline void ceph_blog_enter(struct ceph_fs_client *fsc,
+ struct ceph_journal_info *ji)
+{
+ struct ceph_journal_info *parent = ceph_ji_from_current();
+
+ ji->magic = CEPH_JI_MAGIC;
+ ji->saved_ji = current->journal_info;
+ ji->fsc = fsc;
+ ji->mds_req = ceph_ji_matches_fsc(parent, fsc) ? parent->mds_req : NULL;
+ ji->blog_ctx = NULL;
+ current->journal_info = ji;
+}
+
+static inline void ceph_blog_exit(struct ceph_journal_info *ji)
+{
+ current->journal_info = ji->saved_ji;
+}
+
+static inline struct blog_tls_ctx *ceph_blog_get_cached_ctx(void)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_CEPH_FS */
+
+/* ---------- debugfs ---------- */
+
+#ifdef CONFIG_DEBUG_FS
+int ceph_blog_debugfs_init(struct ceph_fs_client *fsc);
+void ceph_blog_debugfs_cleanup(struct ceph_fs_client *fsc);
+#else
+static inline int ceph_blog_debugfs_init(struct ceph_fs_client *fsc) { return 0; }
+static inline void ceph_blog_debugfs_cleanup(struct ceph_fs_client *fsc) {}
+#endif
+
+#endif /* CEPH_BLOG_H */
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 63e0e2aa1ce9..f853836be298 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -133,6 +133,8 @@ struct ceph_client {
struct ceph_mon_client monc;
struct ceph_osd_client osdc;

+ u32 blog_client_id;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dir;
struct dentry *debugfs_monmap;
--
2.34.1