linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
To: "linux-mm@kvack.org" <linux-mm@kvack.org>,
	Alex Markuze <amarkuze@redhat.com>,
	"ceph-devel@vger.kernel.org" <ceph-devel@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Cc: "dietmar.eggemann@arm.com" <dietmar.eggemann@arm.com>,
	"rppt@kernel.org" <rppt@kernel.org>,
	"lorenzo.stoakes@oracle.com" <lorenzo.stoakes@oracle.com>,
	Xiubo Li <xiubli@redhat.com>,
	"idryomov@gmail.com" <idryomov@gmail.com>,
	"david@redhat.com" <david@redhat.com>,
	"mgorman@suse.de" <mgorman@suse.de>,
	"vbabka@suse.cz" <vbabka@suse.cz>,
	"vincent.guittot@linaro.org" <vincent.guittot@linaro.org>,
	"akpm@linux-foundation.org" <akpm@linux-foundation.org>,
	"Liam.Howlett@oracle.com" <Liam.Howlett@oracle.com>,
	Ingo Molnar <mingo@redhat.com>,
	"rostedt@goodmis.org" <rostedt@goodmis.org>,
	"surenb@google.com" <surenb@google.com>,
	Valentin Schneider <vschneid@redhat.com>,
	"kees@kernel.org" <kees@kernel.org>,
	"peterz@infradead.org" <peterz@infradead.org>,
	"mhocko@suse.com" <mhocko@suse.com>,
	"bsegall@google.com" <bsegall@google.com>,
	"juri.lelli@redhat.com" <juri.lelli@redhat.com>
Subject: Re:  [RFC PATCH 3/5] ceph: Add BLOG scaffolding
Date: Mon, 3 Nov 2025 22:37:15 +0000	[thread overview]
Message-ID: <b6d9c32721a5b836a84945232d98aab1d15e3638.camel@ibm.com> (raw)
In-Reply-To: <20251024084259.2359693-4-amarkuze@redhat.com>

On Fri, 2025-10-24 at 08:42 +0000, Alex Markuze wrote:
> Introduce the Ceph BLOG integration layer that enables the filesystem to
> register binary loggers and route log events through module-specific TLS
> contexts. This commit establishes the infrastructure for high-performance
> binary logging in the Ceph client without modifying existing logging calls.
> 

Frankly speaking, the kernel subsystems' integration logic requires a lot of
code. I expected that it will be much easier to integrate the BLOG
infrastructure into a particular kernel subsystem. Is it possible to move
majority of the functionality into the generalized BLOG infrastructure? I
believe that everyone will love really simple integration logic.

Thanks,
Slava. 

