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;
|
AioContext *ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int xen_block_send_response(XenBlockRequest *request);
|
||||||
|
|
||||||
static void reset_request(XenBlockRequest *request)
|
static void reset_request(XenBlockRequest *request)
|
||||||
{
|
{
|
||||||
memset(&request->req, 0, sizeof(request->req));
|
memset(&request->req, 0, sizeof(request->req));
|
||||||
@ -115,23 +117,26 @@ out:
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_block_finish_request(XenBlockRequest *request)
|
static void xen_block_complete_request(XenBlockRequest *request)
|
||||||
{
|
{
|
||||||
XenBlockDataPlane *dataplane = request->dataplane;
|
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);
|
QLIST_REMOVE(request, list);
|
||||||
dataplane->requests_inflight--;
|
dataplane->requests_inflight--;
|
||||||
}
|
|
||||||
|
|
||||||
static void xen_block_release_request(XenBlockRequest *request)
|
|
||||||
{
|
|
||||||
XenBlockDataPlane *dataplane = request->dataplane;
|
|
||||||
|
|
||||||
QLIST_REMOVE(request, list);
|
|
||||||
reset_request(request);
|
reset_request(request);
|
||||||
request->dataplane = dataplane;
|
request->dataplane = dataplane;
|
||||||
QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
|
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_do_aio(XenBlockRequest *request);
|
||||||
static int xen_block_send_response(XenBlockRequest *request);
|
|
||||||
|
|
||||||
static void xen_block_complete_aio(void *opaque, int ret)
|
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;
|
request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||||
xen_block_finish_request(request);
|
|
||||||
|
|
||||||
switch (request->req.operation) {
|
switch (request->req.operation) {
|
||||||
case BLKIF_OP_WRITE:
|
case BLKIF_OP_WRITE:
|
||||||
@ -306,17 +309,8 @@ static void xen_block_complete_aio(void *opaque, int ret)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xen_block_send_response(request)) {
|
|
||||||
Error *local_err = NULL;
|
|
||||||
|
|
||||||
xen_device_notify_event_channel(dataplane->xendev,
|
xen_block_complete_request(request);
|
||||||
dataplane->event_channel,
|
|
||||||
&local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_report_err(local_err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xen_block_release_request(request);
|
|
||||||
|
|
||||||
if (dataplane->more_work) {
|
if (dataplane->more_work) {
|
||||||
qemu_bh_schedule(dataplane->bh);
|
qemu_bh_schedule(dataplane->bh);
|
||||||
@ -420,8 +414,8 @@ static int xen_block_do_aio(XenBlockRequest *request)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
xen_block_finish_request(request);
|
|
||||||
request->status = BLKIF_RSP_ERROR;
|
request->status = BLKIF_RSP_ERROR;
|
||||||
|
xen_block_complete_request(request);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,17 +569,7 @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (xen_block_send_response(request)) {
|
xen_block_complete_request(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);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user