]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Kiyoshi Ueda <k-ueda@ct.jp.nec.com> |
2 | Subject: Block integrity support for DM and MD | |
3 | References: FATE#304345 | |
4 | ||
5 | This patch adds Data integrity support to DM and MD. | |
6 | It has been reworked to support request-based multipathing. | |
7 | ||
8 | Signed-off-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com> | |
9 | Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> | |
10 | Cc: Martin K. Petersen <martin.petersen@oracle.com> | |
11 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
12 | ||
13 | --- | |
14 | drivers/md/dm-table.c | 37 +++++++++++++++++++++++++++++++++++++ | |
15 | drivers/md/dm.c | 22 ++++++++++++++++++++++ | |
16 | drivers/md/dm.h | 1 + | |
17 | drivers/md/md.c | 34 ++++++++++++++++++++++++++++++++++ | |
18 | fs/bio-integrity.c | 5 +++-- | |
19 | fs/bio.c | 2 +- | |
20 | include/linux/bio.h | 4 ++-- | |
21 | 7 files changed, 100 insertions(+), 5 deletions(-) | |
22 | ||
23 | --- a/drivers/md/dm-table.c | |
24 | +++ b/drivers/md/dm-table.c | |
25 | @@ -951,6 +951,43 @@ void dm_table_set_restrictions(struct dm | |
26 | queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q); | |
27 | } | |
28 | ||
29 | +void dm_table_set_integrity(struct dm_table *t, struct mapped_device *md) | |
30 | +{ | |
31 | + struct list_head *devices = dm_table_get_devices(t); | |
32 | + struct dm_dev *prev, *cur; | |
33 | + | |
34 | + /* | |
35 | + * Run through all devices to ensure they have matching | |
36 | + * integrity profile | |
37 | + */ | |
38 | + cur = prev = NULL; | |
39 | + | |
40 | + list_for_each_entry(cur, devices, list) { | |
41 | + | |
42 | + if (prev && blk_integrity_compare(prev->bdev->bd_disk, | |
43 | + cur->bdev->bd_disk) < 0) { | |
44 | + printk(KERN_ERR "%s: %s %s Integrity mismatch!\n", | |
45 | + __func__, prev->bdev->bd_disk->disk_name, | |
46 | + cur->bdev->bd_disk->disk_name); | |
47 | + return; | |
48 | + } | |
49 | + prev = cur; | |
50 | + } | |
51 | + | |
52 | + /* Register dm device as being integrity capable */ | |
53 | + if (prev && bdev_get_integrity(prev->bdev)) { | |
54 | + struct gendisk *disk = dm_disk(md); | |
55 | + | |
56 | + if (blk_integrity_register(dm_disk(md), | |
57 | + bdev_get_integrity(prev->bdev))) | |
58 | + printk(KERN_ERR "%s: %s Could not register integrity!\n", | |
59 | + __func__, disk->disk_name); | |
60 | + else | |
61 | + printk(KERN_INFO "Enabling data integrity on %s\n", | |
62 | + disk->disk_name); | |
63 | + } | |
64 | +} | |
65 | + | |
66 | unsigned int dm_table_get_num_targets(struct dm_table *t) | |
67 | { | |
68 | return t->num_targets; | |
69 | --- a/drivers/md/dm.c | |
70 | +++ b/drivers/md/dm.c | |
71 | @@ -1022,6 +1022,13 @@ static struct bio *split_bvec(struct bio | |
72 | clone->bi_size = to_bytes(len); | |
73 | clone->bi_io_vec->bv_offset = offset; | |
74 | clone->bi_io_vec->bv_len = clone->bi_size; | |
75 | + clone->bi_flags |= 1 << BIO_CLONED; | |
76 | + | |
77 | + if (bio_integrity(bio)) { | |
78 | + bio_integrity_clone(clone, bio, GFP_NOIO, bs); | |
79 | + bio_integrity_trim(clone, | |
80 | + bio_sector_offset(bio, idx, offset), len); | |
81 | + } | |
82 | ||
83 | return clone; | |
84 | } | |
85 | @@ -1044,6 +1051,14 @@ static struct bio *clone_bio(struct bio | |
86 | clone->bi_size = to_bytes(len); | |
87 | clone->bi_flags &= ~(1 << BIO_SEG_VALID); | |
88 | ||
89 | + if (bio_integrity(bio)) { | |
90 | + bio_integrity_clone(clone, bio, GFP_NOIO, bs); | |
91 | + | |
92 | + if (idx != bio->bi_idx || clone->bi_size < bio->bi_size) | |
93 | + bio_integrity_trim(clone, | |
94 | + bio_sector_offset(bio, idx, 0), len); | |
95 | + } | |
96 | + | |
97 | return clone; | |
98 | } | |
99 | ||
100 | @@ -1365,6 +1380,11 @@ static int clone_request_bios(struct req | |
101 | } | |
102 | ||
103 | __bio_clone(clone_bio, bio); | |
104 | + if (bio_integrity(bio)) | |
105 | + if (bio_integrity_clone(clone_bio, bio, GFP_ATOMIC, | |
106 | + md->bs) < 0) | |
107 | + goto free_and_out; | |
108 | + | |
109 | clone_bio->bi_destructor = dm_bio_destructor; | |
110 | clone_bio->bi_end_io = end_clone_bio; | |
111 | info->rq = clone; | |
112 | @@ -1835,6 +1855,7 @@ static void free_dev(struct mapped_devic | |
113 | mempool_destroy(md->io_pool); | |
114 | if (md->bs) | |
115 | bioset_free(md->bs); | |
116 | + blk_integrity_unregister(md->disk); | |
117 | del_gendisk(md->disk); | |
118 | free_minor(minor); | |
119 | ||
120 | @@ -1910,6 +1931,7 @@ static int __bind(struct mapped_device * | |
121 | write_lock(&md->map_lock); | |
122 | md->map = t; | |
123 | dm_table_set_restrictions(t, q); | |
124 | + dm_table_set_integrity(t, md); | |
125 | if (!(dm_table_get_mode(t) & FMODE_WRITE)) { | |
126 | set_disk_ro(md->disk, 1); | |
127 | } else { | |
128 | --- a/drivers/md/dm.h | |
129 | +++ b/drivers/md/dm.h | |
130 | @@ -51,6 +51,7 @@ void dm_table_event_callback(struct dm_t | |
131 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); | |
132 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); | |
133 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); | |
134 | +void dm_table_set_integrity(struct dm_table *t, struct mapped_device *md); | |
135 | struct list_head *dm_table_get_devices(struct dm_table *t); | |
136 | void dm_table_presuspend_targets(struct dm_table *t); | |
137 | void dm_table_postsuspend_targets(struct dm_table *t); | |
138 | --- a/drivers/md/md.c | |
139 | +++ b/drivers/md/md.c | |
140 | @@ -1411,6 +1411,38 @@ static int match_mddev_units(mddev_t *md | |
141 | ||
142 | static LIST_HEAD(pending_raid_disks); | |
143 | ||
144 | +static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev) | |
145 | +{ | |
146 | + struct mdk_personality *pers = mddev->pers; | |
147 | + struct gendisk *disk = mddev->gendisk; | |
148 | + struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev); | |
149 | + struct blk_integrity *bi_mddev = blk_get_integrity(disk); | |
150 | + | |
151 | + /* Data integrity passthrough not supported on RAID 4, 5 and 6 */ | |
152 | + if (pers && pers->level >= 4 && pers->level <= 6) | |
153 | + return; | |
154 | + | |
155 | + /* If rdev is integrity capable, register profile for mddev */ | |
156 | + if (!bi_mddev && bi_rdev) { | |
157 | + if (blk_integrity_register(disk, bi_rdev)) | |
158 | + printk(KERN_ERR "%s: %s Could not register integrity!\n", | |
159 | + __func__, disk->disk_name); | |
160 | + else | |
161 | + printk(KERN_NOTICE "Enabling data integrity on %s\n", | |
162 | + disk->disk_name); | |
163 | + return; | |
164 | + } | |
165 | + | |
166 | + /* Check that mddev and rdev have matching profiles */ | |
167 | + if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) { | |
168 | + printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__, | |
169 | + disk->disk_name, rdev->bdev->bd_disk->disk_name); | |
170 | + printk(KERN_NOTICE "Disabling data integrity on %s\n", | |
171 | + disk->disk_name); | |
172 | + blk_integrity_unregister(disk); | |
173 | + } | |
174 | +} | |
175 | + | |
176 | static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) | |
177 | { | |
178 | char b[BDEVNAME_SIZE]; | |
179 | @@ -1479,6 +1511,7 @@ static int bind_rdev_to_array(mdk_rdev_t | |
180 | } | |
181 | list_add_rcu(&rdev->same_set, &mddev->disks); | |
182 | bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); | |
183 | + md_integrity_check(rdev, mddev); | |
184 | return 0; | |
185 | ||
186 | fail: | |
187 | @@ -3967,6 +4000,7 @@ static int do_md_stop(mddev_t * mddev, i | |
188 | printk(KERN_INFO "md: %s switched to read-only mode.\n", | |
189 | mdname(mddev)); | |
190 | err = 0; | |
191 | + blk_integrity_unregister(disk); | |
192 | md_new_event(mddev); | |
193 | sysfs_notify(&mddev->kobj, NULL, "array_state"); | |
194 | out: | |
195 | --- a/fs/bio-integrity.c | |
196 | +++ b/fs/bio-integrity.c | |
197 | @@ -655,19 +655,20 @@ EXPORT_SYMBOL(bio_integrity_split); | |
198 | * bio_integrity_clone - Callback for cloning bios with integrity metadata | |
199 | * @bio: New bio | |
200 | * @bio_src: Original bio | |
201 | + * @gfp_mask: Memory allocation mask | |
202 | * @bs: bio_set to allocate bip from | |
203 | * | |
204 | * Description: Called to allocate a bip when cloning a bio | |
205 | */ | |
206 | int bio_integrity_clone(struct bio *bio, struct bio *bio_src, | |
207 | - struct bio_set *bs) | |
208 | + gfp_t gfp_mask, struct bio_set *bs) | |
209 | { | |
210 | struct bio_integrity_payload *bip_src = bio_src->bi_integrity; | |
211 | struct bio_integrity_payload *bip; | |
212 | ||
213 | BUG_ON(bip_src == NULL); | |
214 | ||
215 | - bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs); | |
216 | + bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs); | |
217 | ||
218 | if (bip == NULL) | |
219 | return -EIO; | |
220 | --- a/fs/bio.c | |
221 | +++ b/fs/bio.c | |
222 | @@ -256,7 +256,7 @@ struct bio *bio_clone(struct bio *bio, g | |
223 | if (bio_integrity(bio)) { | |
224 | int ret; | |
225 | ||
226 | - ret = bio_integrity_clone(b, bio, fs_bio_set); | |
227 | + ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set); | |
228 | ||
229 | if (ret < 0) | |
230 | return NULL; | |
231 | --- a/include/linux/bio.h | |
232 | +++ b/include/linux/bio.h | |
233 | @@ -501,7 +501,7 @@ extern void bio_integrity_endio(struct b | |
234 | extern void bio_integrity_advance(struct bio *, unsigned int); | |
235 | extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); | |
236 | extern void bio_integrity_split(struct bio *, struct bio_pair *, int); | |
237 | -extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *); | |
238 | +extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *); | |
239 | extern int bioset_integrity_create(struct bio_set *, int); | |
240 | extern void bioset_integrity_free(struct bio_set *); | |
241 | extern void bio_integrity_init_slab(void); | |
242 | @@ -512,7 +512,7 @@ extern void bio_integrity_init_slab(void | |
243 | #define bioset_integrity_create(a, b) (0) | |
244 | #define bio_integrity_prep(a) (0) | |
245 | #define bio_integrity_enabled(a) (0) | |
246 | -#define bio_integrity_clone(a, b, c) (0) | |
247 | +#define bio_integrity_clone(a, b, c, d) (0) | |
248 | #define bioset_integrity_free(a) do { } while (0) | |
249 | #define bio_integrity_free(a, b) do { } while (0) | |
250 | #define bio_integrity_endio(a, b) do { } while (0) |