nbd patches for 2021-02-02

- more cleanup from iotest python conversion
 - progress towards consistent use of signed 64-bit types through block layer
 - fix some crashes related to NBD reconnect
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAmAasREACgkQp6FrSiUn
 Q2q0bAgAqkkrQtMhTcQ6cZenLhBc7qIojOybnOnO8hXb7SpndHjE9f9OF0f0+OOm
 9vk24KyohvCFc7IwMHA/lccvHYH4Ftb8VPgYEs+U+iCxzdyM8M1goy8tbOp82Fgg
 8ahxRbBP4VTkBUiXNcCxO2KbBQL2m+YkLKvfbw+XN0KbxER6hoikfNsSty97/3su
 ZKtfEqBPH7Tl7kJz0JBfGTpCSPa6cXFzIwxK+m8pq7IKeNrICg1Uu0VR49QfTWlh
 2ptIxvKx+QkxLV+QoW7m/fqXFaIFye0tQAwTr/5b3/jBtAkgg8Yznn0TMgiqwXMr
 SuxbUpjNWqBtjjhwavSje020VhrD2w==
 =7eUe
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-02-02-v2' into staging

nbd patches for 2021-02-02

- more cleanup from iotest python conversion
- progress towards consistent use of signed 64-bit types through block layer
- fix some crashes related to NBD reconnect

# gpg: Signature made Wed 03 Feb 2021 14:20:01 GMT
# gpg:                using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg:                 aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg:                 aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2  F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-nbd-2021-02-02-v2:
  nbd: make nbd_read* return -EIO on error
  block/nbd: only enter connection coroutine if it's present
  block/nbd: only detach existing iochannel from aio_context
  block/io: use int64_t bytes in copy_range
  block/io: support int64_t bytes in read/write wrappers
  block/io: support int64_t bytes in bdrv_co_p{read,write}v_part()
  block/io: support int64_t bytes in bdrv_aligned_preadv()
  block/io: support int64_t bytes in bdrv_co_do_copy_on_readv()
  block/io: support int64_t bytes in bdrv_aligned_pwritev()
  block/io: support int64_t bytes in bdrv_co_do_pwrite_zeroes()
  block/io: use int64_t bytes in driver wrappers
  block: use int64_t as bytes type in tracked requests
  block/io: improve bdrv_check_request: check qiov too
  block/throttle-groups: throttle_group_co_io_limits_intercept(): 64bit bytes
  block/io: bdrv_pad_request(): support qemu_iovec_init_extended failure
  block/io: refactor bdrv_pad_request(): move bdrv_pad_request() up
  block: fix theoretical overflow in bdrv_init_padding()
  util/iov: make qemu_iovec_init_extended() honest
  block: refactor bdrv_check_request: add errp
  iotests: Fix expected whitespace for 185

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-02-03 14:52:12 +00:00
commit 1ed9228f63
15 changed files with 275 additions and 133 deletions

View file

@ -31,7 +31,7 @@ typedef struct BlkverifyRequest {
uint64_t bytes; uint64_t bytes;
int flags; int flags;
int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *, int (*request_fn)(BdrvChild *, int64_t, int64_t, QEMUIOVector *,
BdrvRequestFlags); BdrvRequestFlags);
int ret; /* test image result */ int ret; /* test image result */

View file

@ -2969,7 +2969,7 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
req->bytes = BDRV_MAX_LENGTH - req->offset; req->bytes = BDRV_MAX_LENGTH - req->offset;
assert(bdrv_check_request(req->offset, req->bytes) == 0); bdrv_check_request(req->offset, req->bytes, &error_abort);
bdrv_make_request_serialising(req, bs->bl.request_alignment); bdrv_make_request_serialising(req, bs->bl.request_alignment);
} }

View file

