[RFC PATCH 03/11] pcache: introduce meta_segment abstraction

Dongsheng Yang <[email protected]>
Newsgroups org.kernel.vger.linux-bcache,dev.linux.lists.nvdimm,org.kernel.vger.linux-block,org.kernel.vger.linux-cxl,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
This patch introduces the `meta_segment` abstraction to persistently store
metadata for pcache, specifically the `pcache_backing_dev_info` structure.

Each `meta_segment` wraps a data segment and organizes metadata space into
multiple entries, each replicated multiple times for reliability. Metadata
integrity is ensured using a sequence counter and CRC per metadata header.

Key highlights:
- `struct pcache_meta_segment`: Manages a segment dedicated to metadata.
- `struct pcache_meta_segment_info`: Describes the layout and size of
  metadata entries.
- `meta_seg_info_write()`: Writes updated metadata info with CRC protection.
- `meta_seg_meta()`: Computes the address of a given metadata entry.
- `pcache_meta_seg_for_each_meta`: A convenient macro to iterate over all
  metadata entries in the segment, simplifying metadata scanning and
  management logic.

Currently, only `pcache_backing_dev_info` is stored via this mechanism.

This design provides a structured, verifiable, and extensible foundation
for storing persistent metadata in the pcache framework.

Signed-off-by: Dongsheng Yang <[email protected]>
---
 drivers/block/pcache/meta_segment.c | 61 +++++++++++++++++++++++++++++
 drivers/block/pcache/meta_segment.h | 46 ++++++++++++++++++++++
 2 files changed, 107 insertions(+)
 create mode 100644 drivers/block/pcache/meta_segment.c
 create mode 100644 drivers/block/pcache/meta_segment.h

diff --git a/drivers/block/pcache/meta_segment.c b/drivers/block/pcache/meta_segment.c
new file mode 100644
index 000000000000..6a6dd9ad9041
--- /dev/null
+++ b/drivers/block/pcache/meta_segment.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "cache_dev.h"
+#include "cache.h"
+#include "backing_dev.h"
+#include "meta_segment.h"
+
+static void meta_seg_info_write(struct pcache_meta_segment *meta_seg)
+{
+	struct pcache_meta_segment_info *info_addr;
+
+	mutex_lock(&meta_seg->info_lock);
+	meta_seg->meta_seg_info.seg_info.header.seq++;
+
+	info_addr = CACHE_DEV_SEGMENT(meta_seg->cache_dev, meta_seg->meta_seg_info.seg_info.seg_id);
+	info_addr = pcache_meta_find_oldest(&info_addr->seg_info.header, PCACHE_SEG_INFO_SIZE);
+
+	memcpy(info_addr, &meta_seg->meta_seg_info, sizeof(struct pcache_meta_segment_info));
+	info_addr->seg_info.header.crc = pcache_meta_crc(&info_addr->seg_info.header, PCACHE_SEG_INFO_SIZE);
+
+	cache_dev_flush(meta_seg->cache_dev, info_addr, PCACHE_SEG_INFO_SIZE);
+	mutex_unlock(&meta_seg->info_lock);
+}
+
+static void meta_seg_init(struct pcache_cache_dev *cache_dev, struct pcache_meta_segment *meta_seg, u32 seg_id, u32 meta_size)
+{
+	struct pcache_segment_init_options seg_opts = { 0 };
+
+	meta_seg->cache_dev = cache_dev;
+	mutex_init(&meta_seg->info_lock);
+
+	seg_opts.type = PCACHES_TYPE_META;
+	seg_opts.state = PCACHE_SEGMENT_STATE_RUNNING;
+	seg_opts.seg_id = seg_id;
+	seg_opts.data_off = PCACHE_SEG_INFO_SIZE * PCACHE_META_INDEX_MAX;
+	seg_opts.seg_info = &meta_seg->meta_seg_info.seg_info;
+
+	pcache_segment_init(cache_dev, &meta_seg->segment, &seg_opts);
+
+	meta_seg->meta_seg_info.meta_size = meta_size;
+	meta_seg->meta_seg_info.meta_num = meta_seg->segment.data_size / (meta_size * PCACHE_META_INDEX_MAX);
+
+	meta_seg_info_write(meta_seg);
+}
+
+struct pcache_meta_segment *pcache_meta_seg_alloc(struct pcache_cache_dev *cache_dev, u32 seg_id, u32 meta_size)
+{
+	struct pcache_meta_segment *meta_seg;
+
+	meta_seg = kzalloc(sizeof(struct pcache_meta_segment), GFP_KERNEL);
+	if (!meta_seg)
+		return NULL;
+
+	meta_seg_init(cache_dev, meta_seg, seg_id, meta_size);
+
+	return meta_seg;
+}
+
+void pcache_meta_seg_free(struct pcache_meta_segment *meta_seg)
+{
+	kfree(meta_seg);
+}
diff --git a/drivers/block/pcache/meta_segment.h b/drivers/block/pcache/meta_segment.h
new file mode 100644
index 000000000000..3e0886d0bd2b
--- /dev/null
+++ b/drivers/block/pcache/meta_segment.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _PCACHE_META_SEGMENT_H
+#define _PCACHE_META_SEGMENT_H
+
+#include <linux/bio.h>
+
+#include "pcache_internal.h"
+#include "cache_dev.h"
+#include "segment.h"
+
+struct pcache_cache_dev;
+struct pcache_backing_dev_info;
+
+struct pcache_meta_segment_info {
+	struct pcache_segment_info	seg_info;
+	u32 meta_size;
+	u32 meta_num;
+};
+
+struct pcache_meta_segment {
+	struct pcache_segment	segment;
+
+	struct pcache_cache_dev *cache_dev;
+
+	struct pcache_meta_segment_info meta_seg_info;
+	struct mutex info_lock;
+
+	struct pcache_meta_segment *next_meta_seg;
+};
+
+static inline void *meta_seg_meta(struct pcache_meta_segment *meta_seg, u32 meta_id)
+{
+	void *data = meta_seg->segment.data;
+
+	return (data + meta_id * meta_seg->meta_seg_info.meta_size * PCACHE_META_INDEX_MAX);
+}
+
+#define pcache_meta_seg_for_each_meta(meta_seg, i, meta)	\
+	for (i = 0;						\
+	     i < meta_seg->meta_seg_info.meta_num &&		\
+	     ((meta = meta_seg_meta(meta_seg, i)) || true);	\
+	     i++)
+
+struct pcache_meta_segment *pcache_meta_seg_alloc(struct pcache_cache_dev *cache_dev, u32 seg_id, u32 meta_size);
+void pcache_meta_seg_free(struct pcache_meta_segment *meta_seg);
+#endif /* _PCACHE_META_SEGMENT_H */
-- 
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.