xen-block: Fix double qlist remove and request leak
Commit a31ca6801c02 ("qemu/queue.h: clear linked list pointers on remove") revealed that a request was removed twice from a list, once in xen_block_finish_request() and a second time in xen_block_release_request() when both function are called from xen_block_complete_aio(). But also, the `requests_inflight' counter is decreased twice, and thus became negative. This is a bug that was introduced in bfd0d6366043 ("xen-block: improve response latency"), where a `finished' list was removed. That commit also introduced a leak of request in xen_block_do_aio(). That function calls xen_block_finish_request() but the request is never released after that. To fix both issue, we do two changes: - we squash finish_request() and release_request() together as we want to remove a request from 'inflight' list to add it to 'freelist'. - before releasing a request, we need to let the other end know the result, thus we should call xen_block_send_response() before releasing a request. The first change fixes the double QLIST_REMOVE() as we remove the extra call. The second change makes the leak go away because if we want to call finish_request(), we need to call a function that does all of finish, send response, and release. Fixes: bfd0d6366043 ("xen-block: improve response latency") Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Message-Id: <20200406140217.1441858-1-anthony.perard@citrix.com> Reviewed-by: Paul Durrant <paul@xen.org> [mreitz: Amended commit message as per Paul's suggestions] Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
25fb2e9c39
commit
36d883ba0d
@ -64,6 +64,8 @@ struct XenBlockDataPlane {
|
||||
AioContext *ctx;
|
||||
};
|
||||
|
||||
static int xen_block_send_response(XenBlockRequest *request);
|
||||
|
||||
static void reset_request(XenBlockRequest *request)
|
||||
{
|
||||
memset(&request->req, 0, sizeof(request->req));
|
||||
@ -115,23 +117,26 @@ out:
|
||||
return request;
|
||||
}
|
||||
|
||||
static void xen_block_finish_request(XenBlockRequest *request)
|
||||
static void xen_block_complete_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
if (xen_block_send_response(request)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_notify_event_channel(dataplane->xendev,
|
||||
dataplane->event_channel,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
|
||||
QLIST_REMOVE(request, list);
|
||||
dataplane->requests_inflight--;
|
||||
}
|
||||
|
||||
static void xen_block_release_request(XenBlockRequest *request)
|
||||
{
|
||||
XenBlockDataPlane *dataplane = request->dataplane;
|
||||
|
||||
QLIST_REMOVE(request, list);
|
||||
reset_request(request);
|
||||
request->dataplane = dataplane;
|
||||
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
|
||||
dataplane->requests_inflight--;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -246,7 +251,6 @@ static int xen_block_copy_request(XenBlockRequest *request)
|
||||
}
|
||||
|
||||
static int xen_block_do_aio(XenBlockRequest *request);
|
||||
static int xen_block_send_response(XenBlockRequest *request);
|
||||
|
||||
static void xen_block_complete_aio(void *opaque, int ret)
|
||||
{
|
||||
@ -286,7 +290,6 @@ static void xen_block_complete_aio(void *opaque, int ret)
|
||||
}
|
||||
|
||||
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||
xen_block_finish_request(request);
|
||||
|
||||
switch (request->req.operation) {
|
||||
case BLKIF_OP_WRITE:
|
||||
@ -306,17 +309,8 @@ static void xen_block_complete_aio(void *opaque, int ret)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (xen_block_send_response(request)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_notify_event_channel(dataplane->xendev,
|
||||
dataplane->event_channel,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
xen_block_release_request(request);
|
||||
xen_block_complete_request(request);
|
||||
|
||||
if (dataplane->more_work) {
|
||||
qemu_bh_schedule(dataplane->bh);
|
||||
@ -420,8 +414,8 @@ static int xen_block_do_aio(XenBlockRequest *request)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
xen_block_finish_request(request);
|
||||
request->status = BLKIF_RSP_ERROR;
|
||||
xen_block_complete_request(request);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -575,17 +569,7 @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
|
||||
break;
|
||||
};
|
||||
|
||||
if (xen_block_send_response(request)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
xen_device_notify_event_channel(dataplane->xendev,
|
||||
dataplane->event_channel,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
}
|
||||
xen_block_release_request(request);
|
||||
xen_block_complete_request(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user