Skip to content

Commit

Permalink
UBUNTU: SAUCE: hv/bounce buffer: Fix a race that can fail disk detection
Browse files Browse the repository at this point in the history
As soon as hv_ringbuffer_write() returns, the host's response can arrive
immediately, and the channel callback of hv_storvsc can be called -- at
this time, if the "*pbounce_pkt" is still not assigned, the channel
callback is unable to find the bounce_pkt info, and consequently
storvsc_on_channel_callback() -> hv_pkt_bounce() is not called,
i.e. the bounce buffer is leaked and we fail to copy the bounce buffer
to the private SCSI response buffer, and from the VM's perspective it
looks like the host didn't write the response, and the VM's SCSI commands
(e.g. INQUERY, READ) may fail unexpectedly, and sometimes some of the
disks can not be detected properly.

Fix the race by moving the *pbounce_pkt line to before
hv_ringbuffer_write(), and resetting it if hv_ringbuffer_write() fails.

Fixes: df6c139 ("UBUNTU: SAUCE: x86/Hyper-V: Copy data from/to bounce buffer during IO operation.")
Signed-off-by: Dexuan Cui <decui@microsoft.com>
  • Loading branch information
dcui committed Apr 30, 2022
1 parent 28cbf53 commit ddde4dc
Showing 1 changed file with 26 additions and 6 deletions.
32 changes: 26 additions & 6 deletions drivers/hv/hv_bounce.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,21 @@ int vmbus_sendpacket_pagebuffer_bounce(
(struct hv_page_range *)desc->range, io_type);
if (unlikely(!bounce_pkt))
return -EAGAIN;

/*
* This assignment must be before hv_ringbuffer_write(), because as
* soon as hv_ringbuffer_write() returns, the channel callback may
* be running, and the callback needs request->bounce_pkt, which is
* assigned in this function. Note: if hv_ringbuffer_write() fails,
* *pbounce_pkt must be reset to NULL.
*/
*pbounce_pkt = bounce_pkt;

ret = hv_ringbuffer_write(channel, bufferlist, 3, requestid);
if (unlikely(ret < 0))
if (unlikely(ret < 0)) {
hv_bounce_resources_release(channel, bounce_pkt);
else
*pbounce_pkt = bounce_pkt;
*pbounce_pkt = NULL;
}

return ret;
}
Expand Down Expand Up @@ -619,13 +629,23 @@ int vmbus_sendpacket_mpb_desc_bounce(
if (unlikely(!bounce_pkt))
goto free;
bufferlist[0].iov_base = desc_bounce;

/*
* This assignment must be before hv_ringbuffer_write(), because as
* soon as hv_ringbuffer_write() returns, the channel callback may
* be running, and the callback needs request->bounce_pkt, which is
* assigned in this function. Note: if hv_ringbuffer_write() fails,
* *pbounce_pkt must be reset to NULL.
*/
*pbounce_pkt = bounce_pkt;

ret = hv_ringbuffer_write(channel, bufferlist, 3, requestid);
free:
kfree(desc_bounce);
if (unlikely(ret < 0))
if (unlikely(ret < 0)) {
hv_bounce_resources_release(channel, bounce_pkt);
else
*pbounce_pkt = bounce_pkt;
*pbounce_pkt = NULL;
}
return ret;
}

Expand Down

0 comments on commit ddde4dc

Please sign in to comment.