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

Alex Markuze <[email protected]> Mon, 6 Jul 2026 14:38:35 +0000
Newsgroups org.kernel.vger.ceph-devel
Message-ID <[email protected]>
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 <[email protected]>
---
 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