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;
int flags;
int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *,
int (*request_fn)(BdrvChild *, int64_t, int64_t, QEMUIOVector *,
BdrvRequestFlags);
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;
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);
}

View file

@ -41,7 +41,7 @@
static void bdrv_parent_cb_resize(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,
bool ignore_bds_parents)
@ -717,10 +717,10 @@ static void tracked_request_end(BdrvTrackedRequest *req)
static void tracked_request_begin(BdrvTrackedRequest *req,
BlockDriverState *bs,
int64_t offset,
uint64_t bytes,
int64_t bytes,
enum BdrvTrackedRequestType type)
{
assert(bytes <= INT64_MAX && offset <= INT64_MAX - bytes);
bdrv_check_request(offset, bytes, &error_abort);
*req = (BdrvTrackedRequest){
.bs = bs,
@ -741,8 +741,10 @@ static void tracked_request_begin(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 */
if (offset >= req->overlap_offset + req->overlap_bytes) {
return false;
@ -810,8 +812,10 @@ static void tracked_request_set_serialising(BdrvTrackedRequest *req,
uint64_t align)
{
int64_t overlap_offset = req->offset & ~(align - 1);
uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
- overlap_offset;
int64_t overlap_bytes =
ROUND_UP(req->offset + req->bytes, align) - overlap_offset;
bdrv_check_request(req->offset, req->bytes, &error_abort);
if (!req->serialising) {
qatomic_inc(&req->bs->serialising_in_flight);
@ -920,26 +924,75 @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
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;
}
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;
}
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 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) {
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 bytes, BdrvRequestFlags flags)
int64_t bytes, BdrvRequestFlags flags)
{
return bdrv_pwritev(child, offset, bytes, NULL,
BDRV_REQ_ZERO_WRITE | flags);
@ -1000,7 +1053,7 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
}
/* 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;
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
-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;
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.
*/
int bdrv_pwrite_sync(BdrvChild *child, int64_t offset,
const void *buf, int count)
const void *buf, int64_t count)
{
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,
uint64_t offset, uint64_t bytes,
int64_t offset, int64_t bytes,
QEMUIOVector *qiov,
size_t qiov_offset, int flags)
{
@ -1082,6 +1136,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
QEMUIOVector local_qiov;
int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(!(flags & ~BDRV_REQ_MASK));
assert(!(flags & BDRV_REQ_NO_FALLBACK));
@ -1141,7 +1196,7 @@ out:
}
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
int64_t offset, int64_t bytes,
QEMUIOVector *qiov,
size_t qiov_offset, int flags)
{
@ -1151,6 +1206,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
QEMUIOVector local_qiov;
int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(!(flags & ~BDRV_REQ_MASK));
assert(!(flags & BDRV_REQ_NO_FALLBACK));
@ -1221,14 +1277,16 @@ emulate_flags:
}
static int coroutine_fn
bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov,
bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
size_t qiov_offset)
{
BlockDriver *drv = bs->drv;
QEMUIOVector local_qiov;
int ret;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) {
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,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
size_t qiov_offset, int flags)
{
BlockDriverState *bs = child->bs;
@ -1269,13 +1327,15 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
BlockDriver *drv = bs->drv;
int64_t cluster_offset;
int64_t cluster_bytes;
size_t skip_bytes;
int64_t skip_bytes;
int ret;
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
BDRV_REQUEST_MAX_BYTES);
unsigned int progress = 0;
int64_t progress = 0;
bool skip_write;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) {
return -ENOMEDIUM;
}
@ -1416,15 +1476,16 @@ err:
* reads; any other features must be implemented by the caller.
*/
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)
{
BlockDriverState *bs = child->bs;
int64_t total_bytes, max_bytes;
int ret = 0;
uint64_t bytes_remaining = bytes;
int64_t bytes_remaining = bytes;
int max_transfer;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
assert(is_power_of_2(align));
assert((offset & (align - 1)) == 0);
assert((bytes & (align - 1)) == 0);
@ -1486,7 +1547,7 @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
}
while (bytes_remaining) {
int num;
int64_t num;
if (max_bytes) {
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,
BdrvRequestPadding *pad)
{
uint64_t align = bs->bl.request_alignment;
size_t sum;
int64_t align = bs->bl.request_alignment;
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));
@ -1589,7 +1654,7 @@ static int bdrv_padding_rmw_read(BdrvChild *child,
assert(req->serialising && pad->buf);
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);
@ -1644,6 +1709,7 @@ static void bdrv_padding_destroy(BdrvRequestPadding *pad)
qemu_vfree(pad->buf);
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
* needed.
*
* All parameters except @bs are in-out: they represent original request at
* function call and padded (if padding needed) at function finish.
*
* Function always succeeds.
* Request parameters (@qiov, &qiov_offset, &offset, &bytes) are in-out:
* - on function start they represent original request
* - on failure or when padding is not needed they are unchanged
* - on success when padding is needed they represent padded request
*/
static bool bdrv_pad_request(BlockDriverState *bs,
QEMUIOVector **qiov, size_t *qiov_offset,
int64_t *offset, unsigned int *bytes,
BdrvRequestPadding *pad)
static int bdrv_pad_request(BlockDriverState *bs,
QEMUIOVector **qiov, size_t *qiov_offset,
int64_t *offset, int64_t *bytes,
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)) {
return false;
if (padded) {
*padded = false;
}
return 0;
}
qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head,
*qiov, *qiov_offset, *bytes,
pad->buf + pad->buf_len - pad->tail, pad->tail);
ret = qemu_iovec_init_extended(&pad->local_qiov, pad->buf, pad->head,
*qiov, *qiov_offset, *bytes,
pad->buf + pad->buf_len - pad->tail,
pad->tail);
if (ret < 0) {
bdrv_padding_destroy(pad);
return ret;
}
*bytes += pad->head + pad->tail;
*offset -= pad->head;
*qiov = &pad->local_qiov;
*qiov_offset = 0;
if (padded) {
*padded = true;
}
return true;
return 0;
}
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)
{
return bdrv_co_preadv_part(child, offset, bytes, qiov, 0, flags);
}
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)
{
@ -1695,13 +1776,13 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
BdrvRequestPadding pad;
int ret;
trace_bdrv_co_preadv(bs, offset, bytes, flags);
trace_bdrv_co_preadv_part(bs, offset, bytes, flags);
if (!bdrv_is_inserted(bs)) {
return -ENOMEDIUM;
}
ret = bdrv_check_request32(offset, bytes);
ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
if (ret < 0) {
return ret;
}
@ -1725,7 +1806,11 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
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);
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,
int64_t offset, int bytes, BdrvRequestFlags flags)
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
{
BlockDriver *drv = bs->drv;
QEMUIOVector qiov;
@ -1755,6 +1840,8 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
bs->bl.request_alignment);
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
bdrv_check_request(offset, bytes, &error_abort);
if (!drv) {
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);
while (bytes > 0 && !ret) {
int num = bytes;
int64_t num = bytes;
/* Align request. Block drivers can expect the "bulk" of the request
* to be aligned, and that unaligned requests do not cross cluster
@ -1851,11 +1938,12 @@ fail:
}
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)
{
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) {
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(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) {
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
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)
{
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
BlockDriverState *bs = child->bs;
bdrv_check_request(offset, bytes, &error_abort);
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.
*/
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)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
int ret;
uint64_t bytes_remaining = bytes;
int64_t bytes_remaining = bytes;
int max_transfer;
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
if (!drv) {
return -ENOMEDIUM;
}
@ -1966,7 +2059,6 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
assert(is_power_of_2(align));
assert((offset & (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),
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,
int64_t offset,
unsigned int bytes,
int64_t bytes,
BdrvRequestFlags flags,
BdrvTrackedRequest *req)
{
@ -2065,7 +2157,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
assert(!bytes || (offset & (align - 1)) == 0);
if (bytes >= align) {
/* 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,
NULL, 0, flags);
if (ret < 0) {
@ -2095,14 +2187,14 @@ out:
* Handle a write request in coroutine context
*/
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)
{
return bdrv_co_pwritev_part(child, offset, bytes, qiov, 0, flags);
}
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)
{
BlockDriverState *bs = child->bs;
@ -2110,14 +2202,15 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
uint64_t align = bs->bl.request_alignment;
BdrvRequestPadding pad;
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)) {
return -ENOMEDIUM;
}
ret = bdrv_check_request32(offset, bytes);
ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
if (ret < 0) {
return ret;
}
@ -2141,20 +2234,35 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
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);
/*
* 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);
if (flags & BDRV_REQ_ZERO_WRITE) {
assert(!padded);
ret = bdrv_co_do_zero_pwritev(child, offset, bytes, flags, &req);
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_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 bytes, BdrvRequestFlags flags)
int64_t bytes, BdrvRequestFlags 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;
}
ret = bdrv_check_request(offset, bytes);
ret = bdrv_check_request(offset, bytes, NULL);
if (ret < 0) {
return ret;
}
@ -3093,8 +3201,8 @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host)
}
static int coroutine_fn bdrv_co_copy_range_internal(
BdrvChild *src, uint64_t src_offset, BdrvChild *dst,
uint64_t dst_offset, uint64_t bytes,
BdrvChild *src, int64_t src_offset, BdrvChild *dst,
int64_t dst_offset, int64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags,
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)) {
return -ENOMEDIUM;
}
ret = bdrv_check_request32(dst_offset, bytes);
ret = bdrv_check_request32(dst_offset, bytes, NULL, 0);
if (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)) {
return -ENOMEDIUM;
}
ret = bdrv_check_request32(src_offset, bytes);
ret = bdrv_check_request32(src_offset, bytes, NULL, 0);
if (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
* semantics. */
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes,
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes,
BdrvRequestFlags read_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
* semantics. */
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes,
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes,
BdrvRequestFlags read_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);
}
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes, BdrvRequestFlags read_flags,
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags)
{
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;
}
ret = bdrv_check_request(offset, 0);
ret = bdrv_check_request(offset, 0, errp);
if (ret < 0) {
error_setg(errp, "Required too big image size, it must be not greater "
"than %" PRId64, BDRV_MAX_LENGTH);
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() */
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)
@ -243,13 +250,15 @@ static void nbd_client_attach_aio_context_bh(void *opaque)
BlockDriverState *bs = opaque;
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
/*
* 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
* entered for the first time. Both places are safe for entering the
* coroutine.
*/
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co);
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 entered for the first time. Both places are safe for entering
* the coroutine.
*/
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co);
}
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)
*/
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
unsigned int bytes,
int64_t bytes,
bool is_write)
{
bool must_wait;
ThrottleGroupMember *token;
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
assert(bytes >= 0);
qemu_mutex_lock(&tg->lock);
/* 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"
# 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_pwritev(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"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_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_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_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_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_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, 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, 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, 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, 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_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_abort(BDRVReopenState *reopen_state);
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_pread(BdrvChild *child, int64_t offset, void *buf, int bytes);
int bdrv_pwrite(BdrvChild *child, int64_t offset, const 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,
int64_t bytes);
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
* 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.
*/
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,
const char *backing_file);
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.
**/
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes, BdrvRequestFlags read_flags,
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);
#endif

