@@ -438,7 +438,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);
@@ -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,9 @@ 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 +943,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 +1011,9 @@ 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 +1077,18 @@ 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;
@@ -1309,6 +1342,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,
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 | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-)