xref: /openbmc/qemu/include/block/reqlist.h (revision b49872aa8fc0f3f5a3036cc37aa2cb5c92866f33)
1d088e6a4SVladimir Sementsov-Ogievskiy /*
2d088e6a4SVladimir Sementsov-Ogievskiy  * reqlist API
3d088e6a4SVladimir Sementsov-Ogievskiy  *
4d088e6a4SVladimir Sementsov-Ogievskiy  * Copyright (C) 2013 Proxmox Server Solutions
5d088e6a4SVladimir Sementsov-Ogievskiy  * Copyright (c) 2021 Virtuozzo International GmbH.
6d088e6a4SVladimir Sementsov-Ogievskiy  *
7d088e6a4SVladimir Sementsov-Ogievskiy  * Authors:
8d088e6a4SVladimir Sementsov-Ogievskiy  *  Dietmar Maurer (dietmar@proxmox.com)
9d088e6a4SVladimir Sementsov-Ogievskiy  *  Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10d088e6a4SVladimir Sementsov-Ogievskiy  *
11d088e6a4SVladimir Sementsov-Ogievskiy  * This work is licensed under the terms of the GNU GPL, version 2 or later.
12d088e6a4SVladimir Sementsov-Ogievskiy  * See the COPYING file in the top-level directory.
13d088e6a4SVladimir Sementsov-Ogievskiy  */
14d088e6a4SVladimir Sementsov-Ogievskiy 
15d088e6a4SVladimir Sementsov-Ogievskiy #ifndef REQLIST_H
16d088e6a4SVladimir Sementsov-Ogievskiy #define REQLIST_H
17d088e6a4SVladimir Sementsov-Ogievskiy 
18d088e6a4SVladimir Sementsov-Ogievskiy #include "qemu/coroutine.h"
19d088e6a4SVladimir Sementsov-Ogievskiy 
20d088e6a4SVladimir Sementsov-Ogievskiy /*
21d088e6a4SVladimir Sementsov-Ogievskiy  * The API is not thread-safe and shouldn't be. The struct is public to be part
22d088e6a4SVladimir Sementsov-Ogievskiy  * of other structures and protected by third-party locks, see
23d088e6a4SVladimir Sementsov-Ogievskiy  * block/block-copy.c for example.
24d088e6a4SVladimir Sementsov-Ogievskiy  */
25d088e6a4SVladimir Sementsov-Ogievskiy 
26d088e6a4SVladimir Sementsov-Ogievskiy typedef struct BlockReq {
27d088e6a4SVladimir Sementsov-Ogievskiy     int64_t offset;
28d088e6a4SVladimir Sementsov-Ogievskiy     int64_t bytes;
29d088e6a4SVladimir Sementsov-Ogievskiy 
30d088e6a4SVladimir Sementsov-Ogievskiy     CoQueue wait_queue; /* coroutines blocked on this req */
31d088e6a4SVladimir Sementsov-Ogievskiy     QLIST_ENTRY(BlockReq) list;
32d088e6a4SVladimir Sementsov-Ogievskiy } BlockReq;
33d088e6a4SVladimir Sementsov-Ogievskiy 
34d088e6a4SVladimir Sementsov-Ogievskiy typedef QLIST_HEAD(, BlockReq) BlockReqList;
35d088e6a4SVladimir Sementsov-Ogievskiy 
36d088e6a4SVladimir Sementsov-Ogievskiy /*
37d088e6a4SVladimir Sementsov-Ogievskiy  * Initialize new request and add it to the list. Caller must be sure that
38d088e6a4SVladimir Sementsov-Ogievskiy  * there are no conflicting requests in the list.
39d088e6a4SVladimir Sementsov-Ogievskiy  */
40d088e6a4SVladimir Sementsov-Ogievskiy void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
41d088e6a4SVladimir Sementsov-Ogievskiy                       int64_t bytes);
42d088e6a4SVladimir Sementsov-Ogievskiy /* Search for request in the list intersecting with @offset/@bytes area. */
43d088e6a4SVladimir Sementsov-Ogievskiy BlockReq *reqlist_find_conflict(BlockReqList *reqs, int64_t offset,
44d088e6a4SVladimir Sementsov-Ogievskiy                                 int64_t bytes);
45d088e6a4SVladimir Sementsov-Ogievskiy 
46d088e6a4SVladimir Sementsov-Ogievskiy /*
47d088e6a4SVladimir Sementsov-Ogievskiy  * If there are no intersecting requests return false. Otherwise, wait for the
48d088e6a4SVladimir Sementsov-Ogievskiy  * first found intersecting request to finish and return true.
49d088e6a4SVladimir Sementsov-Ogievskiy  *
50d088e6a4SVladimir Sementsov-Ogievskiy  * @lock is passed to qemu_co_queue_wait()
51d088e6a4SVladimir Sementsov-Ogievskiy  * False return value proves that lock was released at no point.
52d088e6a4SVladimir Sementsov-Ogievskiy  */
53d088e6a4SVladimir Sementsov-Ogievskiy bool coroutine_fn reqlist_wait_one(BlockReqList *reqs, int64_t offset,
54d088e6a4SVladimir Sementsov-Ogievskiy                                    int64_t bytes, CoMutex *lock);
55d088e6a4SVladimir Sementsov-Ogievskiy 
56d088e6a4SVladimir Sementsov-Ogievskiy /*
57*3b7ca26bSVladimir Sementsov-Ogievskiy  * Wait for all intersecting requests. It just calls reqlist_wait_one() in a
58*3b7ca26bSVladimir Sementsov-Ogievskiy  * loop, caller is responsible to stop producing new requests in this region
59*3b7ca26bSVladimir Sementsov-Ogievskiy  * in parallel, otherwise reqlist_wait_all() may never return.
60*3b7ca26bSVladimir Sementsov-Ogievskiy  */
61*3b7ca26bSVladimir Sementsov-Ogievskiy void coroutine_fn reqlist_wait_all(BlockReqList *reqs, int64_t offset,
62*3b7ca26bSVladimir Sementsov-Ogievskiy                                    int64_t bytes, CoMutex *lock);
63*3b7ca26bSVladimir Sementsov-Ogievskiy 
64*3b7ca26bSVladimir Sementsov-Ogievskiy /*
65d088e6a4SVladimir Sementsov-Ogievskiy  * Shrink request and wake all waiting coroutines (maybe some of them are not
66d088e6a4SVladimir Sementsov-Ogievskiy  * intersecting with shrunk request).
67d088e6a4SVladimir Sementsov-Ogievskiy  */
68d088e6a4SVladimir Sementsov-Ogievskiy void coroutine_fn reqlist_shrink_req(BlockReq *req, int64_t new_bytes);
69d088e6a4SVladimir Sementsov-Ogievskiy 
70d088e6a4SVladimir Sementsov-Ogievskiy /*
71d088e6a4SVladimir Sementsov-Ogievskiy  * Remove request and wake all waiting coroutines. Do not release any memory.
72d088e6a4SVladimir Sementsov-Ogievskiy  */
73d088e6a4SVladimir Sementsov-Ogievskiy void coroutine_fn reqlist_remove_req(BlockReq *req);
74d088e6a4SVladimir Sementsov-Ogievskiy 
75d088e6a4SVladimir Sementsov-Ogievskiy #endif /* REQLIST_H */
76