xref: /openbmc/qemu/block/reqlist.c (revision 954a6c4f)
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 
20 void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
21                       int64_t bytes)
22 {
23     assert(!reqlist_find_conflict(reqs, offset, bytes));
24 
25     *req = (BlockReq) {
26         .offset = offset,
27         .bytes = bytes,
28     };
29     qemu_co_queue_init(&req->wait_queue);
30     QLIST_INSERT_HEAD(reqs, req, list);
31 }
32 
33 BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
34                                 int64_t bytes)
35 {
36     BlockReq *r;
37 
38     QLIST_FOREACH(r, reqs, list) {
39         if (ranges_overlap(offset, bytes, r->offset, r->bytes)) {
40             return r;
41         }
42     }
43 
44     return NULL;
45 }
46 
47 bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
48                                    int64_t bytes, CoMutex *lock)
49 {
50     BlockReq *r = reqlist_find_conflict(reqs, offset, bytes);
51 
52     if (!r) {
53         return false;
54     }
55 
56     qemu_co_queue_wait(&r->wait_queue, lock);
57 
58     return true;
59 }
60 
61 void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
62                                    int64_t bytes, CoMutex *lock)
63 {
64     while (reqlist_wait_one(reqs, offset, bytes, lock)) {
65         /* continue */
66     }
67 }
68 
69 void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes)
70 {
71     if (new_bytes == req->bytes) {
72         return;
73     }
74 
75     assert(new_bytes > 0 && new_bytes < req->bytes);
76 
77     req->bytes = new_bytes;
78     qemu_co_queue_restart_all(&req->wait_queue);
79 }
80 
81 void coroutine_fn reqlist_remove_req(BlockReq *req)
82 {
83     QLIST_REMOVE(req, list);
84     qemu_co_queue_restart_all(&req->wait_queue);
85 }
86