File Index
Files and directories
Sign in
FILE

pcache_internal.h

File preview with syntax highlighting.

linux-6.19.14/drivers/md/dm-pcache/pcache_internal.h C
  1/* SPDX-License-Identifier: GPL-2.0-or-later */
  2#ifndef _PCACHE_INTERNAL_H
  3#define _PCACHE_INTERNAL_H
  4
  5#include <linux/delay.h>
  6#include <linux/crc32c.h>
  7
  8#define pcache_err(fmt, ...)							\
  9	pr_err("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
 10#define pcache_info(fmt, ...)							\
 11	pr_info("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
 12#define pcache_debug(fmt, ...)							\
 13	pr_debug("dm-pcache: %s:%u " fmt, __func__, __LINE__, ##__VA_ARGS__)
 14
 15#define PCACHE_KB			(1024ULL)
 16#define PCACHE_MB			(1024 * PCACHE_KB)
 17
 18/* Maximum number of metadata indices */
 19#define PCACHE_META_INDEX_MAX		2
 20
 21#define PCACHE_CRC_SEED			0x3B15A
 22/*
 23 * struct pcache_meta_header - PCACHE metadata header structure
 24 * @crc: CRC checksum for validating metadata integrity.
 25 * @seq: Sequence number to track metadata updates.
 26 * @version: Metadata version.
 27 * @res: Reserved space for future use.
 28 */
 29struct pcache_meta_header {
 30	__u32 crc;
 31	__u8  seq;
 32	__u8  version;
 33	__u16 res;
 34};
 35
 36/*
 37 * pcache_meta_crc - Calculate CRC for the given metadata header.
 38 * @header: Pointer to the metadata header.
 39 * @meta_size: Size of the metadata structure.
 40 *
 41 * Returns the CRC checksum calculated by excluding the CRC field itself.
 42 */
 43static inline u32 pcache_meta_crc(struct pcache_meta_header *header, u32 meta_size)
 44{
 45	return crc32c(PCACHE_CRC_SEED, (void *)header + 4, meta_size - 4);
 46}
 47
 48/*
 49 * pcache_meta_seq_after - Check if a sequence number is more recent, accounting for overflow.
 50 * @seq1: First sequence number.
 51 * @seq2: Second sequence number.
 52 *
 53 * Determines if @seq1 is more recent than @seq2 by calculating the signed
 54 * difference between them. This approach allows handling sequence number
 55 * overflow correctly because the difference wraps naturally, and any value
 56 * greater than zero indicates that @seq1 is "after" @seq2. This method
 57 * assumes 8-bit unsigned sequence numbers, where the difference wraps
 58 * around if seq1 overflows past seq2.
 59 *
 60 * Returns:
 61 *   - true if @seq1 is more recent than @seq2, indicating it comes "after"
 62 *   - false otherwise.
 63 */
 64static inline bool pcache_meta_seq_after(u8 seq1, u8 seq2)
 65{
 66	return (s8)(seq1 - seq2) > 0;
 67}
 68
 69/*
 70 * pcache_meta_find_latest - Find the latest valid metadata.
 71 * @header: Pointer to the metadata header.
 72 * @meta_size: Size of each metadata block.
 73 *
 74 * Finds the latest valid metadata by checking sequence numbers. If a
 75 * valid entry with the highest sequence number is found, its pointer
 76 * is returned. Returns NULL if no valid metadata is found.
 77 */
 78static inline void __must_check *pcache_meta_find_latest(struct pcache_meta_header *header,
 79					u32 meta_size, u32 meta_max_size,
 80					void *meta_ret)
 81{
 82	struct pcache_meta_header *meta, *latest = NULL;
 83	u32 i, seq_latest = 0;
 84	void *meta_addr;
 85
 86	meta = meta_ret;
 87
 88	for (i = 0; i < PCACHE_META_INDEX_MAX; i++) {
 89		meta_addr = (void *)header + (i * meta_max_size);
 90		if (copy_mc_to_kernel(meta, meta_addr, meta_size)) {
 91			pcache_err("hardware memory error when copy meta");
 92			return ERR_PTR(-EIO);
 93		}
 94
 95		/* Skip if CRC check fails, which means corrupted */
 96		if (meta->crc != pcache_meta_crc(meta, meta_size))
 97			continue;
 98
 99		/* Update latest if a more recent sequence is found */
100		if (!latest || pcache_meta_seq_after(meta->seq, seq_latest)) {
101			seq_latest = meta->seq;
102			latest = meta_addr;
103		}
104	}
105
106	if (!latest)
107		return NULL;
108
109	if (copy_mc_to_kernel(meta_ret, latest, meta_size)) {
110		pcache_err("hardware memory error");
111		return ERR_PTR(-EIO);
112	}
113
114	return latest;
115}
116
117#endif /* _PCACHE_INTERNAL_H */
~/ Read-only file preview.