@ -41,7 +41,7 @@
static void bdrv_parent_cb_resize(BlockDriverState *bs); static void bdrv_parent_cb_resize(BlockDriverState *bs);
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags); int64_t offset, int64_t bytes, BdrvRequestFlags flags);
static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore, static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
bool ignore_bds_parents) bool ignore_bds_parents)
@ -717,10 +717,10 @@ static void tracked_request_end(BdrvTrackedRequest *req)
static void tracked_request_begin(BdrvTrackedRequest *req, static void tracked_request_begin(BdrvTrackedRequest *req,
BlockDriverState *bs, BlockDriverState *bs,
int64_t offset, int64_t offset,
uint64_t bytes, int64_t bytes,
enum BdrvTrackedRequestType type) enum BdrvTrackedRequestType type)
{ {
assert(bytes <= INT64_MAX && offset <= INT64_MAX - bytes); bdrv_check_request(offset, bytes, &error_abort);
*req = (BdrvTrackedRequest){ *req = (BdrvTrackedRequest){
.bs = bs, .bs = bs,
@ -741,8 +741,10 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
} }
static bool tracked_request_overlaps(BdrvTrackedRequest *req, static bool tracked_request_overlaps(BdrvTrackedRequest *req,
int64_t offset, uint64_t bytes) int64_t offset, int64_t bytes)
{ {
bdrv_check_request(offset, bytes, &error_abort);
/* aaaa bbbb */ /* aaaa bbbb */
if (offset >= req->overlap_offset + req->overlap_bytes) { if (offset >= req->overlap_offset + req->overlap_bytes) {
return false; return false;
@ -810,8 +812,10 @@ static void tracked_request_set_serialising(BdrvTrackedRequest *req,
uint64_t align) uint64_t align)
{ {
int64_t overlap_offset = req->offset & ~(align - 1); int64_t overlap_offset = req->offset & ~(align - 1);
uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align) int64_t overlap_bytes =
- overlap_offset; ROUND_UP(req->offset + req->bytes, align) - overlap_offset;
bdrv_check_request(req->offset, req->bytes, &error_abort);
if (!req->serialising) { if (!req->serialising) {
qatomic_inc(&req->bs->serialising_in_flight); qatomic_inc(&req->bs->serialising_in_flight);
@ -920,26 +924,75 @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
return waited; return waited;
} }
int bdrv_check_request(int64_t offset, int64_t bytes) static int bdrv_check_qiov_request(int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset,
Error **errp)
{ {
if (offset < 0 || bytes < 0) { /*
* Check generic offset/bytes correctness
*/
if (offset < 0) {
error_setg(errp, "offset is negative: %" PRIi64, offset);
return -EIO;
}
if (bytes < 0) {
error_setg(errp, "bytes is negative: %" PRIi64, bytes);
return -EIO; return -EIO;
} }
if (bytes > BDRV_MAX_LENGTH) { if (bytes > BDRV_MAX_LENGTH) {
error_setg(errp, "bytes(%" PRIi64 ") exceeds maximum(%" PRIi64 ")",
bytes, BDRV_MAX_LENGTH);
return -EIO;
}
if (offset > BDRV_MAX_LENGTH) {
error_setg(errp, "offset(%" PRIi64 ") exceeds maximum(%" PRIi64 ")",
offset, BDRV_MAX_LENGTH);
return -EIO; return -EIO;
} }
if (offset > BDRV_MAX_LENGTH - bytes) { if (offset > BDRV_MAX_LENGTH - bytes) {
error_setg(errp, "sum of offset(%" PRIi64 ") and bytes(%" PRIi64 ") "
"exceeds maximum(%" PRIi64 ")", offset, bytes,
BDRV_MAX_LENGTH);
return -EIO;
}
if (!qiov) {
return 0;
}
/*
* Check qiov and qiov_offset
*/
if (qiov_offset > qiov->size) {
error_setg(errp, "qiov_offset(%zu) overflow io vector size(%zu)",
qiov_offset, qiov->size);
return -EIO;
}
if (bytes > qiov->size - qiov_offset) {
error_setg(errp, "bytes(%" PRIi64 ") + qiov_offset(%zu) overflow io "
"vector size(%zu)", bytes, qiov_offset, qiov->size);
return -EIO; return -EIO;
} }
return 0; return 0;
} }
static int bdrv_check_request32(int64_t offset, int64_t bytes) int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp)
{ {
int ret = bdrv_check_request(offset, bytes); return bdrv_check_qiov_request(offset, bytes, NULL, 0, errp);
}
static int bdrv_check_request32(int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset)
{
int ret = bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -952,7 +1005,7 @@ static int bdrv_check_request32(int64_t offset, int64_t bytes)
} }
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags) int64_t bytes, BdrvRequestFlags flags)
{ {
return bdrv_pwritev(child, offset, bytes, NULL, return bdrv_pwritev(child, offset, bytes, NULL,
BDRV_REQ_ZERO_WRITE | flags); BDRV_REQ_ZERO_WRITE | flags);
@ -1000,7 +1053,7 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
} }
/* See bdrv_pwrite() for the return codes */ /* See bdrv_pwrite() for the return codes */
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes) int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes)
{ {
int ret; int ret;
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
@ -1020,7 +1073,8 @@ int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
-EINVAL Invalid offset or number of bytes -EINVAL Invalid offset or number of bytes
-EACCES Trying to write a read-only device -EACCES Trying to write a read-only device
*/ */
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes) int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf,
int64_t bytes)
{ {
int ret; int ret;
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
@ -1041,7 +1095,7 @@ int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
* Returns 0 on success, -errno in error cases. * Returns 0 on success, -errno in error cases.
*/ */
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
const void *buf, int count) const void *buf, int64_t count)
{ {
int ret; int ret;
@ -1072,7 +1126,7 @@ static void bdrv_co_io_em_complete(void *opaque, int ret)
} }
static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs, static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, int flags) size_t qiov_offset, int flags)
{ {
@ -1082,6 +1136,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
int ret; int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(!(flags & ~BDRV_REQ_MASK)); assert(!(flags & ~BDRV_REQ_MASK));
assert(!(flags & BDRV_REQ_NO_FALLBACK)); assert(!(flags & BDRV_REQ_NO_FALLBACK));
@ -1141,7 +1196,7 @@ out:
} }
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, int flags) size_t qiov_offset, int flags)
{ {
@ -1151,6 +1206,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
int ret; int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(!(flags & ~BDRV_REQ_MASK)); assert(!(flags & ~BDRV_REQ_MASK));
assert(!(flags & BDRV_REQ_NO_FALLBACK)); assert(!(flags & BDRV_REQ_NO_FALLBACK));
@ -1221,14 +1277,16 @@ emulate_flags:
} }
static int coroutine_fn static int coroutine_fn
bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset, bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset,
uint64_t bytes, QEMUIOVector *qiov, int64_t bytes, QEMUIOVector *qiov,
size_t qiov_offset) size_t qiov_offset)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
int ret; int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -1254,7 +1312,7 @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
} }
static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
size_t qiov_offset, int flags) size_t qiov_offset, int flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
@ -1269,13 +1327,15 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int64_t cluster_offset; int64_t cluster_offset;
int64_t cluster_bytes; int64_t cluster_bytes;
size_t skip_bytes; int64_t skip_bytes;
int ret; int ret;
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
BDRV_REQUEST_MAX_BYTES); BDRV_REQUEST_MAX_BYTES);
unsigned int progress = 0; int64_t progress = 0;
bool skip_write; bool skip_write;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -1416,15 +1476,16 @@ err:
* reads; any other features must be implemented by the caller. * reads; any other features must be implemented by the caller.
*/ */
static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes, BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags) int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
int64_t total_bytes, max_bytes; int64_t total_bytes, max_bytes;
int ret = 0; int ret = 0;
uint64_t bytes_remaining = bytes; int64_t bytes_remaining = bytes;
int max_transfer; int max_transfer;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(is_power_of_2(align)); assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0); assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0); assert((bytes & (align - 1)) == 0);
@ -1486,7 +1547,7 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
} }
while (bytes_remaining) { while (bytes_remaining) {
int num; int64_t num;
if (max_bytes) { if (max_bytes) {
num = MIN(bytes_remaining, MIN(max_bytes, max_transfer)); num = MIN(bytes_remaining, MIN(max_bytes, max_transfer));
@ -1548,8 +1609,12 @@ static bool bdrv_init_padding(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int64_t bytes,
BdrvRequestPadding *pad) BdrvRequestPadding *pad)
{ {
uint64_t align = bs->bl.request_alignment; int64_t align = bs->bl.request_alignment;
size_t sum; int64_t sum;
bdrv_check_request(offset, bytes, &error_abort);
assert(align <= INT_MAX); /* documented in block/block_int.h */
assert(align <= SIZE_MAX / 2); /* so we can allocate the buffer */
memset(pad, 0, sizeof(*pad)); memset(pad, 0, sizeof(*pad));
@ -1589,7 +1654,7 @@ static int bdrv_padding_rmw_read(BdrvChild *child,
assert(req->serialising && pad->buf); assert(req->serialising && pad->buf);
if (pad->head || pad->merge_reads) { if (pad->head || pad->merge_reads) {
uint64_t bytes = pad->merge_reads ? pad->buf_len : align; int64_t bytes = pad->merge_reads ? pad->buf_len : align;
qemu_iovec_init_buf(&local_qiov, pad->buf, bytes); qemu_iovec_init_buf(&local_qiov, pad->buf, bytes);
@ -1644,6 +1709,7 @@ static void bdrv_padding_destroy(BdrvRequestPadding *pad)
qemu_vfree(pad->buf); qemu_vfree(pad->buf);
qemu_iovec_destroy(&pad->local_qiov); qemu_iovec_destroy(&pad->local_qiov);
} }
memset(pad, 0, sizeof(*pad));
} }
/* /*
@ -1653,40 +1719,55 @@ static void bdrv_padding_destroy(BdrvRequestPadding *pad)
* read of padding, bdrv_padding_rmw_read() should be called separately if * read of padding, bdrv_padding_rmw_read() should be called separately if
* needed. * needed.
* *
* All parameters except @bs are in-out: they represent original request at * Request parameters (@qiov, &qiov_offset, &offset, &bytes) are in-out:
* function call and padded (if padding needed) at function finish. * - on function start they represent original request
* * - on failure or when padding is not needed they are unchanged
* Function always succeeds. * - on success when padding is needed they represent padded request
*/ */
static bool bdrv_pad_request(BlockDriverState *bs, static int bdrv_pad_request(BlockDriverState *bs,
QEMUIOVector **qiov, size_t *qiov_offset, QEMUIOVector **qiov, size_t *qiov_offset,
int64_t *offset, unsigned int *bytes, int64_t *offset, int64_t *bytes,
BdrvRequestPadding *pad) BdrvRequestPadding *pad, bool *padded)
{ {
int ret;
bdrv_check_qiov_request(*offset, *bytes, *qiov, *qiov_offset, &error_abort);
if (!bdrv_init_padding(bs, *offset, *bytes, pad)) { if (!bdrv_init_padding(bs, *offset, *bytes, pad)) {
return false; if (padded) {
*padded = false;
}
return 0;
} }
qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head, ret = qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head,
*qiov, *qiov_offset, *bytes, *qiov, *qiov_offset, *bytes,
pad->buf + pad->buf_len - pad->tail, pad->tail); pad->buf + pad->buf_len - pad->tail,
pad->tail);
if (ret < 0) {
bdrv_padding_destroy(pad);
return ret;
}
*bytes += pad->head + pad->tail; *bytes += pad->head + pad->tail;
*offset -= pad->head; *offset -= pad->head;
*qiov = &pad->local_qiov; *qiov = &pad->local_qiov;
*qiov_offset = 0; *qiov_offset = 0;
if (padded) {
*padded = true;
}
return true; return 0;
} }
int coroutine_fn bdrv_co_preadv(BdrvChild *child, int coroutine_fn bdrv_co_preadv(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return bdrv_co_preadv_part(child, offset, bytes, qiov, 0, flags); return bdrv_co_preadv_part(child, offset, bytes, qiov, 0, flags);
} }
int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
int64_t offset, unsigned int bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
@ -1695,13 +1776,13 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
BdrvRequestPadding pad; BdrvRequestPadding pad;
int ret; int ret;
trace_bdrv_co_preadv(bs, offset, bytes, flags); trace_bdrv_co_preadv_part(bs, offset, bytes, flags);
if (!bdrv_is_inserted(bs)) { if (!bdrv_is_inserted(bs)) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
ret = bdrv_check_request32(offset, bytes); ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -1725,7 +1806,11 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
flags |= BDRV_REQ_COPY_ON_READ; flags |= BDRV_REQ_COPY_ON_READ;
} }
bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad); ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad,
NULL);
if (ret < 0) {
return ret;
}
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ); tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ);
ret = bdrv_aligned_preadv(child, &req, offset, bytes, ret = bdrv_aligned_preadv(child, &req, offset, bytes,
@ -1740,7 +1825,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
} }
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags) int64_t offset, int64_t bytes, BdrvRequestFlags flags)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
QEMUIOVector qiov; QEMUIOVector qiov;
@ -1755,6 +1840,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
bs->bl.request_alignment); bs->bl.request_alignment);
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER); int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
bdrv_check_request(offset, bytes, &error_abort);
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -1770,7 +1857,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
assert(max_write_zeroes >= bs->bl.request_alignment); assert(max_write_zeroes >= bs->bl.request_alignment);
while (bytes > 0 && !ret) { while (bytes > 0 && !ret) {
int num = bytes; int64_t num = bytes;
/* Align request. Block drivers can expect the "bulk" of the request /* Align request. Block drivers can expect the "bulk" of the request
* to be aligned, and that unaligned requests do not cross cluster * to be aligned, and that unaligned requests do not cross cluster
@ -1851,11 +1938,12 @@ fail:
} }
static inline int coroutine_fn static inline int coroutine_fn
bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes, bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes,
BdrvTrackedRequest *req, int flags) BdrvTrackedRequest *req, int flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
bdrv_check_request(offset, bytes, &error_abort);
if (bs->read_only) { if (bs->read_only) {
return -EPERM; return -EPERM;
@ -1882,7 +1970,8 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
assert(req->overlap_offset <= offset); assert(req->overlap_offset <= offset);
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes); assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE); assert(offset + bytes <= bs->total_sectors * BDRV_SECTOR_SIZE ||
child->perm & BLK_PERM_RESIZE);
switch (req->type) { switch (req->type) {
case BDRV_TRACKED_WRITE: case BDRV_TRACKED_WRITE:
@ -1903,12 +1992,14 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
} }
static inline void coroutine_fn static inline void coroutine_fn
bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes, bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
BdrvTrackedRequest *req, int ret) BdrvTrackedRequest *req, int ret)
{ {
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE); int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
bdrv_check_request(offset, bytes, &error_abort);
qatomic_inc(&bs->write_gen); qatomic_inc(&bs->write_gen);
/* /*
@ -1945,16 +2036,18 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
* after possibly fragmenting it. * after possibly fragmenting it.
*/ */
static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
BdrvTrackedRequest *req, int64_t offset, unsigned int bytes, BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags) int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int ret; int ret;
uint64_t bytes_remaining = bytes; int64_t bytes_remaining = bytes;
int max_transfer; int max_transfer;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -1966,7 +2059,6 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
assert(is_power_of_2(align)); assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0); assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0); assert((bytes & (align - 1)) == 0);
assert(!qiov || qiov_offset + bytes <= qiov->size);
max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX), max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX),
align); align);
@ -2028,7 +2120,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
int64_t offset, int64_t offset,
unsigned int bytes, int64_t bytes,
BdrvRequestFlags flags, BdrvRequestFlags flags,
BdrvTrackedRequest *req) BdrvTrackedRequest *req)
{ {
@ -2065,7 +2157,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
assert(!bytes || (offset & (align - 1)) == 0); assert(!bytes || (offset & (align - 1)) == 0);
if (bytes >= align) { if (bytes >= align) {
/* Write the aligned part in the middle. */ /* Write the aligned part in the middle. */
uint64_t aligned_bytes = bytes & ~(align - 1); int64_t aligned_bytes = bytes & ~(align - 1);
ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align, ret = bdrv_aligned_pwritev(child, req, offset, aligned_bytes, align,
NULL, 0, flags); NULL, 0, flags);
if (ret < 0) { if (ret < 0) {
@ -2095,14 +2187,14 @@ out:
* Handle a write request in coroutine context * Handle a write request in coroutine context
*/ */
int coroutine_fn bdrv_co_pwritev(BdrvChild *child, int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return bdrv_co_pwritev_part(child, offset, bytes, qiov, 0, flags); return bdrv_co_pwritev_part(child, offset, bytes, qiov, 0, flags);
} }
int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, size_t qiov_offset, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
@ -2110,14 +2202,15 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
uint64_t align = bs->bl.request_alignment; uint64_t align = bs->bl.request_alignment;
BdrvRequestPadding pad; BdrvRequestPadding pad;
int ret; int ret;
bool padded = false;
trace_bdrv_co_pwritev(child->bs, offset, bytes, flags); trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags);
if (!bdrv_is_inserted(bs)) { if (!bdrv_is_inserted(bs)) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
ret = bdrv_check_request32(offset, bytes); ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -2141,20 +2234,35 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
return 0; return 0;
} }
if (!(flags & BDRV_REQ_ZERO_WRITE)) {
/*
* Pad request for following read-modify-write cycle.
* bdrv_co_do_zero_pwritev() does aligning by itself, so, we do
* alignment only if there is no ZERO flag.
*/
ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad,
&padded);
if (ret < 0) {
return ret;
}
}
bdrv_inc_in_flight(bs); bdrv_inc_in_flight(bs);
/*
* Align write if necessary by performing a read-modify-write cycle.
* Pad qiov with the read parts and be sure to have a tracked request not
* only for bdrv_aligned_pwritev, but also for the reads of the RMW cycle.
*/
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_WRITE); tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_WRITE);
if (flags & BDRV_REQ_ZERO_WRITE) { if (flags & BDRV_REQ_ZERO_WRITE) {
assert(!padded);
ret = bdrv_co_do_zero_pwritev(child, offset, bytes, flags, &req); ret = bdrv_co_do_zero_pwritev(child, offset, bytes, flags, &req);
goto out; goto out;
} }
if (bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad)) { if (padded) {
/*
* Request was unaligned to request_alignment and therefore
* padded. We are going to do read-modify-write, and must
* serialize the request to prevent interactions of the
* widened region with other transactions.
*/
bdrv_make_request_serialising(&req, align); bdrv_make_request_serialising(&req, align);
bdrv_padding_rmw_read(child, &req, &pad, false); bdrv_padding_rmw_read(child, &req, &pad, false);
} }
@ -2172,7 +2280,7 @@ out:
} }
int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags) int64_t bytes, BdrvRequestFlags flags)
{ {
trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags); trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags);
@ -2847,7 +2955,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
return -EPERM; return -EPERM;
} }
ret = bdrv_check_request(offset, bytes); ret = bdrv_check_request(offset, bytes, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -3093,8 +3201,8 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host)
} }
static int coroutine_fn bdrv_co_copy_range_internal( static int coroutine_fn bdrv_co_copy_range_internal(
BdrvChild *src, uint64_t src_offset, BdrvChild *dst, BdrvChild *src, int64_t src_offset, BdrvChild *dst,
uint64_t dst_offset, uint64_t bytes, int64_t dst_offset, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags, BdrvRequestFlags read_flags, BdrvRequestFlags write_flags,
bool recurse_src) bool recurse_src)
{ {
@ -3108,7 +3216,7 @@ static int coroutine_fn bdrv_co_copy_range_internal(
if (!dst || !dst->bs || !bdrv_is_inserted(dst->bs)) { if (!dst || !dst->bs || !bdrv_is_inserted(dst->bs)) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
ret = bdrv_check_request32(dst_offset, bytes); ret = bdrv_check_request32(dst_offset, bytes, NULL, 0);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -3119,7 +3227,7 @@ static int coroutine_fn bdrv_co_copy_range_internal(
if (!src || !src->bs || !bdrv_is_inserted(src->bs)) { if (!src || !src->bs || !bdrv_is_inserted(src->bs)) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
ret = bdrv_check_request32(src_offset, bytes); ret = bdrv_check_request32(src_offset, bytes, NULL, 0);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -3172,9 +3280,9 @@ static int coroutine_fn bdrv_co_copy_range_internal(
* *
* See the comment of bdrv_co_copy_range for the parameter and return value * See the comment of bdrv_co_copy_range for the parameter and return value
* semantics. */ * semantics. */
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -3188,9 +3296,9 @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
* *
* See the comment of bdrv_co_copy_range for the parameter and return value * See the comment of bdrv_co_copy_range for the parameter and return value
* semantics. */ * semantics. */
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -3200,9 +3308,9 @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
bytes, read_flags, write_flags, false); bytes, read_flags, write_flags, false);
} }
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, BdrvRequestFlags read_flags, int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
return bdrv_co_copy_range_from(src, src_offset, return bdrv_co_copy_range_from(src, src_offset,
@ -3249,10 +3357,8 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
return -EINVAL; return -EINVAL;
} }
ret = bdrv_check_request(offset, 0); ret = bdrv_check_request(offset, 0, errp);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Required too big image size, it must be not greater "
"than %" PRId64, BDRV_MAX_LENGTH);
return ret; return ret;
} }

