Re: [PATCH v2 04/15] ceph: add BLOG magazine batch allocator

Xiubo Li <[email protected]> Tue, 14 Jul 2026 12:08:50 +0800
Newsgroups org.kernel.vger.ceph-devel
Message-ID <CAOJNxRK+Y8LwbiccNtF=n-+wKPEz3ap2tLNT8fiRXmVkUNVQgQ@mail.gmail.com>
On Mon, 6 Jul 2026 at 22:38, Alex Markuze <[email protected]> wrote:
>
> Add blog_batch.c: per-CPU magazine batching for TLS context recycling.
> Freed composites go to a local magazine; subsequent acquisitions reclaim
> from the magazine, making the common-case log path allocation-free.
>
> Signed-off-by: Alex Markuze <[email protected]>
> ---
>  fs/ceph/blog_batch.c | 312 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 312 insertions(+)
>  create mode 100644 fs/ceph/blog_batch.c
>
> diff --git a/fs/ceph/blog_batch.c b/fs/ceph/blog_batch.c
> new file mode 100644
> index 000000000000..6daf853b8201
> --- /dev/null
> +++ b/fs/ceph/blog_batch.c
> @@ -0,0 +1,312 @@

[......]

> +/**
> + * blog_batch_init - Initialize the batching system
> + * @batch: Batch structure to initialize
> + * @mag_cache: Slab cache for magazine structs, or NULL to create one
> + * @nr_prealloc: Number of composites to preallocate (0 = none)
> + * @retain_limit: Max composites to retain on put; excess are freed (0 = unlimited)
> + *
> + * Allocates and initializes the per-CPU magazines and global pools.
> + * Composites are allocated via alloc_pages() in BLOG_MAGAZINE_SIZE
> + * batches.  Pass nr_prealloc = 0 for batches that start empty
> + * (e.g. the log_batch).
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int blog_batch_init(struct blog_batch *batch, struct kmem_cache *mag_cache,
> +                   unsigned int nr_prealloc, unsigned int retain_limit)
> +{
> +       unsigned int nr_mags, i, j;
> +       int cpu;
> +       struct blog_cpu_magazine *cpu_mag;
> +       struct blog_magazine *mag;
> +       struct blog_tls_pagefrag *composite;
> +       struct page *pages;
> +
> +       /* Initialize counters */
> +       batch->nr_full = 0;
> +       batch->nr_empty = 0;

Possibly the aboe initializaion code is not needed since the logger is
allocated by kzalloc() ?

> +       batch->retain_limit = retain_limit;
> +
> +       /* Use caller-provided cache or create one */
> +       if (mag_cache) {
> +               batch->magazine_cache = mag_cache;
> +               batch->external_cache = true;

[......]

> +/**
> + * blog_batch_cleanup - Clean up the batching system
> + * @batch: Batch structure to clean up
> + *
> + * Frees all magazines and composites, and destroys the magazine cache.
> + */
> +void blog_batch_cleanup(struct blog_batch *batch)
> +{
> +       int cpu;
> +       struct blog_magazine *mag, *tmp;
> +       struct blog_cpu_magazine *cpu_mag;
> +
> +       /* Free per-CPU magazines */
> +       if (batch->cpu_magazines) {
> +               for_each_possible_cpu(cpu) {
> +                       cpu_mag = per_cpu_ptr(batch->cpu_magazines, cpu);
> +                       if (cpu_mag->mag)
> +                               free_magazine(batch, cpu_mag->mag);
> +               }
> +               free_percpu(batch->cpu_magazines);
> +       }
> +
> +       /* Free magazines in the full pool */
> +       spin_lock(&batch->full_lock);

Is the lock needed in cleanup ?

> +       list_for_each_entry_safe(mag, tmp, &batch->full_magazines, list) {
> +               list_del(&mag->list);
> +               batch->nr_full--;
> +               free_magazine(batch, mag);
> +       }
> +       spin_unlock(&batch->full_lock);
> +
> +       /* Free magazines in the empty pool */
> +       spin_lock(&batch->empty_lock);
> +       list_for_each_entry_safe(mag, tmp, &batch->empty_magazines, list) {
> +               list_del(&mag->list);
> +               batch->nr_empty--;
> +               free_magazine(batch, mag);
> +       }
> +       spin_unlock(&batch->empty_lock);
> +
> +       /* Destroy magazine cache */
> +       if (!batch->external_cache && batch->magazine_cache)
> +               kmem_cache_destroy(batch->magazine_cache);
> +
> +       batch->magazine_cache = NULL;
> +       batch->external_cache = false;
> +}
> +
> +/**


[......]