mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
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 <apinchuk@datto.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tomohiro Kusumi <kusumi.tomohiro@osnexus.com> Closes #8379 Closes #8401
This commit is contained in:
parent
1e427f2e2b
commit
9abbee4912
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user