Skip to content

Commit 5017064

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 8c65fdb commit 5017064

2 files changed

Lines changed: 134 additions & 0 deletions

File tree

drivers/md/dm-pcache/segment.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
segment_info_set_type(segment->seg_info, options->type);
56+
57+
segment->cache_dev = cache_dev;
58+
segment->seg_id = options->seg_id;
59+
segment->data_size = PCACHE_SEG_SIZE - options->data_off;
60+
segment->data = CACHE_DEV_SEGMENT(cache_dev, options->seg_id) + options->data_off;
61+
}

drivers/md/dm-pcache/segment.h

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

0 commit comments

Comments
 (0)