From: "Denis V. Lunev" <den@openvz.org>
To: andrey.drobyshev@virtuozzo.com
Cc: svt-core@virtuozzo.com, den@openvz.org
Subject: [PATCH hci-8.1 3/5] scsi-disk: fix WRITE SAME racing with inactivation of block nodes #VSTOR-151532
Date: Mon, 26 Oct 2026 18:49:27 +0100 [thread overview]
Message-ID: <20261026174929.685720-4-den@openvz.org> (raw)
In-Reply-To: <20261026174929.685720-1-den@openvz.org>
From: Denis V. Lunev <den@openvz.org>
WRITE SAME with a non-zero pattern is written in SCSI_WRITE_SAME_MAX
chunks, and each chunk is submitted from the completion callback of the
previous one. As with UNMAP, a drain only waits for the chunk in
flight, the next one is queued by blk_wait_while_drained(), and
bdrv_inactivate_all() resumes it on an inactive node:
bdrv_co_write_req_prepare: Assertion
`!(bs->open_flags & BDRV_O_INACTIVE)' failed.
Write the chunks from scsi_disk_co_aio_start() with BDRV_REQ_NO_QUEUE,
so a drain waits for the whole command. werror=ignore still goes on
with the next chunk.
The sector count becomes int64_t on the way: the old int overflowed for
a WRITE SAME(16) of 2^31 or more 512-byte sectors.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Hanna Reitz <hreitz@redhat.com>
Cc: qemu-stable@nongnu.org
---
hw/scsi/scsi-disk.c | 102 +++++++++++++++++---------------------------
1 file changed, 39 insertions(+), 63 deletions(-)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 8383b7cbe93..f287315fbc5 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1929,52 +1929,52 @@ invalid_field:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
}
-typedef struct WriteSameCBData {
- SCSIDiskReq *r;
- int64_t sector;
- int nb_sectors;
- QEMUIOVector qiov;
- struct iovec iov;
-} WriteSameCBData;
-
-static void scsi_write_same_complete(void *opaque, int ret)
+static int coroutine_fn scsi_write_same_co(SCSIDiskCoAIOCB *iocb)
{
- WriteSameCBData *data = opaque;
- SCSIDiskReq *r = data->r;
+ SCSIDiskReq *r = iocb->r;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ BlockBackend *blk = s->qdev.conf.blk;
+ uint8_t *inbuf = r->iov.iov_base;
+ uint32_t buflen = MIN(s->qdev.blocksize, r->buflen);
+ int64_t sector = r->req.cmd.lba * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
+ int64_t nb_sectors = (int64_t)scsi_data_cdb_xfer(r->req.cmd.buf) *
+ (s->qdev.blocksize / BDRV_SECTOR_SIZE);
+ size_t size = MIN(nb_sectors * BDRV_SECTOR_SIZE, SCSI_WRITE_SAME_MAX);
+ uint8_t *buf = blk_blockalign(blk, size);
+ int ret = 0;
+ size_t i, l;
+
+ for (i = 0; i < size; i += l) {
+ l = MIN(buflen, size - i);
+ memcpy(&buf[i], inbuf, l);
+ }
- assert(r->req.aiocb != NULL);
- r->req.aiocb = NULL;
+ while (nb_sectors > 0) {
+ size_t chunk = MIN(nb_sectors * BDRV_SECTOR_SIZE, size);
- if (scsi_disk_req_check_error(r, ret, true)) {
- goto done;
- }
+ if (iocb->canceled) {
+ ret = -ECANCELED;
+ break;
+ }
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ block_acct_start(blk_get_stats(blk), &r->acct, chunk,
+ BLOCK_ACCT_WRITE);
+ ret = blk_co_pwrite(blk, sector << BDRV_SECTOR_BITS, chunk, buf,
+ BDRV_REQ_NO_QUEUE);
+ if (ret < 0) {
+ if (!scsi_disk_ignore_error(r, ret)) {
+ break;
+ }
+ ret = 0;
+ }
+ block_acct_done(blk_get_stats(blk), &r->acct);
- data->nb_sectors -= data->iov.iov_len / BDRV_SECTOR_SIZE;
- data->sector += data->iov.iov_len / BDRV_SECTOR_SIZE;
- data->iov.iov_len = MIN(data->nb_sectors * BDRV_SECTOR_SIZE,
- data->iov.iov_len);
- if (data->iov.iov_len) {
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- data->iov.iov_len, BLOCK_ACCT_WRITE);
- /* Reinitialize qiov, to handle unaligned WRITE SAME request
- * where final qiov may need smaller size */
- qemu_iovec_init_external(&data->qiov, &data->iov, 1);
- r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
- data->sector << BDRV_SECTOR_BITS,
- &data->qiov, 0,
- scsi_write_same_complete, data);
- return;
+ sector += chunk / BDRV_SECTOR_SIZE;
+ nb_sectors -= chunk / BDRV_SECTOR_SIZE;
}
- scsi_req_complete(&r->req, GOOD);
-
-done:
- scsi_req_unref(&r->req);
- qemu_vfree(data->iov.iov_base);
- g_free(data);
+ qemu_vfree(buf);
+ return ret;
}
static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
@@ -1983,9 +1983,6 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
uint32_t buflen = MIN(s->qdev.blocksize, r->buflen);
- WriteSameCBData *data;
- uint8_t *buf;
- int i, l;
/* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */
if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
@@ -2017,28 +2014,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
return;
}
- data = g_new0(WriteSameCBData, 1);
- data->r = r;
- data->sector = r->req.cmd.lba * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
- data->nb_sectors = nb_sectors * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
- data->iov.iov_len = MIN(data->nb_sectors * BDRV_SECTOR_SIZE,
- SCSI_WRITE_SAME_MAX);
- data->iov.iov_base = buf = blk_blockalign(s->qdev.conf.blk,
- data->iov.iov_len);
- qemu_iovec_init_external(&data->qiov, &data->iov, 1);
-
- for (i = 0; i < data->iov.iov_len; i += l) {
- l = MIN(buflen, data->iov.iov_len - i);
- memcpy(&buf[i], inbuf, l);
- }
-
- scsi_req_ref(&r->req);
- block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
- data->iov.iov_len, BLOCK_ACCT_WRITE);
- r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
- data->sector << BDRV_SECTOR_BITS,
- &data->qiov, 0,
- scsi_write_same_complete, data);
+ scsi_disk_co_aio_start(r, scsi_write_same_co);
}
static void scsi_disk_emulate_write_data(SCSIRequest *req)
--
2.53.0
next prev parent reply other threads:[~2026-10-26 17:49 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 17:49 [PATCH hci-8.1 0/5] scsi-disk: fix UNMAP and WRITE SAME racing with inactivation #VSTOR-151532 Denis V. Lunev
2026-10-26 17:49 ` [PATCH hci-8.1 1/5] scsi-disk: check all UNMAP descriptors before discarding any #VSTOR-151532 Denis V. Lunev
2026-10-26 17:49 ` [PATCH hci-8.1 2/5] scsi-disk: fix UNMAP racing with inactivation of block nodes #VSTOR-151532 Denis V. Lunev
2026-10-26 17:49 ` Denis V. Lunev [this message]
2026-10-26 17:49 ` [PATCH hci-8.1 4/5] virtio-scsi-test: split virtio_scsi_do_command() into submit and wait #VSTOR-151532 Denis V. Lunev
2026-10-26 17:49 ` [PATCH hci-8.1 5/5] virtio-scsi-test: test UNMAP and WRITE SAME during inactivation #VSTOR-151532 Denis V. Lunev
2026-10-27 10:56 ` [PATCH hci-8.1 0/5] scsi-disk: fix UNMAP and WRITE SAME racing with " Andrey Drobyshev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261026174929.685720-4-den@openvz.org \
--to=den@openvz.org \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=svt-core@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.