diff options
Diffstat (limited to 'block/blk-integrity.c')
-rw-r--r-- | block/blk-integrity.c | 106 |
1 files changed, 83 insertions, 23 deletions
diff --git a/block/blk-integrity.c b/block/blk-integrity.c index edce1ef7933d..129b9e209a3b 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c | |||
@@ -30,26 +30,41 @@ | |||
30 | 30 | ||
31 | static struct kmem_cache *integrity_cachep; | 31 | static struct kmem_cache *integrity_cachep; |
32 | 32 | ||
33 | static const char *bi_unsupported_name = "unsupported"; | ||
34 | |||
33 | /** | 35 | /** |
34 | * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements | 36 | * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements |
35 | * @rq: request with integrity metadata attached | 37 | * @q: request queue |
38 | * @bio: bio with integrity metadata attached | ||
36 | * | 39 | * |
37 | * Description: Returns the number of elements required in a | 40 | * Description: Returns the number of elements required in a |
38 | * scatterlist corresponding to the integrity metadata in a request. | 41 | * scatterlist corresponding to the integrity metadata in a bio. |
39 | */ | 42 | */ |
40 | int blk_rq_count_integrity_sg(struct request *rq) | 43 | int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) |
41 | { | 44 | { |
42 | struct bio_vec *iv, *ivprv; | 45 | struct bio_vec *iv, *ivprv = NULL; |
43 | struct req_iterator iter; | 46 | unsigned int segments = 0; |
44 | unsigned int segments; | 47 | unsigned int seg_size = 0; |
48 | unsigned int i = 0; | ||
49 | |||
50 | bio_for_each_integrity_vec(iv, bio, i) { | ||
51 | |||
52 | if (ivprv) { | ||
53 | if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) | ||
54 | goto new_segment; | ||
45 | 55 | ||
46 | ivprv = NULL; | 56 | if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) |
47 | segments = 0; | 57 | goto new_segment; |
48 | 58 | ||
49 | rq_for_each_integrity_segment(iv, rq, iter) { | 59 | if (seg_size + iv->bv_len > queue_max_segment_size(q)) |
60 | goto new_segment; | ||
50 | 61 | ||
51 | if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv)) | 62 | seg_size += iv->bv_len; |
63 | } else { | ||
64 | new_segment: | ||
52 | segments++; | 65 | segments++; |
66 | seg_size = iv->bv_len; | ||
67 | } | ||
53 | 68 | ||
54 | ivprv = iv; | 69 | ivprv = iv; |
55 | } | 70 | } |
@@ -60,30 +75,34 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg); | |||
60 | 75 | ||
61 | /** | 76 | /** |
62 | * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist | 77 | * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist |
63 | * @rq: request with integrity metadata attached | 78 | * @q: request queue |
79 | * @bio: bio with integrity metadata attached | ||
64 | * @sglist: target scatterlist | 80 | * @sglist: target scatterlist |
65 | * | 81 | * |
66 | * Description: Map the integrity vectors in request into a | 82 | * Description: Map the integrity vectors in request into a |
67 | * scatterlist. The scatterlist must be big enough to hold all | 83 | * scatterlist. The scatterlist must be big enough to hold all |
68 | * elements. I.e. sized using blk_rq_count_integrity_sg(). | 84 | * elements. I.e. sized using blk_rq_count_integrity_sg(). |
69 | */ | 85 | */ |
70 | int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) | 86 | int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, |
87 | struct scatterlist *sglist) | ||
71 | { | 88 | { |
72 | struct bio_vec *iv, *ivprv; | 89 | struct bio_vec *iv, *ivprv = NULL; |
73 | struct req_iterator iter; | 90 | struct scatterlist *sg = NULL; |
74 | struct scatterlist *sg; | 91 | unsigned int segments = 0; |
75 | unsigned int segments; | 92 | unsigned int i = 0; |
76 | |||
77 | ivprv = NULL; | ||
78 | sg = NULL; | ||
79 | segments = 0; | ||
80 | 93 | ||
81 | rq_for_each_integrity_segment(iv, rq, iter) { | 94 | bio_for_each_integrity_vec(iv, bio, i) { |
82 | 95 | ||
83 | if (ivprv) { | 96 | if (ivprv) { |
84 | if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) | 97 | if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) |
85 | goto new_segment; | 98 | goto new_segment; |
86 | 99 | ||
100 | if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) | ||
101 | goto new_segment; | ||
102 | |||
103 | if (sg->length + iv->bv_len > queue_max_segment_size(q)) | ||
104 | goto new_segment; | ||
105 | |||
87 | sg->length += iv->bv_len; | 106 | sg->length += iv->bv_len; |
88 | } else { | 107 | } else { |
89 | new_segment: | 108 | new_segment: |
@@ -162,6 +181,40 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2) | |||
162 | } | 181 | } |
163 | EXPORT_SYMBOL(blk_integrity_compare); | 182 | EXPORT_SYMBOL(blk_integrity_compare); |
164 | 183 | ||
184 | int blk_integrity_merge_rq(struct request_queue *q, struct request *req, | ||
185 | struct request *next) | ||
186 | { | ||
187 | if (blk_integrity_rq(req) != blk_integrity_rq(next)) | ||
188 | return -1; | ||
189 | |||
190 | if (req->nr_integrity_segments + next->nr_integrity_segments > | ||
191 | q->limits.max_integrity_segments) | ||
192 | return -1; | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | EXPORT_SYMBOL(blk_integrity_merge_rq); | ||
197 | |||
198 | int blk_integrity_merge_bio(struct request_queue *q, struct request *req, | ||
199 | struct bio *bio) | ||
200 | { | ||
201 | int nr_integrity_segs; | ||
202 | struct bio *next = bio->bi_next; | ||
203 | |||
204 | bio->bi_next = NULL; | ||
205 | nr_integrity_segs = blk_rq_count_integrity_sg(q, bio); | ||
206 | bio->bi_next = next; | ||
207 | |||
208 | if (req->nr_integrity_segments + nr_integrity_segs > | ||
209 | q->limits.max_integrity_segments) | ||
210 | return -1; | ||
211 | |||
212 | req->nr_integrity_segments += nr_integrity_segs; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | EXPORT_SYMBOL(blk_integrity_merge_bio); | ||
217 | |||
165 | struct integrity_sysfs_entry { | 218 | struct integrity_sysfs_entry { |
166 | struct attribute attr; | 219 | struct attribute attr; |
167 | ssize_t (*show)(struct blk_integrity *, char *); | 220 | ssize_t (*show)(struct blk_integrity *, char *); |
@@ -307,6 +360,14 @@ static struct kobj_type integrity_ktype = { | |||
307 | .release = blk_integrity_release, | 360 | .release = blk_integrity_release, |
308 | }; | 361 | }; |
309 | 362 | ||
363 | bool blk_integrity_is_initialized(struct gendisk *disk) | ||
364 | { | ||
365 | struct blk_integrity *bi = blk_get_integrity(disk); | ||
366 | |||
367 | return (bi && bi->name && strcmp(bi->name, bi_unsupported_name) != 0); | ||
368 | } | ||
369 | EXPORT_SYMBOL(blk_integrity_is_initialized); | ||
370 | |||
310 | /** | 371 | /** |
311 | * blk_integrity_register - Register a gendisk as being integrity-capable | 372 | * blk_integrity_register - Register a gendisk as being integrity-capable |
312 | * @disk: struct gendisk pointer to make integrity-aware | 373 | * @disk: struct gendisk pointer to make integrity-aware |
@@ -356,7 +417,7 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) | |||
356 | bi->get_tag_fn = template->get_tag_fn; | 417 | bi->get_tag_fn = template->get_tag_fn; |
357 | bi->tag_size = template->tag_size; | 418 | bi->tag_size = template->tag_size; |
358 | } else | 419 | } else |
359 | bi->name = "unsupported"; | 420 | bi->name = bi_unsupported_name; |
360 | 421 | ||
361 | return 0; | 422 | return 0; |
362 | } | 423 | } |
@@ -381,7 +442,6 @@ void blk_integrity_unregister(struct gendisk *disk) | |||
381 | kobject_uevent(&bi->kobj, KOBJ_REMOVE); | 442 | kobject_uevent(&bi->kobj, KOBJ_REMOVE); |
382 | kobject_del(&bi->kobj); | 443 | kobject_del(&bi->kobj); |
383 | kobject_put(&bi->kobj); | 444 | kobject_put(&bi->kobj); |
384 | kmem_cache_free(integrity_cachep, bi); | ||
385 | disk->integrity = NULL; | 445 | disk->integrity = NULL; |
386 | } | 446 | } |
387 | EXPORT_SYMBOL(blk_integrity_unregister); | 447 | EXPORT_SYMBOL(blk_integrity_unregister); |