*/
static void tracked_request_end(BdrvTrackedRequest *req)
{
+ if (req->serialising) {
+ req->bs->serialising_in_flight--;
+ }
+
QLIST_REMOVE(req, list);
qemu_co_queue_restart_all(&req->wait_queue);
}
{
*req = (BdrvTrackedRequest){
.bs = bs,
- .offset = offset,
- .bytes = bytes,
- .is_write = is_write,
- .co = qemu_coroutine_self(),
+ .offset = offset,
+ .bytes = bytes,
+ .is_write = is_write,
+ .co = qemu_coroutine_self(),
+ .serialising = false,
};
qemu_co_queue_init(&req->wait_queue);
QLIST_INSERT_HEAD(&bs->tracked_requests, req, list);
}
+static void mark_request_serialising(BdrvTrackedRequest *req)
+{
+ if (!req->serialising) {
+ req->bs->serialising_in_flight++;
+ req->serialising = true;
+ }
+}
+
/**
* Round a region to cluster boundaries
*/
return true;
}
-static void coroutine_fn wait_for_overlapping_requests(BlockDriverState *bs,
- BdrvTrackedRequest *self, int64_t offset, unsigned int bytes)
+static void coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
{
+ BlockDriverState *bs = self->bs;
BdrvTrackedRequest *req;
int64_t cluster_offset;
unsigned int cluster_bytes;
bool retry;
+ if (!bs->serialising_in_flight) {
+ return;
+ }
+
/* If we touch the same cluster it counts as an overlap. This guarantees
* that allocating writes will be serialized and not race with each other
* for the same cluster. For example, in copy-on-read it ensures that the
* CoR read and write operations are atomic and guest writes cannot
* interleave between them.
*/
- round_bytes_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
+ round_bytes_to_clusters(bs, self->offset, self->bytes,
+ &cluster_offset, &cluster_bytes);
do {
retry = false;
QLIST_FOREACH(req, &bs->tracked_requests, list) {
- if (req == self) {
+ if (req == self || (!req->serialising && !self->serialising)) {
continue;
}
if (tracked_request_overlaps(req, cluster_offset, cluster_bytes)) {
/* Handle Copy on Read and associated serialisation */
if (flags & BDRV_REQ_COPY_ON_READ) {
- bs->copy_on_read_in_flight++;
+ mark_request_serialising(req);
}
- if (bs->copy_on_read_in_flight) {
- wait_for_overlapping_requests(bs, req, offset, bytes);
- }
+ wait_serialising_requests(req);
if (flags & BDRV_REQ_COPY_ON_READ) {
int pnum;
}
out:
- if (flags & BDRV_REQ_COPY_ON_READ) {
- bs->copy_on_read_in_flight--;
- }
-
return ret;
}
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
- if (bs->copy_on_read_in_flight) {
- wait_for_overlapping_requests(bs, req, offset, bytes);
- }
+ wait_serialising_requests(req);
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);