]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - block/bio-integrity.c
bio-integrity: Restore original iterator on verify stage
[karo-tx-linux.git] / block / bio-integrity.c
index b8a3a65f73641a591ab7918b56c3a003594bee89..8df4eb103ba9e78c089a1d1dd2c9cdb35a89d30a 100644 (file)
@@ -159,44 +159,6 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
 }
 EXPORT_SYMBOL(bio_integrity_add_page);
 
-/**
- * bio_integrity_enabled - Check whether integrity can be passed
- * @bio:       bio to check
- *
- * Description: Determines whether bio_integrity_prep() can be called
- * on this bio or not. bio data direction and target device must be
- * set prior to calling.  The functions honors the write_generate and
- * read_verify flags in sysfs.
- */
-bool bio_integrity_enabled(struct bio *bio)
-{
-       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
-
-       if (bio_op(bio) != REQ_OP_READ && bio_op(bio) != REQ_OP_WRITE)
-               return false;
-
-       if (!bio_sectors(bio))
-               return false;
-
-       /* Already protected? */
-       if (bio_integrity(bio))
-               return false;
-
-       if (bi == NULL)
-               return false;
-
-       if (bio_data_dir(bio) == READ && bi->profile->verify_fn != NULL &&
-           (bi->flags & BLK_INTEGRITY_VERIFY))
-               return true;
-
-       if (bio_data_dir(bio) == WRITE && bi->profile->generate_fn != NULL &&
-           (bi->flags & BLK_INTEGRITY_GENERATE))
-               return true;
-
-       return false;
-}
-EXPORT_SYMBOL(bio_integrity_enabled);
-
 /**
  * bio_integrity_intervals - Return number of integrity intervals for a bio
  * @bi:                blk_integrity profile for device
@@ -222,10 +184,11 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
 /**
  * bio_integrity_process - Process integrity metadata for a bio
  * @bio:       bio to generate/verify integrity metadata for
+ * @proc_iter:  iterator to process
  * @proc_fn:   Pointer to the relevant processing function
  */
 static blk_status_t bio_integrity_process(struct bio *bio,
-                                integrity_processing_fn *proc_fn)
+               struct bvec_iter *proc_iter, integrity_processing_fn *proc_fn)
 {
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        struct blk_integrity_iter iter;
@@ -238,10 +201,10 @@ static blk_status_t bio_integrity_process(struct bio *bio,
 
        iter.disk_name = bio->bi_bdev->bd_disk->disk_name;
        iter.interval = 1 << bi->interval_exp;
-       iter.seed = bip_get_seed(bip);
+       iter.seed = proc_iter->bi_sector;
        iter.prot_buf = prot_buf;
 
-       bio_for_each_segment(bv, bio, bviter) {
+       __bio_for_each_segment(bv, bio, bviter, *proc_iter) {
                void *kaddr = kmap_atomic(bv.bv_page);
 
                iter.data_buf = kaddr + bv.bv_offset;
@@ -262,14 +225,15 @@ static blk_status_t bio_integrity_process(struct bio *bio,
  * bio_integrity_prep - Prepare bio for integrity I/O
  * @bio:       bio to prepare
  *
- * Description: Allocates a buffer for integrity metadata, maps the
- * pages and attaches them to a bio.  The bio must have data
- * direction, target device and start sector set priot to calling.  In
- * the WRITE case, integrity metadata will be generated using the
- * block device's integrity function.  In the READ case, the buffer
+ * Description:  Checks if the bio already has an integrity payload attached.
+ * If it does, the payload has been generated by another kernel subsystem,
+ * and we just pass it through. Otherwise allocates integrity payload.
+ * The bio must have data direction, target device and start sector set priot
+ * to calling.  In the WRITE case, integrity metadata will be generated using
+ * the block device's integrity function.  In the READ case, the buffer
  * will be prepared for DMA and a suitable end_io handler set up.
  */
-int bio_integrity_prep(struct bio *bio)
+bool bio_integrity_prep(struct bio *bio)
 {
        struct bio_integrity_payload *bip;
        struct blk_integrity *bi;
@@ -279,20 +243,41 @@ int bio_integrity_prep(struct bio *bio)
        unsigned int len, nr_pages;
        unsigned int bytes, offset, i;
        unsigned int intervals;
+       blk_status_t status;
 
        bi = bdev_get_integrity(bio->bi_bdev);
        q = bdev_get_queue(bio->bi_bdev);
-       BUG_ON(bi == NULL);
-       BUG_ON(bio_integrity(bio));
+       if (bio_op(bio) != REQ_OP_READ && bio_op(bio) != REQ_OP_WRITE)
+               return true;
 
+       if (!bio_sectors(bio))
+               return true;
+
+       /* Already protected? */
+       if (bio_integrity(bio))
+               return true;
+
+       if (bi == NULL)
+               return true;
+
+       if (bio_data_dir(bio) == READ) {
+               if (!bi->profile->verify_fn ||
+                   !(bi->flags & BLK_INTEGRITY_VERIFY))
+                       return true;
+       } else {
+               if (!bi->profile->generate_fn ||
+                   !(bi->flags & BLK_INTEGRITY_GENERATE))
+                       return true;
+       }
        intervals = bio_integrity_intervals(bi, bio_sectors(bio));
 
        /* Allocate kernel buffer for protection data */
        len = intervals * bi->tuple_size;
        buf = kmalloc(len, GFP_NOIO | q->bounce_gfp);
+       status = BLK_STS_RESOURCE;
        if (unlikely(buf == NULL)) {
                printk(KERN_ERR "could not allocate integrity buffer\n");
-               return -ENOMEM;
+               goto err_end_io;
        }
 
        end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -304,7 +289,8 @@ int bio_integrity_prep(struct bio *bio)
        if (IS_ERR(bip)) {
                printk(KERN_ERR "could not allocate data integrity bioset\n");
                kfree(buf);
-               return PTR_ERR(bip);
+               status = BLK_STS_RESOURCE;
+               goto err_end_io;
        }
 
        bip->bip_flags |= BIP_BLOCK_INTEGRITY;
@@ -347,10 +333,17 @@ int bio_integrity_prep(struct bio *bio)
        }
 
        /* Auto-generate integrity metadata if this is a write */
-       if (bio_data_dir(bio) == WRITE)
-               bio_integrity_process(bio, bi->profile->generate_fn);
+       if (bio_data_dir(bio) == WRITE) {
+               bio_integrity_process(bio, &bio->bi_iter,
+                                     bi->profile->generate_fn);
+       }
+       return true;
+
+err_end_io:
+       bio->bi_status = status;
+       bio_endio(bio);
+       return false;
 
-       return 0;
 }
 EXPORT_SYMBOL(bio_integrity_prep);
 
@@ -368,8 +361,19 @@ static void bio_integrity_verify_fn(struct work_struct *work)
                container_of(work, struct bio_integrity_payload, bip_work);
        struct bio *bio = bip->bip_bio;
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       struct bvec_iter iter = bio->bi_iter;
 
-       bio->bi_status = bio_integrity_process(bio, bi->profile->verify_fn);
+       /*
+        * At the moment verify is called bio's iterator was advanced
+        * during split and completion, we need to rewind iterator to
+        * it's original position.
+        */
+       if (bio_rewind_iter(bio, &iter, iter.bi_done)) {
+               bio->bi_status = bio_integrity_process(bio, &iter,
+                                                      bi->profile->verify_fn);
+       } else {
+               bio->bi_status = BLK_STS_IOERR;
+       }
 
        /* Restore original bio completion handler */
        bio->bi_end_io = bip->bip_end_io;
@@ -425,6 +429,7 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
+       bip->bip_iter.bi_sector += bytes_done >> 9;
        bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 EXPORT_SYMBOL(bio_integrity_advance);
@@ -432,22 +437,15 @@ EXPORT_SYMBOL(bio_integrity_advance);
 /**
  * bio_integrity_trim - Trim integrity vector
  * @bio:       bio whose integrity vector to update
- * @offset:    offset to first data sector
- * @sectors:   number of data sectors
  *
  * Description: Used to trim the integrity vector in a cloned bio.
- * The ivec will be advanced corresponding to 'offset' data sectors
- * and the length will be truncated corresponding to 'len' data
- * sectors.
  */
-void bio_integrity_trim(struct bio *bio, unsigned int offset,
-                       unsigned int sectors)
+void bio_integrity_trim(struct bio *bio)
 {
        struct bio_integrity_payload *bip = bio_integrity(bio);
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
 
-       bio_integrity_advance(bio, offset << 9);
-       bip->bip_iter.bi_size = bio_integrity_bytes(bi, sectors);
+       bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio));
 }
 EXPORT_SYMBOL(bio_integrity_trim);