aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomohiro Kusumi <[email protected]>2019-02-21 03:14:36 +0900
committerBrian Behlendorf <[email protected]>2019-02-20 10:14:36 -0800
commit9abbee491285303d78704e937a13ddcbb6cd0f79 (patch)
treebf8573d4e654389623c199bdfdc8830c8dbb269f
parent1e427f2e2b8da17bdddada3926648692bc1ffae0 (diff)
Don't enter zvol's rangelock for read bio with size 0
The SCST driver (SCSI target driver implementation) and possibly others may issue read bio's with a length of zero bytes. Although this is unusual, such bio's issued under certain condition can cause kernel oops, due to how rangelock is implemented. rangelock_add_reader() is not made to handle overlap of two (or more) ranges from read bio's with the same offset when one of them has size of 0, even though they conceptually overlap. Allowing them to enter rangelock results in kernel oops by dereferencing invalid pointer, or assertion failure on AVL tree manipulation with debug enabled kernel module. For example, this happens when read bio whose (offset, size) is (0, 0) enters rangelock followed by another read bio with (0, 4096) when (0, 0) rangelock is still locked, when there are no pending write bio's. It can also happen with reverse order, which is (0, N) followed by (0, 0) when (0, N) is still locked. More details mentioned in #8379. Kernel Oops on ->make_request_fn() of ZFS volume https://github.com/zfsonlinux/zfs/issues/8379 Prevent this by returning bio with size 0 as success without entering rangelock. This has been done for write bio after checking flusher bio case (though not for the same reason), but not for read bio. Reviewed-by: Alek Pinchuk <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Tomohiro Kusumi <[email protected]> Closes #8379 Closes #8401
-rw-r--r--module/zfs/zvol.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index cc0f1d1e0..5ca4f4670 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -1008,6 +1008,16 @@ zvol_request(struct request_queue *q, struct bio *bio)
zvol_write(zvr);
}
} else {
+ /*
+ * The SCST driver, and possibly others, may issue READ I/Os
+ * with a length of zero bytes. These empty I/Os contain no
+ * data and require no additional handling.
+ */
+ if (size == 0) {
+ BIO_END_IO(bio, 0);
+ goto out;
+ }
+
zvr = kmem_alloc(sizeof (zv_request_t), KM_SLEEP);
zvr->zv = zv;
zvr->bio = bio;