View file

@ -235,7 +235,14 @@ static void nbd_client_detach_aio_context(BlockDriverState *bs)
/* Timer is deleted in nbd_client_co_drain_begin() */ /* Timer is deleted in nbd_client_co_drain_begin() */
assert(!s->reconnect_delay_timer); assert(!s->reconnect_delay_timer);
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc)); /*
* If reconnect is in progress we may have no ->ioc. It will be
* re-instantiated in the proper aio context once the connection is
* reestablished.
*/
if (s->ioc) {
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
}
} }
static void nbd_client_attach_aio_context_bh(void *opaque) static void nbd_client_attach_aio_context_bh(void *opaque)
@ -243,13 +250,15 @@ static void nbd_client_attach_aio_context_bh(void *opaque)
BlockDriverState *bs = opaque; BlockDriverState *bs = opaque;
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
/* if (s->connection_co) {
* The node is still drained, so we know the coroutine has yielded in /*
* nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is * The node is still drained, so we know the coroutine has yielded in
* entered for the first time. Both places are safe for entering the * nbd_read_eof(), the only place where bs->in_flight can reach 0, or
* coroutine. * it is entered for the first time. Both places are safe for entering
*/ * the coroutine.
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co); */
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co);
}
bdrv_dec_in_flight(bs); bdrv_dec_in_flight(bs);
} }

