diff options
author | Tomohiro Kusumi <[email protected]> | 2019-02-21 03:14:36 +0900 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-02-20 10:14:36 -0800 |
commit | 9abbee491285303d78704e937a13ddcbb6cd0f79 (patch) | |
tree | bf8573d4e654389623c199bdfdc8830c8dbb269f | |
parent | 1e427f2e2b8da17bdddada3926648692bc1ffae0 (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.c | 10 |
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; |