* [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support
2019-11-08 9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
@ 2019-11-08 9:35 ` Yaowei Bai
2019-11-08 9:35 ` [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface Yaowei Bai
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08 9:35 UTC (permalink / raw)
To: pbonzini, fam, dillaman, kwolf, mreitz
Cc: baiyaowei, yangjun, qemu-devel, qemu-block
Some storages(i.e. librbd) already have interfaces to handle some SCSI
commands directly. This patch adds COMPARE_AND_WRITE command support
through the write path in the block io layer by introducing a new element
BDRV_REQ_COMPARE_AND_WRITE into BdrvRequestFlags which indicates a
COMPARE_AND_WRITE request. In this way we could easily extend to other
SCSI commands support like WRITE_SAME in the future.
Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
block/io.c | 20 ++++++++++++++++++++
include/block/block.h | 5 +++--
include/block/block_int.h | 3 +++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/block/io.c b/block/io.c
index f75777f..3507d71 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1186,6 +1186,26 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
goto emulate_flags;
}
+ if (drv->bdrv_aio_compare_and_write &&
+ (flags & BDRV_REQ_COMPARE_AND_WRITE)) {
+ BlockAIOCB *acb;
+ CoroutineIOCompletion co = {
+ .coroutine = qemu_coroutine_self(),
+ };
+
+ acb = drv->bdrv_aio_compare_and_write(bs, offset, bytes, qiov,
+ flags & bs->supported_write_flags,
+ bdrv_co_io_em_complete, &co);
+ flags &= ~bs->supported_write_flags;
+ if (acb == NULL) {
+ ret = -EIO;
+ } else {
+ qemu_coroutine_yield();
+ ret = co.ret;
+ }
+ goto emulate_flags;
+ }
+
if (drv->bdrv_aio_pwritev) {
BlockAIOCB *acb;
CoroutineIOCompletion co = {
diff --git a/include/block/block.h b/include/block/block.h
index 1df9848..f71aa4f 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -92,9 +92,10 @@ typedef enum {
* on read request and means that caller doesn't really need data to be
* written to qiov parameter which may be NULL.
*/
- BDRV_REQ_PREFETCH = 0x200,
+ BDRV_REQ_PREFETCH = 0x200,
+ BDRV_REQ_COMPARE_AND_WRITE = 0x400,
/* Mask of valid flags */
- BDRV_REQ_MASK = 0x3ff,
+ BDRV_REQ_MASK = 0x7ff,
} BdrvRequestFlags;
typedef struct BlockSizes {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index dd033d0..96096e0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -189,6 +189,9 @@ struct BlockDriver {
BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs,
int64_t offset, int bytes,
BlockCompletionFunc *cb, void *opaque);
+ BlockAIOCB *(*bdrv_aio_compare_and_write)(BlockDriverState *bs,
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags,
+ BlockCompletionFunc *cb, void *opaque);
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface
2019-11-08 9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
2019-11-08 9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
@ 2019-11-08 9:35 ` Yaowei Bai
2019-11-08 9:35 ` [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support Yaowei Bai
2019-11-08 9:35 ` [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE Yaowei Bai
3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08 9:35 UTC (permalink / raw)
To: pbonzini, fam, dillaman, kwolf, mreitz
Cc: baiyaowei, yangjun, qemu-devel, qemu-block
This patch adds librbd's SCSI COMPARE_AND_WRITE command interface
support with bdrv_aio_compare_and_write function pointer. Note
currently when a miscompare happens a mismatch offset of 0 is
always reported rather than the actual mismatch offset. This
should not be a big issue contemporarily and will be fixed
accordingly in the future.
Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
block/raw-format.c | 3 ++-
block/rbd.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/block/raw-format.c b/block/raw-format.c
index 3a76ec7..e87cd44 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -439,7 +439,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bs->sg = bs->file->bs->sg;
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
- (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags) |
+ (BDRV_REQ_COMPARE_AND_WRITE & bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
bs->file->bs->supported_zero_flags);
diff --git a/block/rbd.c b/block/rbd.c
index 027cbcc..0e45bc3 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,11 +73,18 @@
#define LIBRBD_USE_IOVEC 0
#endif
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+#define LIBRBD_HAVE_COMPARE_AND_WRITE 1
+#else
+#define LIBRBD_HAVE_COMPARE_AND_WRITE 0
+#endif
+
typedef enum {
RBD_AIO_READ,
RBD_AIO_WRITE,
RBD_AIO_DISCARD,
- RBD_AIO_FLUSH
+ RBD_AIO_FLUSH,
+ RBD_AIO_COMPARE_AND_WRITE
} RBDAIOCmd;
typedef struct RBDAIOCB {
@@ -798,6 +805,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
}
}
+ if (LIBRBD_HAVE_COMPARE_AND_WRITE) {
+ bs->supported_write_flags = BDRV_REQ_COMPARE_AND_WRITE;
+ }
+
r = 0;
goto out;
@@ -933,7 +944,15 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
rcb = g_new(RADOSCB, 1);
- if (!LIBRBD_USE_IOVEC) {
+ if (cmd == RBD_AIO_COMPARE_AND_WRITE) {
+ acb->bounce = qemu_try_blockalign(bs, qiov->size);
+ if (acb->bounce == NULL) {
+ goto failed;
+ }
+
+ qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
+ rcb->buf = acb->bounce;
+ } else if (!LIBRBD_USE_IOVEC) {
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
acb->bounce = NULL;
} else {
@@ -993,6 +1012,10 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
case RBD_AIO_FLUSH:
r = rbd_aio_flush_wrapper(s->image, c);
break;
+ case RBD_AIO_COMPARE_AND_WRITE:
+ r = rbd_aio_compare_and_write(s->image, off, size / 2, rcb->buf,
+ (rcb->buf + size / 2), c, 0, 0);
+ break;
default:
r = -EINVAL;
}
@@ -1056,6 +1079,20 @@ static int qemu_rbd_co_flush(BlockDriverState *bs)
}
#endif
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+static BlockAIOCB *qemu_rbd_aio_compare_and_write(BlockDriverState *bs,
+ uint64_t offset,
+ uint64_t bytes,
+ QEMUIOVector *qiov,
+ int flags,
+ BlockCompletionFunc *cb,
+ void *opaque)
+{
+ return rbd_start_aio(bs, offset, qiov, bytes, cb, opaque,
+ RBD_AIO_COMPARE_AND_WRITE);
+}
+#endif
+
static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVRBDState *s = bs->opaque;
@@ -1310,6 +1347,10 @@ static BlockDriver bdrv_rbd = {
.bdrv_aio_pdiscard = qemu_rbd_aio_pdiscard,
#endif
+#ifdef LIBRBD_SUPPORTS_COMPARE_AND_WRITE
+ .bdrv_aio_compare_and_write = qemu_rbd_aio_compare_and_write,
+#endif
+
.bdrv_snapshot_create = qemu_rbd_snap_create,
.bdrv_snapshot_delete = qemu_rbd_snap_remove,
.bdrv_snapshot_list = qemu_rbd_snap_list,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support
2019-11-08 9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
2019-11-08 9:35 ` [PATCH 1/4 V2] block: add SCSI COMPARE_AND_WRITE support Yaowei Bai
2019-11-08 9:35 ` [PATCH 2/4 V2] block/rbd: implement bdrv_aio_compare_and_write interface Yaowei Bai
@ 2019-11-08 9:35 ` Yaowei Bai
2019-11-08 9:35 ` [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE Yaowei Bai
3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08 9:35 UTC (permalink / raw)
To: pbonzini, fam, dillaman, kwolf, mreitz
Cc: baiyaowei, yangjun, qemu-devel, qemu-block
This patch emulates COMPARE_AND_WRITE command with the
BDRV_REQ_COMPARE_AND_WRITE flag introduced by last patch. It matches
the SBC-4 standard except the FUA bit support, it'll be finished in
the next patch.
Note that cmd->xfer is set 2 * the number got by scsi_data_cdb_xfer
so we could touch the least code.
Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
hw/scsi/emulation.c | 1 +
hw/scsi/scsi-bus.c | 4 +++
hw/scsi/scsi-disk.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
hw/scsi/trace-events | 1 +
include/hw/scsi/emulation.h | 3 ++
include/scsi/utils.h | 2 ++
scsi/utils.c | 5 +++
7 files changed, 104 insertions(+)
diff --git a/hw/scsi/emulation.c b/hw/scsi/emulation.c
index 06d62f3..1f53c4a 100644
--- a/hw/scsi/emulation.c
+++ b/hw/scsi/emulation.c
@@ -9,6 +9,7 @@ int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl)
memset(outbuf, 0, 0x3c);
outbuf[0] = bl->wsnz; /* wsnz */
+ outbuf[1] = MAX_COMPARE_AND_WRITE_LENGTH;
if (bl->max_io_sectors) {
/* optimal transfer length granularity. This field and the optimal
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 359d50d..a20eb11 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1003,6 +1003,9 @@ static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case WRITE_VERIFY_16:
cmd->xfer *= dev->blocksize;
break;
+ case COMPARE_AND_WRITE:
+ cmd->xfer *= 2 * dev->blocksize;
+ break;
case READ_6:
case READ_REVERSE:
/* length 0 means 256 blocks */
@@ -1222,6 +1225,7 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
case PERSISTENT_RESERVE_OUT:
case MAINTENANCE_OUT:
case SET_WINDOW:
+ case COMPARE_AND_WRITE:
case SCAN:
/* SCAN conflicts with START_STOP. START_STOP has cmd->xfer set to 0 for
* non-scanner devices, so we only get here for SCAN and not for START_STOP.
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 07fb5eb..f9a0267 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -478,6 +478,9 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
case ENOSPC:
scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
break;
+ case EILSEQ:
+ scsi_check_condition(r, SENSE_CODE(MISCOMPARE_DURING_VERIFY));
+ break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@@ -1825,6 +1828,84 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
scsi_write_same_complete, data);
}
+typedef struct CompareAndWriteCBData {
+ SCSIDiskReq *r;
+ int64_t sector;
+ int nb_sectors;
+ QEMUIOVector qiov;
+ struct iovec iov;
+} CompareAndWriteCBData;
+
+static void scsi_compare_and_write_complete(void *opaque, int ret)
+{
+ CompareAndWriteCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
+ if (scsi_disk_req_check_error(r, ret, true)) {
+ goto done;
+ }
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_req_complete(&r->req, GOOD);
+
+done:
+ scsi_req_unref(&r->req);
+ qemu_vfree(data->iov.iov_base);
+ g_free(data);
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
+}
+
+static void scsi_disk_emulate_compare_and_write(SCSIDiskReq *r, uint8_t *inbuf)
+{
+ SCSIRequest *req = &r->req;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+ uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
+ CompareAndWriteCBData *data;
+ uint8_t *buf;
+ int i;
+
+ if (nb_sectors > MAX_COMPARE_AND_WRITE_LENGTH) {
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+ return;
+ }
+
+ if (blk_is_read_only(s->qdev.conf.blk)) {
+ scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
+ return;
+ }
+
+ if (r->req.cmd.lba > s->qdev.max_lba ||
+ !check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+ return;
+ }
+
+ data = g_new0(CompareAndWriteCBData, 1);
+ data->r = r;
+ data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+ data->nb_sectors = r->req.cmd.xfer * (s->qdev.blocksize / 512);
+ data->iov.iov_len = data->nb_sectors;
+ 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 += s->qdev.blocksize) {
+ memcpy(&buf[i], &inbuf[i], s->qdev.blocksize);
+ }
+
+ 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, BDRV_REQ_COMPARE_AND_WRITE,
+ scsi_compare_and_write_complete, data);
+}
+
static void scsi_disk_emulate_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1861,6 +1942,9 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
scsi_disk_emulate_write_same(r, r->iov.iov_base);
break;
+ case COMPARE_AND_WRITE:
+ scsi_disk_emulate_compare_and_write(r, r->iov.iov_base);
+ break;
default:
abort();
}
@@ -2115,6 +2199,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
trace_scsi_disk_emulate_command_WRITE_SAME(
req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer);
break;
+ case COMPARE_AND_WRITE:
+ trace_scsi_disk_emulate_command_COMPARE_AND_WRITE(r->req.cmd.xfer);
+ break;
default:
trace_scsi_disk_emulate_command_UNKNOWN(buf[0],
scsi_command_name(buf[0]));
@@ -2542,6 +2629,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[VERIFY_10] = &scsi_disk_emulate_reqops,
[VERIFY_12] = &scsi_disk_emulate_reqops,
[VERIFY_16] = &scsi_disk_emulate_reqops,
+ [COMPARE_AND_WRITE] = &scsi_disk_emulate_reqops,
[READ_6] = &scsi_disk_dma_reqops,
[READ_10] = &scsi_disk_dma_reqops,
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index b082005..0783e58 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -317,6 +317,7 @@ scsi_disk_emulate_command_MODE_SELECT_10(size_t xfer) "Mode Select(10) (len %zd)
scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)"
scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)"
+scsi_disk_emulate_command_COMPARE_AND_WRITE(size_t xfer) "COMPARE AND WRITE (len %zd)"
scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)"
scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)"
diff --git a/include/hw/scsi/emulation.h b/include/hw/scsi/emulation.h
index 9521704..2148316 100644
--- a/include/hw/scsi/emulation.h
+++ b/include/hw/scsi/emulation.h
@@ -1,6 +1,9 @@
#ifndef HW_SCSI_EMULATION_H
#define HW_SCSI_EMULATION_H
+/* maximum compare and write length : 64kb */
+#define MAX_COMPARE_AND_WRITE_LENGTH 128
+
typedef struct SCSIBlockLimits {
bool wsnz;
uint16_t min_io_size;
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index fbc5588..35f554e 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -101,6 +101,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
extern const struct SCSISense sense_code_WRITE_PROTECTED;
/* Data Protection, Space Allocation Failed Write Protect */
extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+/* Miscompare, Miscompare During Verify Operation */
+extern const struct SCSISense sense_code_MISCOMPARE_DURING_VERIFY;
#define SENSE_CODE(x) sense_code_ ## x
diff --git a/scsi/utils.c b/scsi/utils.c
index c50e81f..c142a53 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -311,6 +311,11 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
};
+/* Miscompare, Miscompare During Verify Operation */
+const struct SCSISense sense_code_MISCOMPARE_DURING_VERIFY = {
+ .key = MISCOMPARE, .asc = 0x1d, .ascq = 0x00
+};
+
/*
* scsi_convert_sense
*
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4 V2] scsi-disk: add FUA support for COMPARE_AND_WRITE
2019-11-08 9:35 [PATCH 0/4 V2] SCSI COMPARE_AND_WRITE command support Yaowei Bai
` (2 preceding siblings ...)
2019-11-08 9:35 ` [PATCH 3/4 V2] hw/scsi: add SCSI COMPARE_AND_WRITE support Yaowei Bai
@ 2019-11-08 9:35 ` Yaowei Bai
3 siblings, 0 replies; 5+ messages in thread
From: Yaowei Bai @ 2019-11-08 9:35 UTC (permalink / raw)
To: pbonzini, fam, dillaman, kwolf, mreitz
Cc: baiyaowei, yangjun, qemu-devel, qemu-block
It is implemented in the blk_aio_pwritev's callback function in a way
similar to its emulation in scsi_write_do_fua function
Signed-off-by: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
---
hw/scsi/scsi-disk.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index f9a0267..0731a3b 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -229,6 +229,7 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
case WRITE_10:
case WRITE_12:
case WRITE_16:
+ case COMPARE_AND_WRITE:
return (cmd->buf[1] & 8) != 0;
case VERIFY_10:
@@ -1850,10 +1851,17 @@ static void scsi_compare_and_write_complete(void *opaque, int ret)
}
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ if (r->need_fua_emulation) {
+ block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
+ BLOCK_ACCT_FLUSH);
+ r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
+ goto free;
+ }
scsi_req_complete(&r->req, GOOD);
done:
scsi_req_unref(&r->req);
+free:
qemu_vfree(data->iov.iov_base);
g_free(data);
aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
@@ -1954,6 +1962,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+ SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
uint64_t nb_sectors;
uint8_t *outbuf;
int buflen;
@@ -2209,6 +2218,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
assert(!r->req.aiocb);
+ r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd);
r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
if (r->iov.iov_len == 0) {
scsi_req_complete(&r->req, GOOD);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 5+ messages in thread