View file

@ -358,12 +358,15 @@ static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
* @is_write: the type of operation (read/write) * @is_write: the type of operation (read/write)
*/ */
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm, void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
unsigned int bytes, int64_t bytes,
bool is_write) bool is_write)
{ {
bool must_wait; bool must_wait;
ThrottleGroupMember *token; ThrottleGroupMember *token;
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts); ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
assert(bytes >= 0);
qemu_mutex_lock(&tg->lock); qemu_mutex_lock(&tg->lock);
/* First we check if this I/O has to be throttled. */ /* First we check if this I/O has to be throttled. */

View file

@ -11,12 +11,12 @@ blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p" blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
# io.c # io.c
bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x" bdrv_co_preadv_part(void *bs, int64_t offset, int64_t bytes, unsigned int flags) "bs %p offset %" PRId64 " bytes %" PRId64 " flags 0x%x"
bdrv_co_pwritev(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x" bdrv_co_pwritev_part(void *bs, int64_t offset, int64_t bytes, unsigned int flags) "bs %p offset %" PRId64 " bytes %" PRId64 " flags 0x%x"
bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int count, int flags) "bs %p offset %"PRId64" count %d flags 0x%x" bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int64_t bytes, int flags) "bs %p offset %" PRId64 " bytes %" PRId64 " flags 0x%x"
bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t cluster_offset, int64_t cluster_bytes) "bs %p offset %"PRId64" bytes %u cluster_offset %"PRId64" cluster_bytes %"PRId64 bdrv_co_do_copy_on_readv(void *bs, int64_t offset, int64_t bytes, int64_t cluster_offset, int64_t cluster_bytes) "bs %p offset %" PRId64 " bytes %" PRId64 " cluster_offset %" PRId64 " cluster_bytes %" PRId64
bdrv_co_copy_range_from(void *src, uint64_t src_offset, void *dst, uint64_t dst_offset, uint64_t bytes, int read_flags, int write_flags) "src %p offset %"PRIu64" dst %p offset %"PRIu64" bytes %"PRIu64" rw flags 0x%x 0x%x" bdrv_co_copy_range_from(void *src, int64_t src_offset, void *dst, int64_t dst_offset, int64_t bytes, int read_flags, int write_flags) "src %p offset %" PRId64 " dst %p offset %" PRId64 " bytes %" PRId64 " rw flags 0x%x 0x%x"
bdrv_co_copy_range_to(void *src, uint64_t src_offset, void *dst, uint64_t dst_offset, uint64_t bytes, int read_flags, int write_flags) "src %p offset %"PRIu64" dst %p offset %"PRIu64" bytes %"PRIu64" rw flags 0x%x 0x%x" bdrv_co_copy_range_to(void *src, int64_t src_offset, void *dst, int64_t dst_offset, int64_t bytes, int read_flags, int write_flags) "src %p offset %" PRId64 " dst %p offset %" PRId64 " bytes %" PRId64 " rw flags 0x%x 0x%x"
# stream.c # stream.c
stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d" stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d"

