We do lock qcow2 s->lock only to remove request from the reqlist. That's quite inefficient. Let's implement atomic operation to avoid extra critical section.
So new interface is: 1. Instead of reqlist_free_req() user may call atomic reqlist_mark_req_invalid(). 2. At some moment under mutex user calls reqlist_free_invalid_reqs() to free RAM. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- include/block/reqlist.h | 13 +++++++++++++ block/reqlist.c | 23 ++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/block/reqlist.h b/include/block/reqlist.h index 32dc87666f..24d6d93a6e 100644 --- a/include/block/reqlist.h +++ b/include/block/reqlist.h @@ -26,6 +26,7 @@ typedef struct BlockReq { int64_t offset; int64_t bytes; + bool valid; CoQueue wait_queue; /* coroutines blocked on this req */ QLIST_ENTRY(BlockReq) list; @@ -84,4 +85,16 @@ static inline void reqlist_free_req(BlockReq *req) } } +/* + * Invalid request will be ignored when searching for conflicts. + * The function modifies .valid atomically and intended for use when we + * want to avoid using mutex. + * If you use this function don't forget to also call + * reqlist_free_invalid_reqs() sometimes, so that list doesn't grow endlessly. + */ +void reqlist_mark_req_invalid(BlockReq *req); + +/* Remove all invalid requests to free RAM space */ +void reqlist_free_invalid_reqs(BlockReqList *reqs); + #endif /* REQLIST_H */ diff --git a/block/reqlist.c b/block/reqlist.c index c580752db7..641307d80d 100644 --- a/block/reqlist.c +++ b/block/reqlist.c @@ -14,6 +14,8 @@ #include "qemu/osdep.h" +#include "qemu/atomic.h" + #include "block/reqlist.h" void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset, @@ -22,6 +24,7 @@ void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset, *req = (BlockReq) { .offset = offset, .bytes = bytes, + .valid = true, }; qemu_co_queue_init(&req->wait_queue); QLIST_INSERT_HEAD(reqs, req, list); @@ -33,7 +36,9 @@ BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset, BlockReq *r; QLIST_FOREACH(r, reqs, list) { - if (offset + bytes > r->offset && offset < r->offset + r->bytes) { + if (r->valid && + offset + bytes > r->offset && offset < r->offset + r->bytes) + { return r; } } @@ -72,3 +77,19 @@ void coroutine_fn reqlist_remove_req(BlockReq *req) QLIST_REMOVE(req, list); qemu_co_queue_restart_all(&req->wait_queue); } + +void reqlist_mark_req_invalid(BlockReq *req) +{ + qatomic_set(&req->valid, false); +} + +void reqlist_free_invalid_reqs(BlockReqList *reqs) +{ + BlockReq *r, *next; + + QLIST_FOREACH_SAFE(r, reqs, list, next) { + if (!r->valid) { + reqlist_free_req(r); + } + } +} -- 2.29.2