[PATCH v3 03/14] ceph: add BLOG page-fragment allocator

Alex Markuze <[email protected]>
Newsgroups org.kernel.vger.ceph-devel
Message-ID <2be13f3f5bdc2e349ff75fcdeeda2f16ef375dde.1787229471.git.amarkuze@redhat.com>
Add blog_pagefrag.c: lockless page-fragment buffer allocator for
per-task BLOG contexts.

Signed-off-by: Alex Markuze <[email protected]>
---
 fs/ceph/blog_pagefrag.c | 84 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 fs/ceph/blog_pagefrag.c

diff --git a/fs/ceph/blog_pagefrag.c b/fs/ceph/blog_pagefrag.c
new file mode 100644
index 000000000000..523cb2d0ba63
--- /dev/null
+++ b/fs/ceph/blog_pagefrag.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Binary Logging Page Fragment Management
+ */
+
+#include "blog_pagefrag.h"
+
+/**
+ * blog_pagefrag_reserve - Reserve space in the pagefrag buffer
+ * @pf: pagefrag allocator
+ * @n: number of bytes to reserve
+ *
+ * Checks if there is sufficient space and returns the current head offset
+ * WITHOUT advancing the head pointer. This allows the caller to write data
+ * before making it visible via blog_pagefrag_publish().
+ *
+ * This is lockless - only one writer per pagefrag (per-task context).
+ *
+ * Return: offset to reserved memory, or negative error if not enough space
+ */
+int blog_pagefrag_reserve(struct blog_pagefrag *pf, unsigned int n)
+{
+	if (n > pf->capacity - pf->head)
+		return -ENOMEM; /* No space left */
+	return pf->head;  /* Return offset without advancing */
+}
+
+/**
+ * blog_pagefrag_publish - Publish reserved space by advancing head pointer
+ * @pf: pagefrag allocator
+ * @publish_head: new head value (offset + bytes_written)
+ *
+ * Advances the head pointer to make previously written data visible to
+ * readers.  Uses store-release so that any reader that observes the new
+ * head value (via load-acquire or under pf->lock) is guaranteed to see
+ * the preceding entry writes.
+ *
+ * Single-writer per pagefrag (per-task context).
+ */
+void blog_pagefrag_publish(struct blog_pagefrag *pf, unsigned int publish_head)
+{
+	/* Release-store pairs with the acquire in readers (pf->lock). */
+	smp_store_release(&pf->head, publish_head);
+}
+
+/**
+ * blog_pagefrag_get_ptr - Get buffer pointer from pagefrag reserve result
+ * @pf: pagefrag allocator
+ * @val: return value from blog_pagefrag_reserve
+ *
+ * Return: pointer to reserved buffer region
+ */
+void *blog_pagefrag_get_ptr(struct blog_pagefrag *pf, u64 val)
+{
+	char *base = (char *)pf->buffer;
+	void *rc = base + val;
+
+	if (unlikely(rc < pf->buffer ||
+		     rc >= (void *)(base + pf->capacity))) {
+		WARN_ON_ONCE(1);
+		return NULL;
+	}
+	return rc;
+}
+
+/**
+ * blog_pagefrag_reset - Reset the pagefrag allocator
+ * @pf: pagefrag allocator to reset
+ *
+ * Resets the head pointer and counters to the beginning of the buffer,
+ * discarding all stored entries.
+ *
+ * Context: Callers must ensure that no writers are active on this
+ * pagefrag before calling reset. The pagefrag is single-writer and
+ * writers do not take pf->lock, so resetting while a writer is mid-
+ * reservation corrupts state. In practice this means the owning task
+ * must have finished its current blog_log() / blog_log_commit() pair.
+ */
+void blog_pagefrag_reset(struct blog_pagefrag *pf)
+{
+	spin_lock(&pf->lock);
+	pf->head = 0;
+	spin_unlock(&pf->lock);
+}
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.