View file

@ -392,12 +392,13 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
void bdrv_reopen_commit(BDRVReopenState *reopen_state); void bdrv_reopen_commit(BDRVReopenState *reopen_state);
void bdrv_reopen_abort(BDRVReopenState *reopen_state); void bdrv_reopen_abort(BDRVReopenState *reopen_state);
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags); int64_t bytes, BdrvRequestFlags flags);
int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags); int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags);
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes); int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int64_t bytes);
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes); int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf,
int64_t bytes);
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
const void *buf, int count); const void *buf, int64_t bytes);
/* /*
* Efficiently zero a region of the disk image. Note that this is a regular * Efficiently zero a region of the disk image. Note that this is a regular
* I/O request like read or write and should have a reasonable size. This * I/O request like read or write and should have a reasonable size. This
@ -405,7 +406,7 @@ int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
* because it may allocate memory for the entire region. * because it may allocate memory for the entire region.
*/ */
int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
int bytes, BdrvRequestFlags flags); int64_t bytes, BdrvRequestFlags flags);
BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file); const char *backing_file);
void bdrv_refresh_filename(BlockDriverState *bs); void bdrv_refresh_filename(BlockDriverState *bs);
@ -844,8 +845,8 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host);
* *
* Returns: 0 if succeeded; negative error code if failed. * Returns: 0 if succeeded; negative error code if failed.
**/ **/
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, BdrvRequestFlags read_flags, int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags); BdrvRequestFlags write_flags);
#endif #endif