View file

@ -79,12 +79,12 @@ enum BdrvTrackedRequestType {
typedef struct BdrvTrackedRequest {
BlockDriverState *bs;
int64_t offset;
uint64_t bytes;
int64_t bytes;
enum BdrvTrackedRequestType type;
bool serialising;
int64_t overlap_offset;
uint64_t overlap_bytes;
int64_t overlap_bytes;
QLIST_ENTRY(BdrvTrackedRequest) list;
Coroutine *co; /* owner, used for deadlock detection */
@ -93,7 +93,7 @@ typedef struct BdrvTrackedRequest {
struct BdrvTrackedRequest *waiting_for;
} 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 {
const char *format_name;
@ -1032,16 +1032,16 @@ extern BlockDriver bdrv_raw;
extern BlockDriver bdrv_qcow2;
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);
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);
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);
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);
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);
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes,
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes,
BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, uint64_t dst_offset,
uint64_t bytes,
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
BdrvChild *dst, int64_t dst_offset,
int64_t bytes,
BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags);

View file

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

View file

@ -77,7 +77,7 @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
unsigned int bytes,
int64_t bytes,
bool is_write);
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
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_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
void qemu_iovec_init_extended(
int qemu_iovec_init_extended(
QEMUIOVector *qiov,
void *head_buf, size_t head_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',
'sync': 'full',
'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
{"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"}}

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}}}
{"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"}}
{"return": {}}

View file

@ -7,6 +7,7 @@
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "block/block_int.h"
#include "block/write-threshold.h"
@ -64,7 +65,7 @@ static void test_threshold_not_trigger(void)
req.offset = 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);
amount = bdrv_write_threshold_exceeded(&bs, &req);
@ -84,7 +85,7 @@ static void test_threshold_trigger(void)
req.offset = (4 * 1024 * 1024) - 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);
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,
* and @tail_buf buffer into new qiov.
*/
void qemu_iovec_init_extended(
int qemu_iovec_init_extended(
QEMUIOVector *qiov,
void *head_buf, size_t head_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;
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) {
mid_iov = qiov_slice(mid_qiov, mid_offset, mid_len,
&mid_head, &mid_tail, &mid_niov);
}
total_niov = !!head_len + mid_niov + !!tail_len;
if (total_niov > IOV_MAX) {
return -EINVAL;
}
if (total_niov == 1) {
qemu_iovec_init_buf(qiov, NULL, 0);
p = &qiov->local_iov;
@ -459,6 +471,8 @@ void qemu_iovec_init_extended(
p->iov_base = tail_buf;
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,
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)