Enable building for ppc64le
Don't remove slof.bin for ppc64le usb: add config options for hub and hid devices for ppc Remove pnv_chip_find_core calls from SPRD helpers Remove pre-3.0 migration from spapr_compat_rhel7_6
This commit is contained in:
commit
d7a2470d45
@ -0,0 +1,167 @@
|
||||
From e1c2bd9c00f8fbd8da62d0cbf52f5d9c4c2a289d Mon Sep 17 00:00:00 2001
|
||||
From: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Date: Tue, 25 Nov 2025 14:31:03 +0100
|
||||
Subject: [PATCH 4/5] block/io_uring: avoid potentially getting stuck after
|
||||
resubmit at the end of ioq_submit()
|
||||
|
||||
RH-Author: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-MergeRequest: 480: linux-aio/io-uring: Resubmit tails of short requests
|
||||
RH-Jira: RHEL-154174
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [3/4] 24168b927a99fcc869aa8aec36a23d03c56ab65d (hreitz/qemu-kvm-c-9-s)
|
||||
|
||||
Note that this issue seems already fixed as a consequence of the large
|
||||
io_uring rework with 047dabef97 ("block/io_uring: use aio_add_sqe()")
|
||||
in current master, so this is purely for QEMU stable branches.
|
||||
|
||||
At the end of ioq_submit(), there is an opportunistic call to
|
||||
luring_process_completions(). This is the single caller of
|
||||
luring_process_completions() that doesn't use the
|
||||
luring_process_completions_and_submit() wrapper.
|
||||
|
||||
Other callers use the wrapper, because luring_process_completions()
|
||||
might require a subsequent call to ioq_submit() after resubmitting a
|
||||
request. As noted for luring_resubmit():
|
||||
|
||||
> Resubmit a request by appending it to submit_queue. The caller must ensure
|
||||
> that ioq_submit() is called later so that submit_queue requests are started.
|
||||
|
||||
So the caller at the end of ioq_submit() violates the contract and can
|
||||
in fact be problematic if no other requests come in later. In such a
|
||||
case, the request intended to be resubmitted will never be actually be
|
||||
submitted via io_uring_submit().
|
||||
|
||||
A reproducer exposing this issue is [0], which is based on user
|
||||
reports from [1]. Another reproducer is iotest 109 with '-i io_uring'.
|
||||
|
||||
I had the most success to trigger the issue with [0] when using a
|
||||
BTRFS RAID 1 storage. With tmpfs, it can take quite a few iterations,
|
||||
but also triggers eventually on my machine. With iotest 109 with '-i
|
||||
io_uring' the issue triggers reliably on my ext4 file system.
|
||||
|
||||
Have ioq_submit() submit any resubmitted requests after calling
|
||||
luring_process_completions(). The return value from io_uring_submit()
|
||||
is checked to be non-negative before the opportunistic processing of
|
||||
completions and going for the new resubmit logic, to ensure that a
|
||||
failure of io_uring_submit() is not missed. Also note that the return
|
||||
value already was not necessarily the total number of submissions,
|
||||
since the loop might've been iterated more than once even before the
|
||||
current change.
|
||||
|
||||
Only trigger the resubmission logic if it is actually necessary to
|
||||
avoid changing behavior more than necessary. For example iotest 109
|
||||
would produce more 'mirror ready' events if always resubmitting after
|
||||
luring_process_completions() at the end of ioq_submit().
|
||||
|
||||
Note iotest 109 still does not pass as is when run with '-i io_uring',
|
||||
because of two offset values for BLOCK_JOB_COMPLETED events being zero
|
||||
instead of non-zero as in the expected output. Note that the two
|
||||
affected test cases are expected failures and still fail, so they just
|
||||
fail "faster". The test cases are actually not triggering the resubmit
|
||||
logic, so the reason seems to be different ordering of requests and
|
||||
completions of the current aio=io_uring implementation versus
|
||||
aio=threads.
|
||||
|
||||
[0]:
|
||||
|
||||
> #!/bin/bash -e
|
||||
> #file=/mnt/btrfs/disk.raw
|
||||
> file=/tmp/disk.raw
|
||||
> filesize=256
|
||||
> readsize=512
|
||||
> rm -f $file
|
||||
> truncate -s $filesize $file
|
||||
> ./qemu-system-x86_64 --trace '*uring*' --qmp stdio \
|
||||
> --blockdev raw,node-name=node0,file.driver=file,file.cache.direct=off,file.filename=$file,file.aio=io_uring \
|
||||
> <<EOF
|
||||
> {"execute": "qmp_capabilities"}
|
||||
> {"execute": "human-monitor-command", "arguments": { "command-line": "qemu-io node0 \"read 0 $readsize \"" }}
|
||||
> {"execute": "quit"}
|
||||
> EOF
|
||||
|
||||
[1]: https://forum.proxmox.com/threads/170045/
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
|
||||
(cherry picked from commit 2bb0153cd806b8f6b4f82b353bd0113cd1c488a5)
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
---
|
||||
block/io_uring.c | 16 +++++++++++++---
|
||||
1 file changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/io_uring.c b/block/io_uring.c
|
||||
index dd4f304910..5dbafc8f7b 100644
|
||||
--- a/block/io_uring.c
|
||||
+++ b/block/io_uring.c
|
||||
@@ -120,11 +120,14 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb,
|
||||
* event loop. When there are no events left to complete the BH is being
|
||||
* canceled.
|
||||
*
|
||||
+ * Returns whether ioq_submit() must be called again afterwards since requests
|
||||
+ * were resubmitted via luring_resubmit().
|
||||
*/
|
||||
-static void luring_process_completions(LuringState *s)
|
||||
+static bool luring_process_completions(LuringState *s)
|
||||
{
|
||||
struct io_uring_cqe *cqes;
|
||||
int total_bytes;
|
||||
+ bool resubmit = false;
|
||||
|
||||
defer_call_begin();
|
||||
|
||||
@@ -182,6 +185,7 @@ static void luring_process_completions(LuringState *s)
|
||||
*/
|
||||
if (ret == -EINTR || ret == -EAGAIN) {
|
||||
luring_resubmit(s, luringcb);
|
||||
+ resubmit = true;
|
||||
continue;
|
||||
}
|
||||
} else if (!luringcb->qiov) {
|
||||
@@ -194,6 +198,7 @@ static void luring_process_completions(LuringState *s)
|
||||
if (luringcb->is_read) {
|
||||
if (ret > 0) {
|
||||
luring_resubmit_short_read(s, luringcb, ret);
|
||||
+ resubmit = true;
|
||||
continue;
|
||||
} else {
|
||||
/* Pad with zeroes */
|
||||
@@ -224,6 +229,8 @@ end:
|
||||
qemu_bh_cancel(s->completion_bh);
|
||||
|
||||
defer_call_end();
|
||||
+
|
||||
+ return resubmit;
|
||||
}
|
||||
|
||||
static int ioq_submit(LuringState *s)
|
||||
@@ -231,6 +238,7 @@ static int ioq_submit(LuringState *s)
|
||||
int ret = 0;
|
||||
LuringAIOCB *luringcb, *luringcb_next;
|
||||
|
||||
+resubmit:
|
||||
while (s->io_q.in_queue > 0) {
|
||||
/*
|
||||
* Try to fetch sqes from the ring for requests waiting in
|
||||
@@ -260,12 +268,14 @@ static int ioq_submit(LuringState *s)
|
||||
}
|
||||
s->io_q.blocked = (s->io_q.in_queue > 0);
|
||||
|
||||
- if (s->io_q.in_flight) {
|
||||
+ if (ret >= 0 && s->io_q.in_flight) {
|
||||
/*
|
||||
* We can try to complete something just right away if there are
|
||||
* still requests in-flight.
|
||||
*/
|
||||
- luring_process_completions(s);
|
||||
+ if (luring_process_completions(s)) {
|
||||
+ goto resubmit;
|
||||
+ }
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
280
SOURCES/kvm-io-uring-Resubmit-tails-of-short-writes.patch
Normal file
280
SOURCES/kvm-io-uring-Resubmit-tails-of-short-writes.patch
Normal file
@ -0,0 +1,280 @@
|
||||
From 5c03f1f319e1a945d3a651677178f5af872971d9 Mon Sep 17 00:00:00 2001
|
||||
From: Hanna Czenczek <hreitz@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 09:43:36 +0100
|
||||
Subject: [PATCH 5/5] io-uring: Resubmit tails of short writes
|
||||
|
||||
RH-Author: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-MergeRequest: 480: linux-aio/io-uring: Resubmit tails of short requests
|
||||
RH-Jira: RHEL-154174
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [4/4] e9d78176f1b737ddc1ea74ca412a892634902409 (hreitz/qemu-kvm-c-9-s)
|
||||
|
||||
Short writes can happen, too, not just short reads. The difference to
|
||||
aio=native is that the kernel will actually retry the tail of short
|
||||
requests internally already -- so it is harder to reproduce. But if the
|
||||
tail of a short request returns an error to the kernel, we will see it
|
||||
in userspace still. To reproduce this, apply the following patch on top
|
||||
of the one shown in HEAD^ (again %s/escaped // to apply):
|
||||
|
||||
escaped diff --git a/block/export/fuse.c b/block/export/fuse.c
|
||||
escaped index 67dc50a412..2b98489a32 100644
|
||||
escaped --- a/block/export/fuse.c
|
||||
escaped +++ b/block/export/fuse.c
|
||||
@@ -1059,8 +1059,15 @@ fuse_co_read(FuseExport *exp, void **bufptr, uint64_t offset, uint32_t size)
|
||||
int64_t blk_len;
|
||||
void *buf;
|
||||
int ret;
|
||||
+ static uint32_t error_size;
|
||||
|
||||
- size = MIN(size, 4096);
|
||||
+ if (error_size == size) {
|
||||
+ error_size = 0;
|
||||
+ return -EIO;
|
||||
+ } else if (size > 4096) {
|
||||
+ error_size = size - 4096;
|
||||
+ size = 4096;
|
||||
+ }
|
||||
|
||||
/* Limited by max_read, should not happen */
|
||||
if (size > FUSE_MAX_READ_BYTES) {
|
||||
@@ -1111,8 +1118,15 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out,
|
||||
{
|
||||
int64_t blk_len;
|
||||
int ret;
|
||||
+ static uint32_t error_size;
|
||||
|
||||
- size = MIN(size, 4096);
|
||||
+ if (error_size == size) {
|
||||
+ error_size = 0;
|
||||
+ return -EIO;
|
||||
+ } else if (size > 4096) {
|
||||
+ error_size = size - 4096;
|
||||
+ size = 4096;
|
||||
+ }
|
||||
|
||||
QEMU_BUILD_BUG_ON(FUSE_MAX_WRITE_BYTES > BDRV_REQUEST_MAX_BYTES);
|
||||
/* Limited by max_write, should not happen */
|
||||
|
||||
I know this is a bit artificial because to produce this, there must be
|
||||
an I/O error somewhere anyway, but if it does happen, qemu will
|
||||
understand it to mean ENOSPC for short writes, which is incorrect. So I
|
||||
believe we need to resubmit the tail to maybe have it succeed now, or at
|
||||
least get the correct error code.
|
||||
|
||||
Reproducer as before:
|
||||
$ ./qemu-img create -f raw test.raw 8k
|
||||
Formatting 'test.raw', fmt=raw size=8192
|
||||
$ ./qemu-io -f raw -c 'write -P 42 0 8k' test.raw
|
||||
wrote 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (64.804 MiB/sec and 8294.9003 ops/sec)
|
||||
$ hexdump -C test.raw
|
||||
00000000 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
|
||||
*
|
||||
00002000
|
||||
$ storage-daemon/qemu-storage-daemon \
|
||||
--blockdev file,node-name=test,filename=test.raw \
|
||||
--export fuse,id=exp,node-name=test,mountpoint=test.raw,writable=true
|
||||
|
||||
$ ./qemu-io --image-opts -c 'read -P 23 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=io_uring
|
||||
read 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (58.481 MiB/sec and 7485.5342 ops/sec)
|
||||
$ ./qemu-io --image-opts -c 'write -P 23 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=io_uring
|
||||
write failed: No space left on device
|
||||
$ hexdump -C test.raw
|
||||
00000000 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 |................|
|
||||
*
|
||||
00001000 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
|
||||
*
|
||||
00002000
|
||||
|
||||
So short reads already work (because there is code for that), but short
|
||||
writes incorrectly produce ENOSPC. This patch fixes that by
|
||||
resubmitting not only the tail of short reads but short writes also.
|
||||
|
||||
(And this patch uses the opportunity to make it so qemu_iovec_destroy()
|
||||
is called only if req->resubmit_qiov.iov is non-NULL. Functionally a
|
||||
non-op, but this is how the code generally checks whether the
|
||||
resubmit_qiov has been set up or not.)
|
||||
|
||||
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Message-ID: <20260324084338.37453-4-hreitz@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit cf9cdaea6e24d13dfdf8402f6829d2ca4dca864b)
|
||||
|
||||
Conflicts:
|
||||
- block/io_uring.c, block/trace-events
|
||||
Missing 047dabef97bd0c4af3c3dc453b19e20345de3602 ("block/io_uring: use
|
||||
aio_add_sqe()") downstream, which changed quite a few things about the
|
||||
io-uring code. Backporting it seems excessive, though, especially
|
||||
given that it would pull in even more dependencies (general aio and
|
||||
aio-posix changes that come right before 047dabef).
|
||||
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
(cherry picked from commit cf9cdaea6e24d13dfdf8402f6829d2ca4dca864b)
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
---
|
||||
block/io_uring.c | 77 +++++++++++++++++++++++++---------------------
|
||||
block/trace-events | 2 +-
|
||||
2 files changed, 43 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/block/io_uring.c b/block/io_uring.c
|
||||
index 5dbafc8f7b..582550f8e9 100644
|
||||
--- a/block/io_uring.c
|
||||
+++ b/block/io_uring.c
|
||||
@@ -31,14 +31,14 @@ typedef struct LuringAIOCB {
|
||||
struct io_uring_sqe sqeq;
|
||||
ssize_t ret;
|
||||
QEMUIOVector *qiov;
|
||||
- bool is_read;
|
||||
+ int type;
|
||||
QSIMPLEQ_ENTRY(LuringAIOCB) next;
|
||||
|
||||
/*
|
||||
- * Buffered reads may require resubmission, see
|
||||
- * luring_resubmit_short_read().
|
||||
+ * Short reads/writes require resubmission, see
|
||||
+ * luring_resubmit_short_io().
|
||||
*/
|
||||
- int total_read;
|
||||
+ int total_done;
|
||||
QEMUIOVector resubmit_qiov;
|
||||
} LuringAIOCB;
|
||||
|
||||
@@ -73,22 +73,27 @@ static void luring_resubmit(LuringState *s, LuringAIOCB *luringcb)
|
||||
}
|
||||
|
||||
/**
|
||||
- * luring_resubmit_short_read:
|
||||
+ * luring_resubmit_short_io:
|
||||
*
|
||||
- * Short reads are rare but may occur. The remaining read request needs to be
|
||||
- * resubmitted.
|
||||
+ * Short reads and writes are rare but may occur. The remaining request needs
|
||||
+ * to be resubmitted.
|
||||
+ *
|
||||
+ * For example, short reads can be reproduced by a FUSE export deliberately
|
||||
+ * executing short reads. The tail of short writes is generally resubmitted by
|
||||
+ * io-uring in the kernel, but if that resubmission encounters an I/O error, the
|
||||
+ * already submitted portion will be returned as a short write.
|
||||
*/
|
||||
-static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb,
|
||||
- int nread)
|
||||
+static void luring_resubmit_short_io(LuringState *s, LuringAIOCB *luringcb,
|
||||
+ int ndone)
|
||||
{
|
||||
QEMUIOVector *resubmit_qiov;
|
||||
size_t remaining;
|
||||
|
||||
- trace_luring_resubmit_short_read(s, luringcb, nread);
|
||||
+ trace_luring_resubmit_short_io(s, luringcb, ndone);
|
||||
|
||||
- /* Update read position */
|
||||
- luringcb->total_read += nread;
|
||||
- remaining = luringcb->qiov->size - luringcb->total_read;
|
||||
+ /* Update I/O position */
|
||||
+ luringcb->total_done += ndone;
|
||||
+ remaining = luringcb->qiov->size - luringcb->total_done;
|
||||
|
||||
/* Shorten qiov */
|
||||
resubmit_qiov = &luringcb->resubmit_qiov;
|
||||
@@ -97,11 +102,11 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb,
|
||||
} else {
|
||||
qemu_iovec_reset(resubmit_qiov);
|
||||
}
|
||||
- qemu_iovec_concat(resubmit_qiov, luringcb->qiov, luringcb->total_read,
|
||||
+ qemu_iovec_concat(resubmit_qiov, luringcb->qiov, luringcb->total_done,
|
||||
remaining);
|
||||
|
||||
/* Update sqe */
|
||||
- luringcb->sqeq.off += nread;
|
||||
+ luringcb->sqeq.off += ndone;
|
||||
luringcb->sqeq.addr = (uintptr_t)luringcb->resubmit_qiov.iov;
|
||||
luringcb->sqeq.len = luringcb->resubmit_qiov.niov;
|
||||
|
||||
@@ -165,8 +170,8 @@ static bool luring_process_completions(LuringState *s)
|
||||
s->io_q.in_flight--;
|
||||
trace_luring_process_completion(s, luringcb, ret);
|
||||
|
||||
- /* total_read is non-zero only for resubmitted read requests */
|
||||
- total_bytes = ret + luringcb->total_read;
|
||||
+ /* total_done is non-zero only for resubmitted requests */
|
||||
+ total_bytes = ret + luringcb->total_done;
|
||||
|
||||
if (ret < 0) {
|
||||
/*
|
||||
@@ -192,27 +197,29 @@ static bool luring_process_completions(LuringState *s)
|
||||
goto end;
|
||||
} else if (total_bytes == luringcb->qiov->size) {
|
||||
ret = 0;
|
||||
- /* Only read/write */
|
||||
+ } else if (ret > 0 && (luringcb->type == QEMU_AIO_READ ||
|
||||
+ luringcb->type == QEMU_AIO_WRITE)) {
|
||||
+ luring_resubmit_short_io(s, luringcb, ret);
|
||||
+ resubmit = true;
|
||||
+ continue;
|
||||
+ } else if (luringcb->type == QEMU_AIO_READ) {
|
||||
+ /* Read ret == 0: EOF, pad with zeroes */
|
||||
+ qemu_iovec_memset(luringcb->qiov, total_bytes, 0,
|
||||
+ luringcb->qiov->size - total_bytes);
|
||||
+ ret = 0;
|
||||
} else {
|
||||
- /* Short Read/Write */
|
||||
- if (luringcb->is_read) {
|
||||
- if (ret > 0) {
|
||||
- luring_resubmit_short_read(s, luringcb, ret);
|
||||
- resubmit = true;
|
||||
- continue;
|
||||
- } else {
|
||||
- /* Pad with zeroes */
|
||||
- qemu_iovec_memset(luringcb->qiov, total_bytes, 0,
|
||||
- luringcb->qiov->size - total_bytes);
|
||||
- ret = 0;
|
||||
- }
|
||||
- } else {
|
||||
- ret = -ENOSPC;
|
||||
- }
|
||||
+ /*
|
||||
+ * Normal write ret == 0 means ENOSPC.
|
||||
+ * For zone-append, we treat any 0 <= ret < qiov->size as ENOSPC,
|
||||
+ * too, because resubmitting the tail seems a little unsafe.
|
||||
+ */
|
||||
+ ret = -ENOSPC;
|
||||
}
|
||||
end:
|
||||
luringcb->ret = ret;
|
||||
- qemu_iovec_destroy(&luringcb->resubmit_qiov);
|
||||
+ if (luringcb->resubmit_qiov.iov) {
|
||||
+ qemu_iovec_destroy(&luringcb->resubmit_qiov);
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If the coroutine is already entered it must be in ioq_submit()
|
||||
@@ -409,7 +416,7 @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
|
||||
.co = qemu_coroutine_self(),
|
||||
.ret = -EINPROGRESS,
|
||||
.qiov = qiov,
|
||||
- .is_read = (type == QEMU_AIO_READ),
|
||||
+ .type = type,
|
||||
};
|
||||
trace_luring_co_submit(bs, s, &luringcb, fd, offset, qiov ? qiov->size : 0,
|
||||
type);
|
||||
diff --git a/block/trace-events b/block/trace-events
|
||||
index 8e789e1f12..99b8c12bc8 100644
|
||||
--- a/block/trace-events
|
||||
+++ b/block/trace-events
|
||||
@@ -70,7 +70,7 @@ luring_do_submit_done(void *s, int ret) "LuringState %p submitted to kernel %d"
|
||||
luring_co_submit(void *bs, void *s, void *luringcb, int fd, uint64_t offset, size_t nbytes, int type) "bs %p s %p luringcb %p fd %d offset %" PRId64 " nbytes %zd type %d"
|
||||
luring_process_completion(void *s, void *aiocb, int ret) "LuringState %p luringcb %p ret %d"
|
||||
luring_io_uring_submit(void *s, int ret) "LuringState %p ret %d"
|
||||
-luring_resubmit_short_read(void *s, void *luringcb, int nread) "LuringState %p luringcb %p nread %d"
|
||||
+luring_resubmit_short_io(void *s, void *luringcb, int ndone) "LuringState %p luringcb %p ndone %d"
|
||||
|
||||
# qcow2.c
|
||||
qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t host_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu"
|
||||
--
|
||||
2.52.0
|
||||
|
||||
127
SOURCES/kvm-linux-aio-Put-all-parameters-into-qemu_laiocb.patch
Normal file
127
SOURCES/kvm-linux-aio-Put-all-parameters-into-qemu_laiocb.patch
Normal file
@ -0,0 +1,127 @@
|
||||
From 87c97b1307f7c16dcd72fd21fe8eb8058a92d1fe Mon Sep 17 00:00:00 2001
|
||||
From: Hanna Czenczek <hreitz@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 09:43:34 +0100
|
||||
Subject: [PATCH 2/5] linux-aio: Put all parameters into qemu_laiocb
|
||||
|
||||
RH-Author: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-MergeRequest: 480: linux-aio/io-uring: Resubmit tails of short requests
|
||||
RH-Jira: RHEL-154174
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [1/4] b348913628115e27ff141bf4ee4c82405ca99362 (hreitz/qemu-kvm-c-9-s)
|
||||
|
||||
Put all request parameters into the qemu_laiocb struct, which will allow
|
||||
re-submitting the tail of short reads/writes.
|
||||
|
||||
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Message-ID: <20260324084338.37453-2-hreitz@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit cc03b62df47a09c507e199cc043f57bdc941cc67)
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
---
|
||||
block/linux-aio.c | 34 ++++++++++++++++++++++------------
|
||||
1 file changed, 22 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/block/linux-aio.c b/block/linux-aio.c
|
||||
index c200e7ad20..c2c5e11946 100644
|
||||
--- a/block/linux-aio.c
|
||||
+++ b/block/linux-aio.c
|
||||
@@ -41,9 +41,15 @@ struct qemu_laiocb {
|
||||
LinuxAioState *ctx;
|
||||
struct iocb iocb;
|
||||
ssize_t ret;
|
||||
+ off_t offset;
|
||||
size_t nbytes;
|
||||
QEMUIOVector *qiov;
|
||||
- bool is_read;
|
||||
+
|
||||
+ int fd;
|
||||
+ int type;
|
||||
+ BdrvRequestFlags flags;
|
||||
+
|
||||
+ uint64_t dev_max_batch;
|
||||
QSIMPLEQ_ENTRY(qemu_laiocb) next;
|
||||
};
|
||||
|
||||
@@ -87,7 +93,7 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
||||
ret = 0;
|
||||
} else if (ret >= 0) {
|
||||
/* Short reads mean EOF, pad with zeros. */
|
||||
- if (laiocb->is_read) {
|
||||
+ if (laiocb->type == QEMU_AIO_READ) {
|
||||
qemu_iovec_memset(laiocb->qiov, ret, 0,
|
||||
laiocb->qiov->size - ret);
|
||||
} else {
|
||||
@@ -367,23 +373,23 @@ static void laio_deferred_fn(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
-static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
- int type, BdrvRequestFlags flags,
|
||||
- uint64_t dev_max_batch)
|
||||
+static int laio_do_submit(struct qemu_laiocb *laiocb)
|
||||
{
|
||||
LinuxAioState *s = laiocb->ctx;
|
||||
struct iocb *iocbs = &laiocb->iocb;
|
||||
QEMUIOVector *qiov = laiocb->qiov;
|
||||
+ int fd = laiocb->fd;
|
||||
+ off_t offset = laiocb->offset;
|
||||
|
||||
- switch (type) {
|
||||
+ switch (laiocb->type) {
|
||||
case QEMU_AIO_WRITE:
|
||||
#ifdef HAVE_IO_PREP_PWRITEV2
|
||||
{
|
||||
- int laio_flags = (flags & BDRV_REQ_FUA) ? RWF_DSYNC : 0;
|
||||
+ int laio_flags = (laiocb->flags & BDRV_REQ_FUA) ? RWF_DSYNC : 0;
|
||||
io_prep_pwritev2(iocbs, fd, qiov->iov, qiov->niov, offset, laio_flags);
|
||||
}
|
||||
#else
|
||||
- assert(flags == 0);
|
||||
+ assert(laiocb->flags == 0);
|
||||
io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset);
|
||||
#endif
|
||||
break;
|
||||
@@ -399,7 +405,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
/* Currently Linux kernel does not support other operations */
|
||||
default:
|
||||
fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
|
||||
- __func__, type);
|
||||
+ __func__, laiocb->type);
|
||||
return -EIO;
|
||||
}
|
||||
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
||||
@@ -407,7 +413,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
|
||||
QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next);
|
||||
s->io_q.in_queue++;
|
||||
if (!s->io_q.blocked) {
|
||||
- if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch)) {
|
||||
+ if (s->io_q.in_queue >= laio_max_batch(s, laiocb->dev_max_batch)) {
|
||||
ioq_submit(s);
|
||||
} else {
|
||||
defer_call(laio_deferred_fn, s);
|
||||
@@ -425,14 +431,18 @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
|
||||
AioContext *ctx = qemu_get_current_aio_context();
|
||||
struct qemu_laiocb laiocb = {
|
||||
.co = qemu_coroutine_self(),
|
||||
+ .offset = offset,
|
||||
.nbytes = qiov ? qiov->size : 0,
|
||||
.ctx = aio_get_linux_aio(ctx),
|
||||
.ret = -EINPROGRESS,
|
||||
- .is_read = (type == QEMU_AIO_READ),
|
||||
.qiov = qiov,
|
||||
+ .fd = fd,
|
||||
+ .type = type,
|
||||
+ .flags = flags,
|
||||
+ .dev_max_batch = dev_max_batch,
|
||||
};
|
||||
|
||||
- ret = laio_do_submit(fd, &laiocb, offset, type, flags, dev_max_batch);
|
||||
+ ret = laio_do_submit(&laiocb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
215
SOURCES/kvm-linux-aio-Resubmit-tails-of-short-reads-writes.patch
Normal file
215
SOURCES/kvm-linux-aio-Resubmit-tails-of-short-reads-writes.patch
Normal file
@ -0,0 +1,215 @@
|
||||
From 0bc45f360a4832545e561db895e8eeec7c6ddd26 Mon Sep 17 00:00:00 2001
|
||||
From: Hanna Czenczek <hreitz@redhat.com>
|
||||
Date: Tue, 24 Mar 2026 09:43:35 +0100
|
||||
Subject: [PATCH 3/5] linux-aio: Resubmit tails of short reads/writes
|
||||
|
||||
RH-Author: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-MergeRequest: 480: linux-aio/io-uring: Resubmit tails of short requests
|
||||
RH-Jira: RHEL-154174
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [2/4] 70a8bb9e2bf13aa005faca3ae67bb71d9f124005 (hreitz/qemu-kvm-c-9-s)
|
||||
|
||||
Short reads/writes can happen. One way to reproduce them is via our
|
||||
FUSE export, with the following diff applied (%s/escaped // to apply --
|
||||
if you put plain diffs in commit messages, git-am will apply them, and I
|
||||
would rather avoid breaking FUSE accidentally via this patch):
|
||||
|
||||
escaped diff --git a/block/export/fuse.c b/block/export/fuse.c
|
||||
escaped index a2a478d293..67dc50a412 100644
|
||||
escaped --- a/block/export/fuse.c
|
||||
escaped +++ b/block/export/fuse.c
|
||||
@@ -828,7 +828,7 @@ static ssize_t coroutine_fn GRAPH_RDLOCK
|
||||
fuse_co_init(FuseExport *exp, struct fuse_init_out *out,
|
||||
const struct fuse_init_in_compat *in)
|
||||
{
|
||||
- const uint32_t supported_flags = FUSE_ASYNC_READ | FUSE_ASYNC_DIO;
|
||||
+ const uint32_t supported_flags = FUSE_ASYNC_READ;
|
||||
|
||||
if (in->major != 7) {
|
||||
error_report("FUSE major version mismatch: We have 7, but kernel has %"
|
||||
@@ -1060,6 +1060,8 @@ fuse_co_read(FuseExport *exp, void **bufptr, uint64_t offset, uint32_t size)
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
+ size = MIN(size, 4096);
|
||||
+
|
||||
/* Limited by max_read, should not happen */
|
||||
if (size > FUSE_MAX_READ_BYTES) {
|
||||
return -EINVAL;
|
||||
@@ -1110,6 +1112,8 @@ fuse_co_write(FuseExport *exp, struct fuse_write_out *out,
|
||||
int64_t blk_len;
|
||||
int ret;
|
||||
|
||||
+ size = MIN(size, 4096);
|
||||
+
|
||||
QEMU_BUILD_BUG_ON(FUSE_MAX_WRITE_BYTES > BDRV_REQUEST_MAX_BYTES);
|
||||
/* Limited by max_write, should not happen */
|
||||
if (size > FUSE_MAX_WRITE_BYTES) {
|
||||
|
||||
Then:
|
||||
$ ./qemu-img create -f raw test.raw 8k
|
||||
Formatting 'test.raw', fmt=raw size=8192
|
||||
$ ./qemu-io -f raw -c 'write -P 42 0 8k' test.raw
|
||||
wrote 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (64.804 MiB/sec and 8294.9003 ops/sec)
|
||||
$ hexdump -C test.raw
|
||||
00000000 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
|
||||
*
|
||||
00002000
|
||||
|
||||
With aio=threads, short I/O works:
|
||||
$ storage-daemon/qemu-storage-daemon \
|
||||
--blockdev file,node-name=test,filename=test.raw \
|
||||
--export fuse,id=exp,node-name=test,mountpoint=test.raw,writable=true
|
||||
|
||||
Other shell:
|
||||
$ ./qemu-io --image-opts -c 'read -P 42 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=threads
|
||||
read 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (36.563 MiB/sec and 4680.0923 ops/sec)
|
||||
$ ./qemu-io --image-opts -c 'write -P 23 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=threads
|
||||
wrote 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (35.995 MiB/sec and 4607.2970 ops/sec)
|
||||
$ hexdump -C test.raw
|
||||
00000000 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 |................|
|
||||
*
|
||||
00002000
|
||||
|
||||
But with aio=native, it does not:
|
||||
$ ./qemu-io --image-opts -c 'read -P 23 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=native
|
||||
Pattern verification failed at offset 0, 8192 bytes
|
||||
read 8192/8192 bytes at offset 0
|
||||
8 KiB, 1 ops; 00.00 sec (86.155 MiB/sec and 11027.7900 ops/sec)
|
||||
$ ./qemu-io --image-opts -c 'write -P 42 0 8k' \
|
||||
driver=file,filename=test.raw,cache.direct=on,aio=native
|
||||
write failed: No space left on device
|
||||
$ hexdump -C test.raw
|
||||
00000000 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
|
||||
*
|
||||
00001000 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 |................|
|
||||
*
|
||||
00002000
|
||||
|
||||
This patch fixes that.
|
||||
|
||||
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
Message-ID: <20260324084338.37453-3-hreitz@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit 7eca3d4883be8d328377001a9ea7ae9882b00f3c)
|
||||
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
---
|
||||
block/linux-aio.c | 56 ++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 50 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/block/linux-aio.c b/block/linux-aio.c
|
||||
index c2c5e11946..84397de54c 100644
|
||||
--- a/block/linux-aio.c
|
||||
+++ b/block/linux-aio.c
|
||||
@@ -45,6 +45,10 @@ struct qemu_laiocb {
|
||||
size_t nbytes;
|
||||
QEMUIOVector *qiov;
|
||||
|
||||
+ /* For handling short reads/writes */
|
||||
+ size_t total_done;
|
||||
+ QEMUIOVector resubmit_qiov;
|
||||
+
|
||||
int fd;
|
||||
int type;
|
||||
BdrvRequestFlags flags;
|
||||
@@ -74,28 +78,61 @@ struct LinuxAioState {
|
||||
};
|
||||
|
||||
static void ioq_submit(LinuxAioState *s);
|
||||
+static int laio_do_submit(struct qemu_laiocb *laiocb);
|
||||
|
||||
static inline ssize_t io_event_ret(struct io_event *ev)
|
||||
{
|
||||
return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Retry tail of short requests.
|
||||
+ */
|
||||
+static int laio_resubmit_short_io(struct qemu_laiocb *laiocb, size_t done)
|
||||
+{
|
||||
+ QEMUIOVector *resubmit_qiov = &laiocb->resubmit_qiov;
|
||||
+
|
||||
+ laiocb->total_done += done;
|
||||
+
|
||||
+ if (!resubmit_qiov->iov) {
|
||||
+ qemu_iovec_init(resubmit_qiov, laiocb->qiov->niov);
|
||||
+ } else {
|
||||
+ qemu_iovec_reset(resubmit_qiov);
|
||||
+ }
|
||||
+ qemu_iovec_concat(resubmit_qiov, laiocb->qiov,
|
||||
+ laiocb->total_done, laiocb->nbytes - laiocb->total_done);
|
||||
+
|
||||
+ return laio_do_submit(laiocb);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Completes an AIO request.
|
||||
*/
|
||||
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
||||
{
|
||||
- int ret;
|
||||
+ ssize_t ret;
|
||||
|
||||
ret = laiocb->ret;
|
||||
if (ret != -ECANCELED) {
|
||||
- if (ret == laiocb->nbytes) {
|
||||
+ if (ret == laiocb->nbytes - laiocb->total_done) {
|
||||
ret = 0;
|
||||
+ } else if (ret > 0 && (laiocb->type == QEMU_AIO_READ ||
|
||||
+ laiocb->type == QEMU_AIO_WRITE)) {
|
||||
+ ret = laio_resubmit_short_io(laiocb, ret);
|
||||
+ if (!ret) {
|
||||
+ return;
|
||||
+ }
|
||||
} else if (ret >= 0) {
|
||||
- /* Short reads mean EOF, pad with zeros. */
|
||||
+ /*
|
||||
+ * For normal reads and writes, we only get here if ret == 0, which
|
||||
+ * means EOF for reads and ENOSPC for writes.
|
||||
+ * For zone-append, we get here with any ret >= 0, which we just
|
||||
+ * treat as ENOSPC, too (safer than resubmitting, probably, but not
|
||||
+ * 100 % clear).
|
||||
+ */
|
||||
if (laiocb->type == QEMU_AIO_READ) {
|
||||
- qemu_iovec_memset(laiocb->qiov, ret, 0,
|
||||
- laiocb->qiov->size - ret);
|
||||
+ qemu_iovec_memset(laiocb->qiov, laiocb->total_done, 0,
|
||||
+ laiocb->qiov->size - laiocb->total_done);
|
||||
} else {
|
||||
ret = -ENOSPC;
|
||||
}
|
||||
@@ -103,6 +140,9 @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
|
||||
}
|
||||
|
||||
laiocb->ret = ret;
|
||||
+ if (laiocb->resubmit_qiov.iov) {
|
||||
+ qemu_iovec_destroy(&laiocb->resubmit_qiov);
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If the coroutine is already entered it must be in ioq_submit() and
|
||||
@@ -379,7 +419,11 @@ static int laio_do_submit(struct qemu_laiocb *laiocb)
|
||||
struct iocb *iocbs = &laiocb->iocb;
|
||||
QEMUIOVector *qiov = laiocb->qiov;
|
||||
int fd = laiocb->fd;
|
||||
- off_t offset = laiocb->offset;
|
||||
+ off_t offset = laiocb->offset + laiocb->total_done;
|
||||
+
|
||||
+ if (laiocb->resubmit_qiov.iov) {
|
||||
+ qiov = &laiocb->resubmit_qiov;
|
||||
+ }
|
||||
|
||||
switch (laiocb->type) {
|
||||
case QEMU_AIO_WRITE:
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,162 @@
|
||||
From 85b1dd9e420291d4b56fca1af2c34ffe93cdc9eb Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Thu, 19 Feb 2026 21:24:46 +0100
|
||||
Subject: [PATCH 1/5] mirror: Fix missed dirty bitmap writes during startup
|
||||
|
||||
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-MergeRequest: 475: mirror: Fix missed dirty bitmap writes during startup
|
||||
RH-Jira: RHEL-155947 RHEL-155948
|
||||
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
|
||||
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-Commit: [1/1] c5ac799003a2763c5eadb0adf0932e951b16e66b (kmwolf/centos-qemu-kvm)
|
||||
|
||||
Currently, mirror disables the block layer's dirty bitmap before its own
|
||||
replacement is working. This means that during startup, there is a
|
||||
window in which the allocation status of blocks in the source has
|
||||
already been checked, but new writes coming in aren't tracked yet,
|
||||
resulting in a corrupted copy:
|
||||
|
||||
1. Dirty bitmap is disabled in mirror_start_job()
|
||||
2. Some request are started in mirror_top_bs while s->job == NULL
|
||||
3. mirror_dirty_init() -> bdrv_co_is_allocated_above() runs and because
|
||||
the request hasn't completed yet, the block isn't allocated
|
||||
4. The request completes, still sees s->job == NULL and skips the
|
||||
bitmap, and nothing else will mark it dirty either
|
||||
|
||||
One ingredient is that mirror_top_opaque->job is only set after the
|
||||
job is fully initialized. For the rationale, see commit 32125b1460
|
||||
("mirror: Fix access of uninitialised fields during start").
|
||||
|
||||
Fix this by giving mirror_top_bs access to dirty_bitmap and enabling it
|
||||
to track writes from the beginning. Disabling the block layer's tracking
|
||||
and enabling the mirror_top_bs one happens in a drained section, so
|
||||
there is no danger of races with in-flight requests any more. All of
|
||||
this happens well before the block allocation status is checked, so we
|
||||
can be sure that no writes will be missed.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Closes: https://gitlab.com/qemu-project/qemu/-/issues/3273
|
||||
Fixes: 32125b14606a ('mirror: Fix access of uninitialised fields during start')
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Message-ID: <20260219202446.312493-1-kwolf@redhat.com>
|
||||
Reviewed-by: Fiona Ebner <f.ebner@proxmox.com>
|
||||
Tested-by: Jean-Louis Dupond <jean-louis@dupond.be>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit 0f51f9c3420b31bb383e456dd7bf24d3056eeb73)
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
---
|
||||
block/mirror.c | 52 +++++++++++++++++++++++++++++++-------------------
|
||||
1 file changed, 32 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/block/mirror.c b/block/mirror.c
|
||||
index b344182c74..f01be99b55 100644
|
||||
--- a/block/mirror.c
|
||||
+++ b/block/mirror.c
|
||||
@@ -99,6 +99,7 @@ typedef struct MirrorBlockJob {
|
||||
|
||||
typedef struct MirrorBDSOpaque {
|
||||
MirrorBlockJob *job;
|
||||
+ BdrvDirtyBitmap *dirty_bitmap;
|
||||
bool stop;
|
||||
bool is_commit;
|
||||
} MirrorBDSOpaque;
|
||||
@@ -1672,9 +1673,11 @@ bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
|
||||
abort();
|
||||
}
|
||||
|
||||
- if (!copy_to_target && s->job && s->job->dirty_bitmap) {
|
||||
- qatomic_set(&s->job->actively_synced, false);
|
||||
- bdrv_set_dirty_bitmap(s->job->dirty_bitmap, offset, bytes);
|
||||
+ if (!copy_to_target) {
|
||||
+ if (s->job) {
|
||||
+ qatomic_set(&s->job->actively_synced, false);
|
||||
+ }
|
||||
+ bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1901,13 +1904,35 @@ static BlockJob *mirror_start_job(
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
ret = bdrv_append(mirror_top_bs, bs, errp);
|
||||
- bdrv_drained_end(bs);
|
||||
-
|
||||
if (ret < 0) {
|
||||
+ bdrv_drained_end(bs);
|
||||
+ bdrv_unref(mirror_top_bs);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ bs_opaque->dirty_bitmap = bdrv_create_dirty_bitmap(mirror_top_bs,
|
||||
+ granularity,
|
||||
+ NULL, errp);
|
||||
+ if (!bs_opaque->dirty_bitmap) {
|
||||
+ bdrv_drained_end(bs);
|
||||
bdrv_unref(mirror_top_bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * The mirror job doesn't use the block layer's dirty tracking because it
|
||||
+ * needs to be able to switch seemlessly between background copy mode (which
|
||||
+ * does need dirty tracking) and write blocking mode (which doesn't) and
|
||||
+ * doing that would require draining the node. Instead, mirror_top_bs takes
|
||||
+ * care of updating the dirty bitmap as appropriate.
|
||||
+ *
|
||||
+ * Note that write blocking mode only becomes effective after mirror_run()
|
||||
+ * sets mirror_top_opaque->job (see should_copy_to_target()). Until then,
|
||||
+ * we're still in background copy mode irrespective of @copy_mode.
|
||||
+ */
|
||||
+ bdrv_disable_dirty_bitmap(bs_opaque->dirty_bitmap);
|
||||
+ bdrv_drained_end(bs);
|
||||
+
|
||||
/* Make sure that the source is not resized while the job is running */
|
||||
s = block_job_create(job_id, driver, NULL, mirror_top_bs,
|
||||
BLK_PERM_CONSISTENT_READ,
|
||||
@@ -2002,24 +2027,13 @@ static BlockJob *mirror_start_job(
|
||||
s->base_overlay = bdrv_find_overlay(bs, base);
|
||||
s->granularity = granularity;
|
||||
s->buf_size = ROUND_UP(buf_size, granularity);
|
||||
+ s->dirty_bitmap = bs_opaque->dirty_bitmap;
|
||||
s->unmap = unmap;
|
||||
if (auto_complete) {
|
||||
s->should_complete = true;
|
||||
}
|
||||
bdrv_graph_rdunlock_main_loop();
|
||||
|
||||
- s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity,
|
||||
- NULL, errp);
|
||||
- if (!s->dirty_bitmap) {
|
||||
- goto fail;
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * The dirty bitmap is set by bdrv_mirror_top_do_write() when not in active
|
||||
- * mode.
|
||||
- */
|
||||
- bdrv_disable_dirty_bitmap(s->dirty_bitmap);
|
||||
-
|
||||
bdrv_graph_wrlock_drained();
|
||||
ret = block_job_add_bdrv(&s->common, "source", bs, 0,
|
||||
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
|
||||
@@ -2099,9 +2113,6 @@ fail:
|
||||
g_free(s->replaces);
|
||||
blk_unref(s->target);
|
||||
bs_opaque->job = NULL;
|
||||
- if (s->dirty_bitmap) {
|
||||
- bdrv_release_dirty_bitmap(s->dirty_bitmap);
|
||||
- }
|
||||
job_early_fail(&s->common.job);
|
||||
}
|
||||
|
||||
@@ -2115,6 +2126,7 @@ fail:
|
||||
bdrv_graph_wrunlock();
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
+ bdrv_release_dirty_bitmap(bs_opaque->dirty_bitmap);
|
||||
bdrv_unref(mirror_top_bs);
|
||||
|
||||
return NULL;
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -151,7 +151,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \
|
||||
Summary: QEMU is a machine emulator and virtualizer
|
||||
Name: qemu-kvm
|
||||
Version: 10.1.0
|
||||
Release: 16%{?rcrel}%{?dist}%{?cc_suffix}.alma.1
|
||||
Release: 17%{?rcrel}%{?dist}%{?cc_suffix}.alma.1
|
||||
# Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped
|
||||
# Epoch 15 used for RHEL 8
|
||||
# Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5)
|
||||
@ -336,14 +336,25 @@ Patch94: kvm-scsi-save-load-SCSI-reservation-state.patch
|
||||
Patch95: kvm-docs-add-SCSI-migrate-pr-documentation.patch
|
||||
# For RHEL-151679 - [rhel-9.8] Regression in BLOCK_IO_ERROR event delivery with (w|r)error setting of 'stop' or 'enospc' due to event rate limiting
|
||||
Patch96: kvm-block-Never-drop-BLOCK_IO_ERROR-with-action-stop-for.patch
|
||||
# For RHEL-155947 - Mirror job can miss writes during startup, corrupting the copy [rhel-9.8]
|
||||
# For RHEL-155948 - Mirror job can miss writes during startup, corrupting the copy [rhel-9]
|
||||
Patch97: kvm-mirror-Fix-missed-dirty-bitmap-writes-during-startup.patch
|
||||
# For RHEL-154174 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-9.8]
|
||||
Patch98: kvm-linux-aio-Put-all-parameters-into-qemu_laiocb.patch
|
||||
# For RHEL-154174 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-9.8]
|
||||
Patch99: kvm-linux-aio-Resubmit-tails-of-short-reads-writes.patch
|
||||
# For RHEL-154174 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-9.8]
|
||||
Patch100: kvm-block-io_uring-avoid-potentially-getting-stuck-after.patch
|
||||
# For RHEL-154174 - qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-9.8]
|
||||
Patch101: kvm-io-uring-Resubmit-tails-of-short-writes.patch
|
||||
|
||||
# AlmaLinux Patch
|
||||
Patch97: 0001-Bring-back-missing-line-in-target-ppc-cpu-models.patch
|
||||
Patch98: 0001-usb-add-config-options-for-hub-and-hid-devices-for-p.patch
|
||||
Patch99: 0001-Add-AlmaLinux-9-to-machine-class-options.patch
|
||||
Patch100: osuosl-enable-ppc64.patch
|
||||
Patch101: 0001-Remove-pnv_chip_find_core-calls-from-SPRD-helpers.patch
|
||||
Patch102: 0002-Remove-pre-3.0-migration-from-spapr_compat_rhel7_6.patch
|
||||
Patch102: 0001-Bring-back-missing-line-in-target-ppc-cpu-models.patch
|
||||
Patch103: 0001-usb-add-config-options-for-hub-and-hid-devices-for-p.patch
|
||||
Patch104: 0001-Add-AlmaLinux-9-to-machine-class-options.patch
|
||||
Patch105: osuosl-enable-ppc64.patch
|
||||
Patch106: 0001-Remove-pnv_chip_find_core-calls-from-SPRD-helpers.patch
|
||||
Patch107: 0002-Remove-pre-3.0-migration-from-spapr_compat_rhel7_6.patch
|
||||
|
||||
|
||||
# For RHEL-11424 - [IBM 9.6 FEAT] KVM: Full boot order support - qemu part
|
||||
@ -2071,13 +2082,26 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Sat Apr 04 2026 Eduard Abdullin <eabdullin@almalinux.org> - 17:10.1.0-16.alma.1
|
||||
* Thu Apr 16 2026 Eduard Abdullin <eabdullin@almalinux.org> - 17:10.1.0-17.alma.1
|
||||
- Enable building for ppc64le
|
||||
- Don't remove slof.bin for ppc64le
|
||||
- usb: add config options for hub and hid devices for ppc
|
||||
- Remove pnv_chip_find_core calls from SPRD helpers
|
||||
- Remove pre-3.0 migration from spapr_compat_rhel7_6
|
||||
|
||||
* Wed Apr 01 2026 Jon Maloy <jmaloy@redhat.com> - 10.1.0-17
|
||||
- kvm-mirror-Fix-missed-dirty-bitmap-writes-during-startup.patch [RHEL-155947 RHEL-155948]
|
||||
- kvm-linux-aio-Put-all-parameters-into-qemu_laiocb.patch [RHEL-154174]
|
||||
- kvm-linux-aio-Resubmit-tails-of-short-reads-writes.patch [RHEL-154174]
|
||||
- kvm-block-io_uring-avoid-potentially-getting-stuck-after.patch [RHEL-154174]
|
||||
- kvm-io-uring-Resubmit-tails-of-short-writes.patch [RHEL-154174]
|
||||
- Resolves: RHEL-155947
|
||||
(Mirror job can miss writes during startup, corrupting the copy [rhel-9.8])
|
||||
- Resolves: RHEL-155948
|
||||
(Mirror job can miss writes during startup, corrupting the copy [rhel-9])
|
||||
- Resolves: RHEL-154174
|
||||
(qemu-kvm: disk writes of fewer bytes than requested is a retry condition, not necessarily an indication of ENOSPC [rhel-9.8])
|
||||
|
||||
* Tue Mar 17 2026 Jon Maloy <jmaloy@redhat.com> - 10.1.0-16
|
||||
- kvm-block-Never-drop-BLOCK_IO_ERROR-with-action-stop-for.patch [RHEL-151679]
|
||||
- Resolves: RHEL-151679
|
||||
|
||||
Loading…
Reference in New Issue
Block a user