Consolidate common PCACHE helpers into a new header so that subsequent
patches can include them without repeating boiler-plate.

- Logging macros with unified prefix and location info.
- Common constants (KB/MB helpers, metadata replica count, CRC seed).
- On-disk metadata header definition and CRC helper.
- Sequence-number comparison that handles wrap-around.
- pcache_meta_find_latest() to pick the newest valid metadata copy.

Signed-off-by: Dongsheng Yang <dongsheng.y...@linux.dev>
---
 drivers/md/dm-pcache/pcache_internal.h | 117 +++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 drivers/md/dm-pcache/pcache_internal.h

diff --git a/drivers/md/dm-pcache/pcache_internal.h 
b/drivers/md/dm-pcache/pcache_internal.h
new file mode 100644
index 000000000000..d427e534727c
--- /dev/null
+++ b/drivers/md/dm-pcache/pcache_internal.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _PCACHE_INTERNAL_H
+#define _PCACHE_INTERNAL_H
+
+#include <linux/delay.h>
+#include <linux/crc32c.h>
+
+#define pcache_err(fmt, ...)                                                   
\
+       pr_err("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define pcache_info(fmt, ...)                                                  
\
+       pr_info("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define pcache_debug(fmt, ...)                                                 
\
+       pr_debug("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
+
+#define PCACHE_KB                      (1024ULL)
+#define PCACHE_MB                      (1024 * PCACHE_KB)
+
+/* Maximum number of metadata indices */
+#define PCACHE_META_INDEX_MAX          2
+
+#define PCACHE_CRC_SEED                        0x3B15A
+/*
+ * struct pcache_meta_header - PCACHE metadata header structure
+ * @crc: CRC checksum for validating metadata integrity.
+ * @seq: Sequence number to track metadata updates.
+ * @version: Metadata version.
+ * @res: Reserved space for future use.
+ */
+struct pcache_meta_header {
+       __u32 crc;
+       __u8  seq;
+       __u8  version;
+       __u16 res;
+};
+
+/*
+ * pcache_meta_crc - Calculate CRC for the given metadata header.
+ * @header: Pointer to the metadata header.
+ * @meta_size: Size of the metadata structure.
+ *
+ * Returns the CRC checksum calculated by excluding the CRC field itself.
+ */
+static inline u32 pcache_meta_crc(struct pcache_meta_header *header, u32 
meta_size)
+{
+       return crc32c(PCACHE_CRC_SEED, (void *)header + 4, meta_size - 4);
+}
+
+/*
+ * pcache_meta_seq_after - Check if a sequence number is more recent, 
accounting for overflow.
+ * @seq1: First sequence number.
+ * @seq2: Second sequence number.
+ *
+ * Determines if @seq1 is more recent than @seq2 by calculating the signed
+ * difference between them. This approach allows handling sequence number
+ * overflow correctly because the difference wraps naturally, and any value
+ * greater than zero indicates that @seq1 is "after" @seq2. This method
+ * assumes 8-bit unsigned sequence numbers, where the difference wraps
+ * around if seq1 overflows past seq2.
+ *
+ * Returns:
+ *   - true if @seq1 is more recent than @seq2, indicating it comes "after"
+ *   - false otherwise.
+ */
+static inline bool pcache_meta_seq_after(u8 seq1, u8 seq2)
+{
+       return (s8)(seq1 - seq2) > 0;
+}
+
+/*
+ * pcache_meta_find_latest - Find the latest valid metadata.
+ * @header: Pointer to the metadata header.
+ * @meta_size: Size of each metadata block.
+ *
+ * Finds the latest valid metadata by checking sequence numbers. If a
+ * valid entry with the highest sequence number is found, its pointer
+ * is returned. Returns NULL if no valid metadata is found.
+ */
+static inline void __must_check *pcache_meta_find_latest(struct 
pcache_meta_header *header,
+                                       u32 meta_size, u32 meta_max_size,
+                                       void *meta_ret)
+{
+       struct pcache_meta_header *meta, *latest = NULL;
+       u32 i, seq_latest = 0;
+       void *meta_addr;
+
+       meta = meta_ret;
+
+       for (i = 0; i < PCACHE_META_INDEX_MAX; i++) {
+               meta_addr = (void *)header + (i * meta_max_size);
+               if (copy_mc_to_kernel(meta, meta_addr, meta_size)) {
+                       pcache_err("hardware memory error when copy meta");
+                       return ERR_PTR(-EIO);
+               }
+
+               /* Skip if CRC check fails, which means corrupted */
+               if (meta->crc != pcache_meta_crc(meta, meta_size))
+                       continue;
+
+               /* Update latest if a more recent sequence is found */
+               if (!latest || pcache_meta_seq_after(meta->seq, seq_latest)) {
+                       seq_latest = meta->seq;
+                       latest = (void *)header + (i * meta_max_size);
+               }
+       }
+
+       if (!latest)
+               return NULL;
+
+       if (copy_mc_to_kernel(meta_ret, latest, meta_size)) {
+               pcache_err("hardware memory error");
+               return ERR_PTR(-EIO);
+       }
+
+       return latest;
+}
+
+#endif /* _PCACHE_INTERNAL_H */
-- 
2.43.0


Reply via email to