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