From: Fam Zheng <famz@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, Fam Zheng <famz@redhat.com>,
Kevin Wolf <kwolf@redhat.com>, Max Reitz <mreitz@redhat.com>,
pbonzini@redhat.com, Stefan Hajnoczi <stefanha@redhat.com>,
eblake@redhat.com
Subject: [Qemu-devel] [RFC PATCH 3/8] block: Introduce bdrv_co_copy_range
Date: Thu, 29 Mar 2018 19:09:09 +0800 [thread overview]
Message-ID: <20180329110914.20888-4-famz@redhat.com> (raw)
In-Reply-To: <20180329110914.20888-1-famz@redhat.com>
This tries to do offloaded data copying in the same procotol (but
possibly a different BDS), or fall back to a bounce buffer if not
supported.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
block/io.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++
include/block/block.h | 4 ++
include/block/block_int.h | 14 +++++
3 files changed, 166 insertions(+)
diff --git a/block/io.c b/block/io.c
index 1b4cfcacb1..64cd3a5170 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2870,3 +2870,151 @@ int coroutine_fn bdrv_co_map_range(BdrvChild *child, int64_t offset,
}
return -ENOTSUP;
}
+
+typedef struct {
+ BdrvChild *child;
+ int64_t offset;
+ int64_t remaining;
+ BlockDriverState *file;
+ int64_t map;
+ int64_t pnum;
+ int status;
+} BdrvCopyRangeState;
+
+static inline void bdrv_range_advance(BdrvCopyRangeState *s, int bytes)
+{
+ s->offset += bytes;
+ s->remaining -= bytes;
+ assert(s->remaining >= 0);
+ s->map = 0;
+ s->pnum = MAX(0, s->pnum - bytes);
+ s->file = NULL;
+}
+
+static int coroutine_fn
+bdrv_co_copy_range_iteration(BdrvCopyRangeState *in, BdrvCopyRangeState *out)
+{
+ int ret;
+ int bytes = MIN(in->remaining, out->remaining);
+ QEMUIOVector qiov;
+ BlockDriverState *in_bs = in->child->bs;
+ BlockDriverState *out_bs = out->child->bs;
+ uint8_t *buf;
+
+ if (!in->pnum) {
+ in->status = bdrv_co_map_range(in->child, in->offset, in->remaining,
+ &in->pnum, &in->map, &in->file, 0);
+ }
+ if (in->status < 0 || !in->file ||
+ in->offset + bytes > bdrv_getlength(in->file)) {
+ goto fallback;
+ }
+
+ assert(in->pnum > 0);
+ bytes = MIN(bytes, in->pnum);
+ if (in->status & BDRV_BLOCK_ZERO) {
+ ret = bdrv_co_pwrite_zeroes(out->child, out->offset, in->pnum, 0);
+ if (ret) {
+ return ret;
+ }
+ bdrv_range_advance(in, bytes);
+ bdrv_range_advance(out, bytes);
+ return 0;
+ }
+
+ if (!(in->status & BDRV_BLOCK_OFFSET_VALID)) {
+ goto fallback;
+ }
+
+ out->status = bdrv_co_map_range(out->child, out->offset, out->remaining,
+ &out->pnum, &out->map, &out->file,
+ BDRV_REQ_ALLOCATE);
+ if (out->status < 0 || !out->file ||
+ !(out->status & BDRV_BLOCK_OFFSET_VALID)) {
+ goto fallback;
+ }
+
+ bytes = MIN(bytes, out->pnum);
+
+ if (in->file->drv->bdrv_co_copy_range) {
+ if (!in->file->drv->bdrv_co_copy_range(in->file, in->map,
+ out->file, out->map,
+ bytes)) {
+ bdrv_range_advance(in, bytes);
+ bdrv_range_advance(out, bytes);
+ return 0;
+ }
+ }
+ /* At this point we could maximize bytes again */
+ bytes = MIN(in->remaining, out->remaining);
+
+fallback:
+ buf = qemu_try_memalign(MAX(bdrv_opt_mem_align(in_bs),
+ bdrv_opt_mem_align(out_bs)),
+ bytes);
+ if (!buf) {
+ return -ENOMEM;
+ }
+
+ qemu_iovec_init(&qiov, 1);
+ qemu_iovec_add(&qiov, buf, bytes);
+
+ ret = bdrv_co_preadv(in->child, in->offset, bytes, &qiov, 0);
+ if (ret) {
+ goto out;
+ }
+ ret = bdrv_co_pwritev(out->child, out->offset, bytes, &qiov, 0);
+ if (!ret) {
+ bdrv_range_advance(in, bytes);
+ bdrv_range_advance(out, bytes);
+ }
+
+out:
+ qemu_vfree(buf);
+ qemu_iovec_destroy(&qiov);
+ return ret;
+}
+
+int coroutine_fn bdrv_co_copy_range(BdrvChild *child_in, int64_t off_in,
+ BdrvChild *child_out, int64_t off_out,
+ int bytes)
+{
+ BdrvTrackedRequest in_req, out_req;
+ BlockDriverState *in_bs = child_in->bs;
+ BlockDriverState *out_bs = child_out->bs;
+ int ret = 0;
+ BdrvCopyRangeState in = (BdrvCopyRangeState) {
+ .child = child_in,
+ .offset = off_in,
+ .remaining = bytes,
+ };
+ BdrvCopyRangeState out = (BdrvCopyRangeState) {
+ .child = child_out,
+ .offset = off_out,
+ .remaining = bytes,
+ };
+
+ bdrv_inc_in_flight(in_bs);
+ bdrv_inc_in_flight(out_bs);
+ tracked_request_begin(&in_req, in_bs, off_in, bytes, BDRV_TRACKED_READ);
+ tracked_request_begin(&out_req, out_bs, off_out, bytes, BDRV_TRACKED_WRITE);
+
+ wait_serialising_requests(&in_req);
+ wait_serialising_requests(&out_req);
+
+ while (in.remaining > 0) {
+ ret = bdrv_co_copy_range_iteration(&in, &out);
+ assert(in.remaining == out.remaining);
+ if (ret < 0) {
+ goto out;
+ }
+ }
+ assert(in.remaining == 0);
+ assert(out.remaining == 0);
+out:
+ tracked_request_end(&in_req);
+ tracked_request_end(&out_req);
+ bdrv_dec_in_flight(in_bs);
+ bdrv_dec_in_flight(out_bs);
+ return ret;
+}
diff --git a/include/block/block.h b/include/block/block.h
index 21d3e9db32..7d57e53cfe 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -610,4 +610,8 @@ int bdrv_co_map_range(BdrvChild *child, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map,
BlockDriverState **file,
int flags);
+int bdrv_co_copy_range(BdrvChild *child_in, int64_t off_in,
+ BdrvChild *child_out, int64_t off_out,
+ int bytes);
+
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 3f3f6f3efd..10a23b5754 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -496,6 +496,20 @@ struct BlockDriver {
int64_t bytes, int64_t *pnum, int64_t *map,
BlockDriverState **file,
int flags);
+ /**
+ * Do offloaded copying of data range. Must be implemented together with
+ * bdrv_co_map_range.
+ *
+ * @bs: where to copy data from
+ * @off_in: the offset to copy data from in @bs
+ * @out: where to write data to. This is guaranteed to be the same
+ * BlockDriver as @bs
+ * @off_out: the offset to copy data to in @out
+ * @bytes: the number of bytes to copy
+ */
+ int (*bdrv_co_copy_range)(BlockDriverState *bs, int64_t off_in,
+ BlockDriverState *out, int64_t off_out,
+ int bytes);
QLIST_ENTRY(BlockDriver) list;
};
--
2.14.3
next prev parent reply other threads:[~2018-03-29 11:09 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-29 11:09 [Qemu-devel] [RFC PATCH 0/8] qemu-img convert with copy offloading Fam Zheng
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 1/8] block: Introduce bdrv_co_map_range API Fam Zheng
2018-04-04 12:57 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2018-04-04 13:01 ` Stefan Hajnoczi
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 2/8] qcow2: Implement bdrv_co_map_range Fam Zheng
2018-03-29 11:09 ` Fam Zheng [this message]
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 4/8] file-posix: Implement bdrv_co_copy_range Fam Zheng
2018-04-04 13:20 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2018-04-09 8:53 ` Fam Zheng
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 5/8] file-posix: Implement bdrv_co_map_range Fam Zheng
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 6/8] raw: Implement raw_co_map_range Fam Zheng
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 7/8] block-backend: Add blk_co_copy_range Fam Zheng
2018-03-29 11:09 ` [Qemu-devel] [RFC PATCH 8/8] qemu-img: Convert with copy offloading Fam Zheng
2018-03-31 8:13 ` [Qemu-devel] [RFC PATCH 0/8] qemu-img convert " no-reply
2018-04-04 13:23 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2018-04-04 13:49 ` Fam Zheng
2018-04-04 15:26 ` Paolo Bonzini
2018-04-05 12:55 ` Stefan Hajnoczi
2018-04-06 11:41 ` Paolo Bonzini
2018-04-08 9:21 ` Fam Zheng
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=20180329110914.20888-4-famz@redhat.com \
--to=famz@redhat.com \
--cc=eblake@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).