View file

@ -79,12 +79,12 @@ enum BdrvTrackedRequestType {
typedef struct BdrvTrackedRequest { typedef struct BdrvTrackedRequest {
BlockDriverState *bs; BlockDriverState *bs;
int64_t offset; int64_t offset;
uint64_t bytes; int64_t bytes;
enum BdrvTrackedRequestType type; enum BdrvTrackedRequestType type;
bool serialising; bool serialising;
int64_t overlap_offset; int64_t overlap_offset;
uint64_t overlap_bytes; int64_t overlap_bytes;
QLIST_ENTRY(BdrvTrackedRequest) list; QLIST_ENTRY(BdrvTrackedRequest) list;
Coroutine *co; /* owner, used for deadlock detection */ Coroutine *co; /* owner, used for deadlock detection */
@ -93,7 +93,7 @@ typedef struct BdrvTrackedRequest {
struct BdrvTrackedRequest *waiting_for; struct BdrvTrackedRequest *waiting_for;
} BdrvTrackedRequest; } BdrvTrackedRequest;
int bdrv_check_request(int64_t offset, int64_t bytes); int bdrv_check_request(int64_t offset, int64_t bytes, Error **errp);
struct BlockDriver { struct BlockDriver {
const char *format_name; const char *format_name;
@ -1032,16 +1032,16 @@ extern BlockDriver bdrv_raw;
extern BlockDriver bdrv_qcow2; extern BlockDriver bdrv_qcow2;
int coroutine_fn bdrv_co_preadv(BdrvChild *child, int coroutine_fn bdrv_co_preadv(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags); BdrvRequestFlags flags);
int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
int64_t offset, unsigned int bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
int coroutine_fn bdrv_co_pwritev(BdrvChild *child, int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags); BdrvRequestFlags flags);
int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
int64_t offset, unsigned int bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, static inline int coroutine_fn bdrv_co_pread(BdrvChild *child,
@ -1357,14 +1357,14 @@ void bdrv_dec_in_flight(BlockDriverState *bs);
void blockdev_close_all_bdrv_states(void); void blockdev_close_all_bdrv_states(void);
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags); BdrvRequestFlags write_flags);
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset, int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, uint64_t dst_offset, BdrvChild *dst, int64_t dst_offset,
uint64_t bytes, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags); BdrvRequestFlags write_flags);

