@@ -65,6 +65,7 @@ enum BdrvTrackedRequestType {
BDRV_TRACKED_WRITE,
BDRV_TRACKED_DISCARD,
BDRV_TRACKED_TRUNCATE,
+ BDRV_TRACKED_LOCK,
};
typedef struct BdrvTrackedRequest {
@@ -968,6 +969,9 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
int64_t offset, unsigned int bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
+void *coroutine_fn bdrv_co_try_lock(BlockDriverState *bs,
+ int64_t offset, unsigned int bytes);
+void coroutine_fn bdrv_co_unlock(void *opaque);
static inline int coroutine_fn bdrv_co_pread(BdrvChild *child,
int64_t offset, unsigned int bytes, void *buf, BdrvRequestFlags flags)
@@ -786,6 +786,15 @@ void bdrv_dec_in_flight(BlockDriverState *bs)
bdrv_wakeup(bs);
}
+static bool ignore_intersection(BdrvTrackedRequest *a, BdrvTrackedRequest *b)
+{
+ return a == b || (!a->serialising && !b->serialising) ||
+ (a->type == BDRV_TRACKED_LOCK && b->type == BDRV_TRACKED_READ &&
+ !b->serialising) ||
+ (b->type == BDRV_TRACKED_LOCK && a->type == BDRV_TRACKED_READ &&
+ !a->serialising);
+}
+
static bool coroutine_fn do_wait_serialising_requests(BdrvTrackedRequest *self,
bool wait)
{
@@ -802,7 +811,7 @@ static bool coroutine_fn do_wait_serialising_requests(BdrvTrackedRequest *self,
retry = false;
qemu_co_mutex_lock(&bs->reqs_lock);
QLIST_FOREACH(req, &bs->tracked_requests, list) {
- if (req == self || (!req->serialising && !self->serialising)) {
+ if (ignore_intersection(self, req)) {
continue;
}
if (tracked_request_overlaps(req, self->overlap_offset,
@@ -840,6 +849,12 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
return do_wait_serialising_requests(self, true);
}
+static bool coroutine_fn should_wait_serialising_requests(
+ BdrvTrackedRequest *self)
+{
+ return do_wait_serialising_requests(self, false);
+}
+
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
size_t size)
{
@@ -3378,3 +3393,30 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
return tco.ret;
}
+
+void *coroutine_fn bdrv_co_try_lock(BlockDriverState *bs,
+ int64_t offset, unsigned int bytes)
+{
+ BdrvTrackedRequest *req = g_new(BdrvTrackedRequest, 1);
+
+ tracked_request_begin(req, bs, offset, bytes, BDRV_TRACKED_LOCK);
+ mark_request_serialising(req, bdrv_get_cluster_size(bs));
+
+ if (should_wait_serialising_requests(req)) {
+ tracked_request_end(req);
+ g_free(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+void coroutine_fn bdrv_co_unlock(void *opaque)
+{
+ BdrvTrackedRequest *req = opaque;
+
+ assert(req->type == BDRV_TRACKED_LOCK);
+
+ tracked_request_end(req);
+ g_free(req);
+}