1 /*
2 * reqlist API
3 *
4 * Copyright (C) 2013 Proxmox Server Solutions
5 * Copyright (c) 2021 Virtuozzo International GmbH.
6 *
7 * Authors:
8 * Dietmar Maurer (dietmar@proxmox.com)
9 * Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10 *
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
13 */
14
15 #include "qemu/osdep.h"
16 #include "qemu/range.h"
17
18 #include "block/reqlist.h"
19
reqlist_init_req(BlockReqList * reqs,BlockReq * req,int64_t offset,int64_t bytes)20 void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
21 int64_t bytes)
22 {
23 *req = (BlockReq) {
24 .offset = offset,
25 .bytes = bytes,
26 };
27 qemu_co_queue_init(&req->wait_queue);
28 QLIST_INSERT_HEAD(reqs, req, list);
29 }
30
reqlist_find_conflict(BlockReqList * reqs,int64_t offset,int64_t bytes)31 BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
32 int64_t bytes)
33 {
34 BlockReq *r;
35
36 QLIST_FOREACH(r, reqs, list) {
37 if (ranges_overlap(offset, bytes, r->offset, r->bytes)) {
38 return r;
39 }
40 }
41
42 return NULL;
43 }
44
reqlist_wait_one(BlockReqList * reqs,int64_t offset,int64_t bytes,CoMutex * lock)45 bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
46 int64_t bytes, CoMutex *lock)
47 {
48 BlockReq *r = reqlist_find_conflict(reqs, offset, bytes);
49
50 if (!r) {
51 return false;
52 }
53
54 qemu_co_queue_wait(&r->wait_queue, lock);
55
56 return true;
57 }
58
reqlist_wait_all(BlockReqList * reqs,int64_t offset,int64_t bytes,CoMutex * lock)59 void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
60 int64_t bytes, CoMutex *lock)
61 {
62 while (reqlist_wait_one(reqs, offset, bytes, lock)) {
63 /* continue */
64 }
65 }
66
reqlist_shrink_req(BlockReq * req,int64_t new_bytes)67 void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes)
68 {
69 if (new_bytes == req->bytes) {
70 return;
71 }
72
73 assert(new_bytes > 0 && new_bytes < req->bytes);
74
75 req->bytes = new_bytes;
76 qemu_co_queue_restart_all(&req->wait_queue);
77 }
78
reqlist_remove_req(BlockReq * req)79 void coroutine_fn reqlist_remove_req(BlockReq *req)
80 {
81 QLIST_REMOVE(req, list);
82 qemu_co_queue_restart_all(&req->wait_queue);
83 }
84