Skip to content

Commit 8fb21bf

Browse files
yangdongshengkawasaki
authored andcommitted
dm-pcache: add segment layer
Introduce segment.{c,h}, an internal abstraction that encapsulates everything related to a single pcache *segment* (the fixed-size allocation unit stored on the cache-device). * On-disk metadata (`struct pcache_segment_info`) - Embedded `struct pcache_meta_header` for CRC/sequence handling. - `flags` field encodes a “has-next” bit and a 4-bit *type* class (`CACHE_DATA` added as the first type). * Initialisation - `pcache_segment_init()` populates the in-memory `struct pcache_segment` from a given segment id, data offset and metadata pointer, computing the usable `data_size` and virtual address within the DAX mapping. * IO helpers - `segment_copy_to_bio()` / `segment_copy_from_bio()` move data between pmem and a bio, using `_copy_mc_to_iter()` and `_copy_from_iter_flushcache()` to tolerate hw memory errors and ensure durability. - `segment_pos_advance()` advances an internal offset while staying inside the segment’s data area. These helpers allow upper layers (cache key management, write-back logic, GC, etc.) to treat a segment as a contiguous byte array without knowing about DAX mappings or persistence details. Signed-off-by: Dongsheng Yang <[email protected]>
1 parent 49affb5 commit 8fb21bf

2 files changed

Lines changed: 137 additions & 0 deletions

File tree

drivers/md/dm-pcache/segment.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
#include <linux/dax.h>
3+
4+
#include "pcache_internal.h"
5+
#include "cache_dev.h"
6+
#include "segment.h"
7+
8+
int segment_copy_to_bio(struct pcache_segment *segment,
9+
u32 data_off, u32 data_len, struct bio *bio, u32 bio_off)
10+
{
11+
struct iov_iter iter;
12+
size_t copied;
13+
void *src;
14+
15+
iov_iter_bvec(&iter, ITER_DEST, &bio->bi_io_vec[bio->bi_iter.bi_idx],
16+
bio_segments(bio), bio->bi_iter.bi_size);
17+
iter.iov_offset = bio->bi_iter.bi_bvec_done;
18+
if (bio_off)
19+
iov_iter_advance(&iter, bio_off);
20+
21+
src = segment->data + data_off;
22+
copied = _copy_mc_to_iter(src, data_len, &iter);
23+
if (copied != data_len)
24+
return -EIO;
25+
26+
return 0;
27+
}
28+
29+
int segment_copy_from_bio(struct pcache_segment *segment,
30+
u32 data_off, u32 data_len, struct bio *bio, u32 bio_off)
31+
{
32+
struct iov_iter iter;
33+
size_t copied;
34+
void *dst;
35+
36+
iov_iter_bvec(&iter, ITER_SOURCE, &bio->bi_io_vec[bio->bi_iter.bi_idx],
37+
bio_segments(bio), bio->bi_iter.bi_size);
38+
iter.iov_offset = bio->bi_iter.bi_bvec_done;
39+
if (bio_off)
40+
iov_iter_advance(&iter, bio_off);
41+
42+
dst = segment->data + data_off;
43+
copied = _copy_from_iter_flushcache(dst, data_len, &iter);
44+
if (copied != data_len)
45+
return -EIO;
46+
pmem_wmb();
47+
48+
return 0;
49+
}
50+
51+
void pcache_segment_init(struct pcache_cache_dev *cache_dev, struct pcache_segment *segment,
52+
struct pcache_segment_init_options *options)
53+
{
54+
segment->seg_info = options->seg_info;
55+
56+
segment_info_set_type(segment->seg_info, options->type);
57+
segment->seg_info->seg_id = options->seg_id;
58+
segment->seg_info->data_off = options->data_off;
59+
60+
segment->cache_dev = cache_dev;
61+
segment->data_size = PCACHE_SEG_SIZE - options->data_off;
62+
segment->data = CACHE_DEV_SEGMENT(cache_dev, options->seg_id) + options->data_off;
63+
}

drivers/md/dm-pcache/segment.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
#ifndef _PCACHE_SEGMENT_H
3+
#define _PCACHE_SEGMENT_H
4+
5+
#include <linux/bio.h>
6+
7+
#include "pcache_internal.h"
8+
9+
struct pcache_segment_info {
10+
struct pcache_meta_header header; /* Metadata header for the segment */
11+
__u32 flags;
12+
__u32 next_seg;
13+
__u32 seg_id;
14+
__u32 data_off;
15+
} __packed;
16+
17+
#define PCACHE_SEG_INFO_FLAGS_HAS_NEXT BIT(0)
18+
19+
#define PCACHE_SEG_INFO_FLAGS_TYPE_MASK GENMASK(4, 1)
20+
#define PCACHE_SEGMENT_TYPE_CACHE_DATA 1
21+
22+
static inline bool segment_info_has_next(struct pcache_segment_info *seg_info)
23+
{
24+
return (seg_info->flags & PCACHE_SEG_INFO_FLAGS_HAS_NEXT);
25+
}
26+
27+
static inline void segment_info_set_type(struct pcache_segment_info *seg_info, u8 type)
28+
{
29+
seg_info->flags &= ~PCACHE_SEG_INFO_FLAGS_TYPE_MASK;
30+
seg_info->flags |= FIELD_PREP(PCACHE_SEG_INFO_FLAGS_TYPE_MASK, type);
31+
}
32+
33+
static inline u8 segment_info_get_type(struct pcache_segment_info *seg_info)
34+
{
35+
return FIELD_GET(PCACHE_SEG_INFO_FLAGS_TYPE_MASK, seg_info->flags);
36+
}
37+
38+
struct pcache_segment_pos {
39+
struct pcache_segment *segment; /* Segment associated with the position */
40+
u32 off; /* Offset within the segment */
41+
};
42+
43+
struct pcache_segment_init_options {
44+
u8 type;
45+
u32 seg_id;
46+
u32 data_off;
47+
48+
struct pcache_segment_info *seg_info;
49+
};
50+
51+
struct pcache_segment {
52+
struct pcache_cache_dev *cache_dev;
53+
54+
void *data;
55+
u32 data_size;
56+
57+
struct pcache_segment_info *seg_info;
58+
};
59+
60+
int segment_copy_to_bio(struct pcache_segment *segment,
61+
u32 data_off, u32 data_len, struct bio *bio, u32 bio_off);
62+
int segment_copy_from_bio(struct pcache_segment *segment,
63+
u32 data_off, u32 data_len, struct bio *bio, u32 bio_off);
64+
65+
static inline void segment_pos_advance(struct pcache_segment_pos *seg_pos, u32 len)
66+
{
67+
BUG_ON(seg_pos->off + len > seg_pos->segment->data_size);
68+
69+
seg_pos->off += len;
70+
}
71+
72+
void pcache_segment_init(struct pcache_cache_dev *cache_dev, struct pcache_segment *segment,
73+
struct pcache_segment_init_options *options);
74+
#endif /* _PCACHE_SEGMENT_H */

0 commit comments

Comments
 (0)