diff options
author | Tomohiro Kusumi <[email protected]> | 2019-07-04 05:03:22 +0900 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-07-03 13:03:22 -0700 |
commit | aa7aab6c457f106d2b794b9adf3fe5aa451ad8e9 (patch) | |
tree | c5ce66e37169c22d02da8b546a9a48cedcc50ddd | |
parent | 46db9d6161d0781f00ee3cb5bc02e11685d2ffaf (diff) |
Fail early on bio corruption confirmed on 5.2-rc1
Unable to import zpool with "Large kmem_alloc" warning due to
corrupted bio's with invalid # of page vectors.
See #8867 for details.
Fail early with ENOMEM.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Tony Hutter <[email protected]>
Signed-off-by: Tomohiro Kusumi <[email protected]>
Closes #8867
Closes #8961
-rw-r--r-- | module/zfs/vdev_disk.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index 1686ddfce..8f06c4117 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -621,6 +621,7 @@ retry: bio_offset = io_offset; bio_size = io_size; for (i = 0; i <= dr->dr_bio_count; i++) { + unsigned int nr_iovecs; /* Finished constructing bio's for given buffer */ if (bio_size <= 0) @@ -638,10 +639,11 @@ retry: } /* bio_alloc() with __GFP_WAIT never returns NULL */ - dr->dr_bio[i] = bio_alloc(GFP_NOIO, - MIN(abd_nr_pages_off(zio->io_abd, bio_size, abd_offset), - BIO_MAX_PAGES)); - if (unlikely(dr->dr_bio[i] == NULL)) { + nr_iovecs = MIN(abd_nr_pages_off(zio->io_abd, bio_size, + abd_offset), BIO_MAX_PAGES); + dr->dr_bio[i] = bio_alloc(GFP_NOIO, nr_iovecs); + if (unlikely(dr->dr_bio[i] == NULL || + (unsigned int)dr->dr_bio[i]->bi_max_vecs != nr_iovecs)) { vdev_disk_dio_free(dr); return (SET_ERROR(ENOMEM)); } |