]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Don't enter zvol's rangelock for read bio with size 0
authorTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Wed, 20 Feb 2019 18:14:36 +0000 (03:14 +0900)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 20 Feb 2019 18:14:36 +0000 (10:14 -0800)
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

module/zfs/zvol.c

index cc0f1d1e031499a5da287b04ce77eeb491438e2f..5ca4f4670a86f946f19cc95333180aef645c4acb 100644 (file)
@@ -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;