View file

@ -364,7 +364,7 @@ static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size,
if (desc) { if (desc) {
error_prepend(errp, "Failed to read %s: ", desc); error_prepend(errp, "Failed to read %s: ", desc);
} }
return -1; return ret;
} }
return 0; return 0;
@ -375,8 +375,9 @@ static inline int nbd_read##bits(QIOChannel *ioc, \
uint##bits##_t *val, \ uint##bits##_t *val, \
const char *desc, Error **errp) \ const char *desc, Error **errp) \
{ \ { \
if (nbd_read(ioc, val, sizeof(*val), desc, errp) < 0) { \ int ret = nbd_read(ioc, val, sizeof(*val), desc, errp); \
return -1; \ if (ret < 0) { \
return ret; \
} \ } \
*val = be##bits##_to_cpu(*val); \ *val = be##bits##_to_cpu(*val); \
return 0; \ return 0; \

View file

@ -77,7 +77,7 @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
void throttle_group_restart_tgm(ThrottleGroupMember *tgm); void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm, void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
unsigned int bytes, int64_t bytes,
bool is_write); bool is_write);
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm, void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
AioContext *new_context); AioContext *new_context);

View file

@ -222,7 +222,7 @@ static inline void *qemu_iovec_buf(QEMUIOVector *qiov)
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
void qemu_iovec_init_extended( int qemu_iovec_init_extended(
QEMUIOVector *qiov, QEMUIOVector *qiov,
void *head_buf, size_t head_len, void *head_buf, size_t head_len,
QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len,

View file

@ -89,7 +89,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off
'format': 'IMGFMT', 'format': 'IMGFMT',
'sync': 'full', 'sync': 'full',
'speed': 65536, 'speed': 65536,
'x-perf': { 'max-chunk': 65536 } } } 'x-perf': {'max-chunk': 65536} } }
Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16 Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}