> **Key Components:**
> 
> **ceph_blog.h - BLOG-aware macros and interfaces:**
> - bout/boutc: Drop-in replacements for dout/doutc with identical semantics
> - CEPH_BLOG_LOG_CTX/CEPH_BLOG_LOG: Low-level logging primitives
> - Automatic fallback to traditional dout when CONFIG_BLOG is disabled
> - Type-safe parameter serialization using BLOG framework
> 
> **blog_client.c - Module registration and context management:**
> - ceph_blog_init(): Register Ceph-specific BLOG logger on module load
> - ceph_blog_exit(): Cleanup and unregister logger on module unload
> - ceph_get_tls_ctx(): Acquire per-task BLOG context for current thread
> - Client-ID to logger mapping for multi-client scenarios
> - Exported symbols for context acquisition from Ceph code paths
> 
> **Makefile integration:**
> - Conditionally build blog_client.o when CONFIG_CEPH_FS && CONFIG_BLOG
> - Clean integration with existing Ceph build system
> 
> **Design rationale:**
> The bout/boutc macros maintain the same call-site syntax as dout/doutc,
> allowing gradual migration and easy A/B testing. Log levels and subsystem
> filtering remain unchanged. The TLS context is acquired lazily on first use
> per task and recycled automatically on task exit via the BLOG lifecycle
> hooks wired in earlier commits.
> 
> No existing Ceph logging is modified in this commit. The infrastructure is
> in place but inactive until logging call sites are converted to bout/boutc
> in subsequent commits.
> 
> Signed-off-by: Alex Markuze <amarkuze@redhat.com>
> ---
>  fs/ceph/Makefile               |   2 +
>  fs/ceph/blog_client.c          | 244 +++++++++++++++++++++++++++++++++
>  include/linux/ceph/ceph_blog.h | 124 +++++++++++++++++
>  3 files changed, 370 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 1f77ca04c426..ccb542870ab3 100644
> --- a/fs/ceph/Makefile
> +++ b/fs/ceph/Makefile
> @@ -10,6 +10,8 @@ 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
>  
> +ceph-$(CONFIG_BLOG) += blog_client.o blog_debugfs.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..2d9c7e37f918
> --- /dev/null
> +++ b/fs/ceph/blog_client.c
> @@ -0,0 +1,244 @@
> +// 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/module.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +#include <linux/ceph/ceph_debug.h>
> +#include <linux/ceph/libceph.h>
> +#include <linux/ceph/ceph_blog.h>
> +#include <linux/blog/blog.h>
> +
> +/* Ceph's BLOG module context */
> +struct blog_module_context *ceph_blog_ctx;
> +EXPORT_SYMBOL(ceph_blog_ctx);
> +
> +/* Ceph's logger - direct access to the logger from module context */
> +struct blog_logger *ceph_logger;
> +EXPORT_SYMBOL(ceph_logger);
> +
> +/* 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
> + *
> + * Creates a module-specific BLOG context for Ceph and initializes
> + * the client ID mapping state.
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int ceph_blog_init(void)
> +{
> +	if (ceph_blog_state.initialized)
> +		return 0;
> +
> +	/* Create Ceph's module-specific BLOG context */
> +	ceph_blog_ctx = blog_module_init("ceph");
> +	if (!ceph_blog_ctx) {
> +		pr_err("ceph: Failed to initialize BLOG module context\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Set ceph_logger for direct access to the logger */
> +	ceph_logger = ceph_blog_ctx->logger;
> +
> +	/* 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_info("ceph: BLOG module context and client mapping initialized\n");
> +	return 0;
> +}
> +EXPORT_SYMBOL(ceph_blog_init);
> +
> +/**
> + * 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 (!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);
> +
> +	/* Clean up module-specific BLOG context */
> +	if (ceph_blog_ctx) {
> +		blog_module_cleanup(ceph_blog_ctx);
> +		ceph_blog_ctx = NULL;
> +		ceph_logger = NULL;
> +	}
> +
> +	pr_info("ceph: BLOG module context and client mapping cleaned up\n");
> +}
> +EXPORT_SYMBOL(ceph_blog_cleanup);
> +
> +/**
> + * 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
> + *
> + * This preserves the exact functionality of ceph_san_check_client_id.
> + * 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, falling back to overflow slot if exhausted */
> +	if (ceph_blog_state.next_client_id >= CEPH_BLOG_MAX_CLIENTS - 1) {
> +		found_id = CEPH_BLOG_MAX_CLIENTS - 1;
> +		entry = &ceph_blog_state.client_map[found_id];
> +	} else {
> +		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;
> +
> +	pr_info("ceph: allocating new BLOG client ID %u for fsid=%pU global_id=%llu\n",
> +		found_id, fsid, global_id);
> +
> +out:
> +	spin_unlock(&ceph_blog_state.lock);
> +	return found_id;
> +}
> +EXPORT_SYMBOL(ceph_blog_check_client_id);
> +
> +/**
> + * ceph_blog_get_client_info - Get client info for a given ID
> + * @id: Client ID
> + *
> + * Return: Client information for this ID, or NULL if invalid
> + */
> +const struct ceph_blog_client_info *ceph_blog_get_client_info(u32 id)
> +{
> +	if (!ceph_blog_state.initialized || id == 0 || id >= CEPH_BLOG_MAX_CLIENTS)
> +		return NULL;
> +	return &ceph_blog_state.client_map[id];
> +}
> +EXPORT_SYMBOL(ceph_blog_get_client_info);
> +
> +/**
> + * 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;
> +
> +	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);
> +}
> +EXPORT_SYMBOL(ceph_blog_client_des_callback);
> +
> +/**
> + * 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 = 0;
> +	u32 id;
> +
> +	if (!client)
> +		return 0;
> +
> +#ifdef CONFIG_BLOG
> +	cached = READ_ONCE(client->blog_client_id);
> +#endif
> +
> +	id = ceph_blog_check_client_id(cached,
> +					 client->fsid.fsid,
> +					 client->monc.auth->global_id);
> +	if (!id)
> +		return 0;
> +
> +#ifdef CONFIG_BLOG
> +	if (READ_ONCE(client->blog_client_id) != id)
> +		WRITE_ONCE(client->blog_client_id, id);
> +#endif
> +
> +	return id;
> +}
> +EXPORT_SYMBOL(ceph_blog_get_client_id);
> diff --git a/include/linux/ceph/ceph_blog.h b/include/linux/ceph/ceph_blog.h
> new file mode 100644
> index 000000000000..0591e3f29703
> --- /dev/null
> +++ b/include/linux/ceph/ceph_blog.h
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Ceph integration with BLOG (Binary LOGging)
> + *
> + * Provides compatibility layer and Ceph-specific extensions
> + */
> +#ifndef CEPH_BLOG_H
> +#define CEPH_BLOG_H
> +
> +#include <linux/blog/blog.h>
> +#include <linux/blog/blog_module.h>
> +#include <linux/ceph/libceph.h>
> +
> +/* Client ID mapping structure - preserves ceph_san_client_id fields */
> +struct ceph_blog_client_info {
> +	char fsid[16];         /* Client FSID */
> +	u64 global_id;         /* Client global ID */
> +};
> +
> +/* Constants */
> +#define CEPH_BLOG_MAX_CLIENTS 256
> +
> +/* Ceph's BLOG module context */
> +extern struct blog_module_context *ceph_blog_ctx;
> +
> +/* Ceph's logger - direct access to the logger for macros */
> +extern struct blog_logger *ceph_logger;
> +
> +/* Forward declaration for ceph_client */
> +struct ceph_client;
> +
> +/* Compatibility macros for easy migration from ceph_san to BLOG */
> +#if IS_ENABLED(CONFIG_BLOG)
> +
> +/* Ceph BLOG client management functions */
> +int ceph_blog_init(void);
> +void ceph_blog_cleanup(void);
> +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);
> +
> +/*
> + * All ceph_san compatibility removed - use only BLOG with per-module contexts
> + * CEPH_SAN has been replaced entirely by BLOG per-module logging
> + */
> +
> +/*
> + * Ceph-specific logging macros - use core BLOG functions with ceph_logger
> + * Note: Only client-aware macros (doutc, boutc) store client_id,
> + * regular macros (dout, bout) do not include client information
> + */
> +#define CEPH_BLOG_LOG(fmt, ...) \
> +	do { \
> +		static u32 __source_id; \
> +		static size_t __size; \
> +		void *___buffer = NULL; \
> +		if (unlikely(!ceph_logger)) \
> +			break; \
> +		if (unlikely(__source_id == 0)) { \
> +			__source_id = blog_get_source_id(ceph_logger, \
> +				kbasename(__FILE__), __func__, __LINE__, fmt); \
> +			__size = blog_cnt(__VA_ARGS__); \
> +		} \
> +		___buffer = blog_log(ceph_logger, __source_id, 0, __size); \
> +		if (likely(___buffer)) { \
> +			void *___tmp = ___buffer; \
> +			if (__size > 0) \
> +				blog_ser(___buffer, ##__VA_ARGS__); \
> +			blog_log_commit(ceph_logger, ___buffer - ___tmp); \
> +		} \
> +	} while (0)
> +
> +#define CEPH_BLOG_LOG_CLIENT(client, fmt, ...) \
> +	do { \
> +		static u32 __source_id; \
> +		static size_t __size; \
> +		void *___buffer = NULL; \
> +		u32 __client_id; \
> +		if (unlikely(!ceph_logger)) \
> +			break; \
> +		if (unlikely(__source_id == 0)) { \
> +			__source_id = blog_get_source_id(ceph_logger, \
> +				kbasename(__FILE__), __func__, __LINE__, fmt); \
> +			__size = blog_cnt(__VA_ARGS__); \
> +		} \
> +		__client_id = ceph_blog_get_client_id(client); \
> +		___buffer = blog_log(ceph_logger, __source_id, __client_id, __size); \
> +		if (likely(___buffer)) { \
> +			void *___tmp = ___buffer; \
> +			if (__size > 0) \
> +				blog_ser(___buffer, ##__VA_ARGS__); \
> +			blog_log_commit(ceph_logger, ___buffer - ___tmp); \
> +		} \
> +	} while (0)
> +
> +/* No legacy ceph_san compatibility - use CEPH_BLOG_LOG* macros only */
> +
> +#else /* !CONFIG_BLOG */
> +
> +/* Stub macros when BLOG is not enabled */
> +#define CEPH_BLOG_LOG(fmt, ...) do {} while (0)
> +#define CEPH_BLOG_LOG_CLIENT(client, fmt, ...) do {} while (0)
> +
> +/* Stub functions should be static inline, not macros */
> +static inline int ceph_blog_init(void) { return 0; }
> +static inline void ceph_blog_cleanup(void) { }
> +static inline u32 ceph_blog_get_client_id(struct ceph_client *client) { 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; }
> +
> +#endif /* CONFIG_BLOG */
> +
> +/* Debugfs support */
> +#ifdef CONFIG_DEBUG_FS
> +int ceph_blog_debugfs_init(struct dentry *parent);
> +void ceph_blog_debugfs_cleanup(void);
> +#else
> +static inline int ceph_blog_debugfs_init(struct dentry *parent) { return 0; }
> +static inline void ceph_blog_debugfs_cleanup(void) {}
> +#endif
> +
> +#endif /* CEPH_BLOG_H */

  reply	other threads:[~2025-11-03 22:37 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-24  8:42 [RFC PATCH 0/5] BLOG: per-task logging contexts with Ceph consumer Alex Markuze
2025-10-24  8:42 ` [RFC PATCH 1/5] sched, fork: Wire BLOG contexts into task lifecycle Alex Markuze
2025-10-24 17:44   ` Steven Rostedt
2025-10-29 18:57   ` Viacheslav Dubeyko
2025-10-24  8:42 ` [RFC PATCH 2/5] lib: Introduce BLOG (Binary LOGging) subsystem Alex Markuze
2025-10-30 18:47   ` Viacheslav Dubeyko
2025-10-24  8:42 ` [RFC PATCH 3/5] ceph: Add BLOG scaffolding Alex Markuze
2025-11-03 22:37   ` Viacheslav Dubeyko [this message]
2025-10-24  8:42 ` [RFC PATCH 4/5] ceph: Add BLOG debugfs support Alex Markuze
2025-11-03 21:07   ` Viacheslav Dubeyko
2025-10-24  8:42 ` [RFC PATCH 5/5] ceph: Activate BLOG logging Alex Markuze
2025-11-03 21:00   ` Viacheslav Dubeyko
2025-10-24 15:32 ` [RFC PATCH 0/5] BLOG: per-task logging contexts with Ceph consumer David Hildenbrand
2025-10-24 17:53 ` Steven Rostedt
2025-10-25 10:50   ` Alex Markuze
2025-10-25 14:59     ` Steven Rostedt
2025-10-25 17:54       ` Alex Markuze
2025-10-27 14:54         ` Steven Rostedt
2025-10-28 17:07 ` Viacheslav Dubeyko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b6d9c32721a5b836a84945232d98aab1d15e3638.camel@ibm.com \
    --to=slava.dubeyko@ibm.com \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=amarkuze@redhat.com \
    --cc=bsegall@google.com \
    --cc=ceph-devel@vger.kernel.org \
    --cc=david@redhat.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=idryomov@gmail.com \
    --cc=juri.lelli@redhat.com \
    --cc=kees@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=mgorman@suse.de \
    --cc=mhocko@suse.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=rppt@kernel.org \
    --cc=surenb@google.com \
    --cc=vbabka@suse.cz \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    --cc=xiubli@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).