--- /dev/null
+From e4b069e0945fa14c71cf8b5b89f8b1b2aa68dbc2 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 22 Aug 2018 12:45:51 -0400
+Subject: dm verity: fix crash on bufio buffer that was allocated with vmalloc
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit e4b069e0945fa14c71cf8b5b89f8b1b2aa68dbc2 upstream.
+
+Since commit d1ac3ff008fb ("dm verity: switch to using asynchronous hash
+crypto API") dm-verity uses asynchronous crypto calls for verification,
+so that it can use hardware with asynchronous processing of crypto
+operations.
+
+These asynchronous calls don't support vmalloc memory, but the buffer data
+can be allocated with vmalloc if dm-bufio is short of memory and uses a
+reserved buffer that was preallocated in dm_bufio_client_create().
+
+Fix verity_hash_update() so that it deals with vmalloc'd memory
+correctly.
+
+Reported-by: "Xiao, Jin" <jin.xiao@intel.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Fixes: d1ac3ff008fb ("dm verity: switch to using asynchronous hash crypto API")
+Cc: stable@vger.kernel.org # 4.12+
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+Acked-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/dm-verity-target.c | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+--- a/drivers/md/dm-verity-target.c
++++ b/drivers/md/dm-verity-target.c
+@@ -139,10 +139,26 @@ static int verity_hash_update(struct dm_
+ {
+ struct scatterlist sg;
+
+- sg_init_one(&sg, data, len);
+- ahash_request_set_crypt(req, &sg, NULL, len);
+-
+- return verity_complete_op(res, crypto_ahash_update(req));
++ if (likely(!is_vmalloc_addr(data))) {
++ sg_init_one(&sg, data, len);
++ ahash_request_set_crypt(req, &sg, NULL, len);
++ return verity_complete_op(res, crypto_ahash_update(req));
++ } else {
++ do {
++ int r;
++ size_t this_step = min_t(size_t, len, PAGE_SIZE - offset_in_page(data));
++ flush_kernel_vmap_range((void *)data, this_step);
++ sg_init_table(&sg, 1);
++ sg_set_page(&sg, vmalloc_to_page(data), this_step, offset_in_page(data));
++ ahash_request_set_crypt(req, &sg, NULL, this_step);
++ r = verity_complete_op(res, crypto_ahash_update(req));
++ if (unlikely(r))
++ return r;
++ data += this_step;
++ len -= this_step;
++ } while (len);
++ return 0;
++ }
+ }
+
+ /*
--- /dev/null
+From d57f9da890696af1484f4a47f7f123560197865a Mon Sep 17 00:00:00 2001
+From: Damien Le Moal <damien.lemoal@wdc.com>
+Date: Fri, 30 Nov 2018 15:31:48 +0900
+Subject: dm zoned: Fix target BIO completion handling
+
+From: Damien Le Moal <damien.lemoal@wdc.com>
+
+commit d57f9da890696af1484f4a47f7f123560197865a upstream.
+
+struct bioctx includes the ref refcount_t to track the number of I/O
+fragments used to process a target BIO as well as ensure that the zone
+of the BIO is kept in the active state throughout the lifetime of the
+BIO. However, since decrementing of this reference count is done in the
+target .end_io method, the function bio_endio() must be called multiple
+times for read and write target BIOs, which causes problems with the
+value of the __bi_remaining struct bio field for chained BIOs (e.g. the
+clone BIO passed by dm core is large and splits into fragments by the
+block layer), resulting in incorrect values and inconsistencies with the
+BIO_CHAIN flag setting. This is turn triggers the BUG_ON() call:
+
+BUG_ON(atomic_read(&bio->__bi_remaining) <= 0);
+
+in bio_remaining_done() called from bio_endio().
+
+Fix this ensuring that bio_endio() is called only once for any target
+BIO by always using internal clone BIOs for processing any read or
+write target BIO. This allows reference counting using the target BIO
+context counter to trigger the target BIO completion bio_endio() call
+once all data, metadata and other zone work triggered by the BIO
+complete.
+
+Overall, this simplifies the code too as the target .end_io becomes
+unnecessary and differences between read and write BIO issuing and
+completion processing disappear.
+
+Fixes: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target")
+Cc: stable@vger.kernel.org
+Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-zoned-target.c | 122 +++++++++++++------------------------------
+ 1 file changed, 38 insertions(+), 84 deletions(-)
+
+--- a/drivers/md/dm-zoned-target.c
++++ b/drivers/md/dm-zoned-target.c
+@@ -20,7 +20,6 @@ struct dmz_bioctx {
+ struct dm_zone *zone;
+ struct bio *bio;
+ atomic_t ref;
+- blk_status_t status;
+ };
+
+ /*
+@@ -78,65 +77,66 @@ static inline void dmz_bio_endio(struct
+ {
+ struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
+
+- if (bioctx->status == BLK_STS_OK && status != BLK_STS_OK)
+- bioctx->status = status;
+- bio_endio(bio);
++ if (status != BLK_STS_OK && bio->bi_status == BLK_STS_OK)
++ bio->bi_status = status;
++
++ if (atomic_dec_and_test(&bioctx->ref)) {
++ struct dm_zone *zone = bioctx->zone;
++
++ if (zone) {
++ if (bio->bi_status != BLK_STS_OK &&
++ bio_op(bio) == REQ_OP_WRITE &&
++ dmz_is_seq(zone))
++ set_bit(DMZ_SEQ_WRITE_ERR, &zone->flags);
++ dmz_deactivate_zone(zone);
++ }
++ bio_endio(bio);
++ }
+ }
+
+ /*
+- * Partial clone read BIO completion callback. This terminates the
++ * Completion callback for an internally cloned target BIO. This terminates the
+ * target BIO when there are no more references to its context.
+ */
+-static void dmz_read_bio_end_io(struct bio *bio)
++static void dmz_clone_endio(struct bio *clone)
+ {
+- struct dmz_bioctx *bioctx = bio->bi_private;
+- blk_status_t status = bio->bi_status;
++ struct dmz_bioctx *bioctx = clone->bi_private;
++ blk_status_t status = clone->bi_status;
+
+- bio_put(bio);
++ bio_put(clone);
+ dmz_bio_endio(bioctx->bio, status);
+ }
+
+ /*
+- * Issue a BIO to a zone. The BIO may only partially process the
++ * Issue a clone of a target BIO. The clone may only partially process the
+ * original target BIO.
+ */
+-static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone,
+- struct bio *bio, sector_t chunk_block,
+- unsigned int nr_blocks)
++static int dmz_submit_bio(struct dmz_target *dmz, struct dm_zone *zone,
++ struct bio *bio, sector_t chunk_block,
++ unsigned int nr_blocks)
+ {
+ struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
+- sector_t sector;
+ struct bio *clone;
+
+- /* BIO remap sector */
+- sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
+-
+- /* If the read is not partial, there is no need to clone the BIO */
+- if (nr_blocks == dmz_bio_blocks(bio)) {
+- /* Setup and submit the BIO */
+- bio->bi_iter.bi_sector = sector;
+- atomic_inc(&bioctx->ref);
+- generic_make_request(bio);
+- return 0;
+- }
+-
+- /* Partial BIO: we need to clone the BIO */
+ clone = bio_clone_fast(bio, GFP_NOIO, dmz->bio_set);
+ if (!clone)
+ return -ENOMEM;
+
+- /* Setup the clone */
+- clone->bi_iter.bi_sector = sector;
++ bio_set_dev(clone, dmz->dev->bdev);
++ clone->bi_iter.bi_sector =
++ dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
+ clone->bi_iter.bi_size = dmz_blk2sect(nr_blocks) << SECTOR_SHIFT;
+- clone->bi_end_io = dmz_read_bio_end_io;
++ clone->bi_end_io = dmz_clone_endio;
+ clone->bi_private = bioctx;
+
+ bio_advance(bio, clone->bi_iter.bi_size);
+
+- /* Submit the clone */
+ atomic_inc(&bioctx->ref);
+ generic_make_request(clone);
+
++ if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
++ zone->wp_block += nr_blocks;
++
+ return 0;
+ }
+
+@@ -214,7 +214,7 @@ static int dmz_handle_read(struct dmz_ta
+ if (nr_blocks) {
+ /* Valid blocks found: read them */
+ nr_blocks = min_t(unsigned int, nr_blocks, end_block - chunk_block);
+- ret = dmz_submit_read_bio(dmz, rzone, bio, chunk_block, nr_blocks);
++ ret = dmz_submit_bio(dmz, rzone, bio, chunk_block, nr_blocks);
+ if (ret)
+ return ret;
+ chunk_block += nr_blocks;
+@@ -229,25 +229,6 @@ static int dmz_handle_read(struct dmz_ta
+ }
+
+ /*
+- * Issue a write BIO to a zone.
+- */
+-static void dmz_submit_write_bio(struct dmz_target *dmz, struct dm_zone *zone,
+- struct bio *bio, sector_t chunk_block,
+- unsigned int nr_blocks)
+-{
+- struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
+-
+- /* Setup and submit the BIO */
+- bio_set_dev(bio, dmz->dev->bdev);
+- bio->bi_iter.bi_sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
+- atomic_inc(&bioctx->ref);
+- generic_make_request(bio);
+-
+- if (dmz_is_seq(zone))
+- zone->wp_block += nr_blocks;
+-}
+-
+-/*
+ * Write blocks directly in a data zone, at the write pointer.
+ * If a buffer zone is assigned, invalidate the blocks written
+ * in place.
+@@ -265,7 +246,9 @@ static int dmz_handle_direct_write(struc
+ return -EROFS;
+
+ /* Submit write */
+- dmz_submit_write_bio(dmz, zone, bio, chunk_block, nr_blocks);
++ ret = dmz_submit_bio(dmz, zone, bio, chunk_block, nr_blocks);
++ if (ret)
++ return ret;
+
+ /*
+ * Validate the blocks in the data zone and invalidate
+@@ -301,7 +284,9 @@ static int dmz_handle_buffered_write(str
+ return -EROFS;
+
+ /* Submit write */
+- dmz_submit_write_bio(dmz, bzone, bio, chunk_block, nr_blocks);
++ ret = dmz_submit_bio(dmz, bzone, bio, chunk_block, nr_blocks);
++ if (ret)
++ return ret;
+
+ /*
+ * Validate the blocks in the buffer zone
+@@ -600,7 +585,6 @@ static int dmz_map(struct dm_target *ti,
+ bioctx->zone = NULL;
+ bioctx->bio = bio;
+ atomic_set(&bioctx->ref, 1);
+- bioctx->status = BLK_STS_OK;
+
+ /* Set the BIO pending in the flush list */
+ if (!nr_sectors && bio_op(bio) == REQ_OP_WRITE) {
+@@ -624,35 +608,6 @@ static int dmz_map(struct dm_target *ti,
+ }
+
+ /*
+- * Completed target BIO processing.
+- */
+-static int dmz_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *error)
+-{
+- struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
+-
+- if (bioctx->status == BLK_STS_OK && *error)
+- bioctx->status = *error;
+-
+- if (!atomic_dec_and_test(&bioctx->ref))
+- return DM_ENDIO_INCOMPLETE;
+-
+- /* Done */
+- bio->bi_status = bioctx->status;
+-
+- if (bioctx->zone) {
+- struct dm_zone *zone = bioctx->zone;
+-
+- if (*error && bio_op(bio) == REQ_OP_WRITE) {
+- if (dmz_is_seq(zone))
+- set_bit(DMZ_SEQ_WRITE_ERR, &zone->flags);
+- }
+- dmz_deactivate_zone(zone);
+- }
+-
+- return DM_ENDIO_DONE;
+-}
+-
+-/*
+ * Get zoned device information.
+ */
+ static int dmz_get_zoned_device(struct dm_target *ti, char *path)
+@@ -946,7 +901,6 @@ static struct target_type dmz_type = {
+ .ctr = dmz_ctr,
+ .dtr = dmz_dtr,
+ .map = dmz_map,
+- .end_io = dmz_end_io,
+ .io_hints = dmz_io_hints,
+ .prepare_ioctl = dmz_prepare_ioctl,
+ .postsuspend = dmz_suspend,