View file

@ -180,7 +180,7 @@ Job failed: Could not resize image: Image size cannot be negative
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} {"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}}
{"return": {}} {"return": {}}
Job failed: Could not resize image: Required too big image size, it must be not greater than 9223372035781033984 Job failed: Could not resize image: offset(9223372036854775296) exceeds maximum(9223372035781033984)
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}

View file

@ -7,6 +7,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "block/write-threshold.h" #include "block/write-threshold.h"
@ -64,7 +65,7 @@ static void test_threshold_not_trigger(void)
req.offset = 1024; req.offset = 1024;
req.bytes = 1024; req.bytes = 1024;
assert(bdrv_check_request(req.offset, req.bytes) == 0); bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold); bdrv_write_threshold_set(&bs, threshold);
amount = bdrv_write_threshold_exceeded(&bs, &req); amount = bdrv_write_threshold_exceeded(&bs, &req);
@ -84,7 +85,7 @@ static void test_threshold_trigger(void)
req.offset = (4 * 1024 * 1024) - 1024; req.offset = (4 * 1024 * 1024) - 1024;
req.bytes = 2 * 1024; req.bytes = 2 * 1024;
assert(bdrv_check_request(req.offset, req.bytes) == 0); bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold); bdrv_write_threshold_set(&bs, threshold);
amount = bdrv_write_threshold_exceeded(&bs, &req); amount = bdrv_write_threshold_exceeded(&bs, &req);

View file

@ -415,7 +415,7 @@ int qemu_iovec_subvec_niov(QEMUIOVector *qiov, size_t offset, size_t len)
* Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov, * Compile new iovec, combining @head_buf buffer, sub-qiov of @mid_qiov,
* and @tail_buf buffer into new qiov. * and @tail_buf buffer into new qiov.
*/ */
void qemu_iovec_init_extended( int qemu_iovec_init_extended(
QEMUIOVector *qiov, QEMUIOVector *qiov,
void *head_buf, size_t head_len, void *head_buf, size_t head_len,
QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len,
@ -425,12 +425,24 @@ void qemu_iovec_init_extended(
int total_niov, mid_niov = 0; int total_niov, mid_niov = 0;
struct iovec *p, *mid_iov = NULL; struct iovec *p, *mid_iov = NULL;
assert(mid_qiov->niov <= IOV_MAX);
if (SIZE_MAX - head_len < mid_len ||
SIZE_MAX - head_len - mid_len < tail_len)
{
return -EINVAL;
}
if (mid_len) { if (mid_len) {
mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len, mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len,
&mid_head, &mid_tail, &mid_niov); &mid_head, &mid_tail, &mid_niov);
} }
total_niov = !!head_len + mid_niov + !!tail_len; total_niov = !!head_len + mid_niov + !!tail_len;
if (total_niov > IOV_MAX) {
return -EINVAL;
}
if (total_niov == 1) { if (total_niov == 1) {
qemu_iovec_init_buf(qiov, NULL, 0); qemu_iovec_init_buf(qiov, NULL, 0);
p = &qiov->local_iov; p = &qiov->local_iov;
@ -459,6 +471,8 @@ void qemu_iovec_init_extended(
p->iov_base = tail_buf; p->iov_base = tail_buf;
p->iov_len = tail_len; p->iov_len = tail_len;
} }
return 0;
} }
/* /*
@ -492,7 +506,14 @@ bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t offset, size_t bytes)
void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source,
size_t offset, size_t len) size_t offset, size_t len)
{ {
qemu_iovec_init_extended(qiov, NULL, 0, source, offset, len, NULL, 0); int ret;
assert(source->size >= len);
assert(source->size - len >= offset);
/* We shrink the request, so we can't overflow neither size_t nor MAX_IOV */
ret = qemu_iovec_init_extended(qiov, NULL, 0, source, offset, len, NULL, 0);
assert(ret == 0);
} }
void qemu_iovec_destroy(QEMUIOVector *qiov) void qemu_iovec_destroy(QEMUIOVector *qiov)