|
@@ -32,24 +32,37 @@ static struct kmem_cache *integrity_cachep;
|
|
|
|
|
|
/**
|
|
|
* blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
|
|
|
- * @rq: request with integrity metadata attached
|
|
|
+ * @q: request queue
|
|
|
+ * @bio: bio with integrity metadata attached
|
|
|
*
|
|
|
* Description: Returns the number of elements required in a
|
|
|
- * scatterlist corresponding to the integrity metadata in a request.
|
|
|
+ * scatterlist corresponding to the integrity metadata in a bio.
|
|
|
*/
|
|
|
-int blk_rq_count_integrity_sg(struct request *rq)
|
|
|
+int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio)
|
|
|
{
|
|
|
- struct bio_vec *iv, *ivprv;
|
|
|
- struct req_iterator iter;
|
|
|
- unsigned int segments;
|
|
|
+ struct bio_vec *iv, *ivprv = NULL;
|
|
|
+ unsigned int segments = 0;
|
|
|
+ unsigned int seg_size = 0;
|
|
|
+ unsigned int i = 0;
|
|
|
|
|
|
- ivprv = NULL;
|
|
|
- segments = 0;
|
|
|
+ bio_for_each_integrity_vec(iv, bio, i) {
|
|
|
|
|
|
- rq_for_each_integrity_segment(iv, rq, iter) {
|
|
|
+ if (ivprv) {
|
|
|
+ if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
|
|
|
+ goto new_segment;
|
|
|
+
|
|
|
+ if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
|
|
|
+ goto new_segment;
|
|
|
+
|
|
|
+ if (seg_size + iv->bv_len > queue_max_segment_size(q))
|
|
|
+ goto new_segment;
|
|
|
|
|
|
- if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv))
|
|
|
+ seg_size += iv->bv_len;
|
|
|
+ } else {
|
|
|
+new_segment:
|
|
|
segments++;
|
|
|
+ seg_size = iv->bv_len;
|
|
|
+ }
|
|
|
|
|
|
ivprv = iv;
|
|
|
}
|
|
@@ -60,30 +73,34 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg);
|
|
|
|
|
|
/**
|
|
|
* blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
|
|
|
- * @rq: request with integrity metadata attached
|
|
|
+ * @q: request queue
|
|
|
+ * @bio: bio with integrity metadata attached
|
|
|
* @sglist: target scatterlist
|
|
|
*
|
|
|
* Description: Map the integrity vectors in request into a
|
|
|
* scatterlist. The scatterlist must be big enough to hold all
|
|
|
* elements. I.e. sized using blk_rq_count_integrity_sg().
|
|
|
*/
|
|
|
-int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)
|
|
|
+int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
|
|
|
+ struct scatterlist *sglist)
|
|
|
{
|
|
|
- struct bio_vec *iv, *ivprv;
|
|
|
- struct req_iterator iter;
|
|
|
- struct scatterlist *sg;
|
|
|
- unsigned int segments;
|
|
|
+ struct bio_vec *iv, *ivprv = NULL;
|
|
|
+ struct scatterlist *sg = NULL;
|
|
|
+ unsigned int segments = 0;
|
|
|
+ unsigned int i = 0;
|
|
|
|
|
|
- ivprv = NULL;
|
|
|
- sg = NULL;
|
|
|
- segments = 0;
|
|
|
-
|
|
|
- rq_for_each_integrity_segment(iv, rq, iter) {
|
|
|
+ bio_for_each_integrity_vec(iv, bio, i) {
|
|
|
|
|
|
if (ivprv) {
|
|
|
if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
|
|
|
goto new_segment;
|
|
|
|
|
|
+ if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
|
|
|
+ goto new_segment;
|
|
|
+
|
|
|
+ if (sg->length + iv->bv_len > queue_max_segment_size(q))
|
|
|
+ goto new_segment;
|
|
|
+
|
|
|
sg->length += iv->bv_len;
|
|
|
} else {
|
|
|
new_segment:
|
|
@@ -162,6 +179,40 @@ int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
|
|
|
}
|
|
|
EXPORT_SYMBOL(blk_integrity_compare);
|
|
|
|
|
|
+int blk_integrity_merge_rq(struct request_queue *q, struct request *req,
|
|
|
+ struct request *next)
|
|
|
+{
|
|
|
+ if (blk_integrity_rq(req) != blk_integrity_rq(next))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (req->nr_integrity_segments + next->nr_integrity_segments >
|
|
|
+ q->limits.max_integrity_segments)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_integrity_merge_rq);
|
|
|
+
|
|
|
+int blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
|
|
+ struct bio *bio)
|
|
|
+{
|
|
|
+ int nr_integrity_segs;
|
|
|
+ struct bio *next = bio->bi_next;
|
|
|
+
|
|
|
+ bio->bi_next = NULL;
|
|
|
+ nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
|
|
|
+ bio->bi_next = next;
|
|
|
+
|
|
|
+ if (req->nr_integrity_segments + nr_integrity_segs >
|
|
|
+ q->limits.max_integrity_segments)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ req->nr_integrity_segments += nr_integrity_segs;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(blk_integrity_merge_bio);
|
|
|
+
|
|
|
struct integrity_sysfs_entry {
|
|
|
struct attribute attr;
|
|
|
ssize_t (*show)(struct blk_integrity *, char *);
|