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