]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Jan 2019 19:26:53 +0000 (20:26 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Jan 2019 19:26:53 +0000 (20:26 +0100)
added patches:
dm-verity-fix-crash-on-bufio-buffer-that-was-allocated-with-vmalloc.patch
dm-zoned-fix-target-bio-completion-handling.patch
vhost-vsock-fix-uninitialized-vhost_vsock-guest_cid.patch

queue-4.14/dm-verity-fix-crash-on-bufio-buffer-that-was-allocated-with-vmalloc.patch [new file with mode: 0644]
queue-4.14/dm-zoned-fix-target-bio-completion-handling.patch [new file with mode: 0644]
queue-4.14/series
queue-4.14/vhost-vsock-fix-uninitialized-vhost_vsock-guest_cid.patch [new file with mode: 0644]

diff --git a/queue-4.14/dm-verity-fix-crash-on-bufio-buffer-that-was-allocated-with-vmalloc.patch b/queue-4.14/dm-verity-fix-crash-on-bufio-buffer-that-was-allocated-with-vmalloc.patch
new file mode 100644 (file)
index 0000000..eabc32c
--- /dev/null
@@ -0,0 +1,66 @@
+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;
++      }
+ }
+ /*
diff --git a/queue-4.14/dm-zoned-fix-target-bio-completion-handling.patch b/queue-4.14/dm-zoned-fix-target-bio-completion-handling.patch
new file mode 100644 (file)
index 0000000..596c334
--- /dev/null
@@ -0,0 +1,261 @@
+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,
index e99e81dee2d44833a410e7536ae01f87601ea57b..eb31684ea4cefd130588b950b58dfd7510dc16e3 100644 (file)
@@ -75,3 +75,6 @@ kbuild-consolidate-clang-compiler-flags.patch
 makefile-export-clang-toolchain-variables.patch
 powerpc-boot-set-target-when-cross-compiling-for-clang.patch
 raid6-ppc-fix-build-for-clang.patch
+vhost-vsock-fix-uninitialized-vhost_vsock-guest_cid.patch
+dm-verity-fix-crash-on-bufio-buffer-that-was-allocated-with-vmalloc.patch
+dm-zoned-fix-target-bio-completion-handling.patch
diff --git a/queue-4.14/vhost-vsock-fix-uninitialized-vhost_vsock-guest_cid.patch b/queue-4.14/vhost-vsock-fix-uninitialized-vhost_vsock-guest_cid.patch
new file mode 100644 (file)
index 0000000..20e2188
--- /dev/null
@@ -0,0 +1,36 @@
+From a72b69dc083a931422cc8a5e33841aff7d5312f2 Mon Sep 17 00:00:00 2001
+From: Stefan Hajnoczi <stefanha@redhat.com>
+Date: Thu, 9 Nov 2017 13:29:10 +0000
+Subject: vhost/vsock: fix uninitialized vhost_vsock->guest_cid
+
+From: Stefan Hajnoczi <stefanha@redhat.com>
+
+commit a72b69dc083a931422cc8a5e33841aff7d5312f2 upstream.
+
+The vhost_vsock->guest_cid field is uninitialized when /dev/vhost-vsock
+is opened until the VHOST_VSOCK_SET_GUEST_CID ioctl is called.
+
+kvmalloc(..., GFP_KERNEL | __GFP_RETRY_MAYFAIL) does not zero memory.
+All other vhost_vsock fields are initialized explicitly so just
+initialize this field too.
+
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Cc: Daniel Verkamp <dverkamp@chromium.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/vhost/vsock.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/vhost/vsock.c
++++ b/drivers/vhost/vsock.c
+@@ -522,6 +522,8 @@ static int vhost_vsock_dev_open(struct i
+               goto out;
+       }
++      vsock->guest_cid = 0; /* no CID assigned yet */
++
+       atomic_set(&vsock->queued_replies, 0);
+       vqs[VSOCK_VQ_TX] = &vsock->vqs[VSOCK_VQ_TX];