Block layer patches:

- Fix resize (extending) of short overlays
 - nvme: introduce PMR support from NVMe 1.4 spec
 - qemu-storage-daemon: Fix non-string --object properties
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAl6q9BERHGt3b2xmQHJl
 ZGhhdC5jb20ACgkQfwmycsiPL9bgag//WlwtXgTRj2N/Gijav7d9ihoaUXs4Kza1
 UpP6MA4WHCPCNJlhkGyYFO4PeQP+BFoGt9+TxGfwVIP8Sv2FYXFY/ZdgrdCw5oHV
 6Zh7xpEcOvDnR5psEvaKHBwIjEWqHMOowm0rgpzf0AmJo8C419oO6Met7zkwKUgL
 gVNtB8RkKWXEoht+JrkhRd15gSAC5bFH1Ragh2ywYhwZuMk4lSZVASk1q/Zd2lX/
 e5a8uFEwC8rNbHJxtUMPZfgCjN0H/t3h1rovxpSp9Z9YL0SQ67qZcDQy9sbOXokN
 2UwIZZsFAZPeDsBoWn+Vy0GtNsYphcG6UOn4UG6404hxMzINZB3p4f6dRDJmssvT
 whTbtfczs5rXyeoQSUHpg6RyVo8sgNWxqfNjiXvSuWy5PtW/qVYPBeO7Bexb/rxl
 +yi0oU72o5AaYhS8FV2Uj1dEMLJSJkdF7558q+eKTL5sUnBOSC4xi2UMKBwhZ46q
 IdRwOrqGI0S23BQkymQR4hXrTsrPrYZAZJHAfzqckq1qqZHg85+RP/wo/Nq1ZykC
 xTJgzzIwBOAQUoqIgARtJY5rE6tmcww/T6nuVIIFglew80nzdf3Ga4kVYWHZk9Dz
 syCTQib7R3bxz0NSZrCkeynkzNrvAt+iGQrYs+RsHDWjSEzIzlYrqVuYxWLuEBSk
 CNbdkLcHi/w=
 =ad71
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches:

- Fix resize (extending) of short overlays
- nvme: introduce PMR support from NVMe 1.4 spec
- qemu-storage-daemon: Fix non-string --object properties

# gpg: Signature made Thu 30 Apr 2020 16:51:45 BST
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  qemu-storage-daemon: Fix non-string --object properties
  qom: Factor out user_creatable_add_dict()
  nvme: introduce PMR support from NVMe 1.4 spec
  qcow2: Forward ZERO_WRITE flag for full preallocation
  iotests: Test committing to short backing file
  iotests: Filter testfiles out in filter_img_info()
  block: truncate: Don't make backing file data visible
  file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
  raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
  qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
  block-backend: Add flags to blk_truncate()
  block: Add flags to bdrv(_co)_truncate()
  block: Add flags to BlockDriver.bdrv_co_truncate()
  qemu-iotests: allow qcow2 external discarded clusters to contain stale data
  qcow2: Add incompatibility note between backing files and raw external data files

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-04-30 19:25:41 +01:00
commit 1c47613588
49 changed files with 951 additions and 96 deletions

View File

@ -548,7 +548,8 @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
int64_t size; int64_t size;
int ret; int ret;
ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err); ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
&local_err);
if (ret < 0 && ret != -ENOTSUP) { if (ret < 0 && ret != -ENOTSUP) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return ret; return ret;

View File

@ -2137,14 +2137,14 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
} }
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{ {
if (!blk_is_available(blk)) { if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted"); error_setg(errp, "No medium inserted");
return -ENOMEDIUM; return -ENOMEDIUM;
} }
return bdrv_truncate(blk->root, offset, exact, prealloc, errp); return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
} }
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,

View File

@ -133,7 +133,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
} }
if (base_len < len) { if (base_len < len) {
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL); ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
if (ret) { if (ret) {
goto out; goto out;
} }
@ -458,7 +458,7 @@ int bdrv_commit(BlockDriverState *bs)
* grow the backing file image if possible. If not possible, * grow the backing file image if possible. If not possible,
* we must return an error */ * we must return an error */
if (length > backing_length) { if (length > backing_length) {
ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
&local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);

View File

@ -115,7 +115,7 @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
* which will be used by the crypto header * which will be used by the crypto header
*/ */
return blk_truncate(data->blk, data->size + headerlen, false, return blk_truncate(data->blk, data->size + headerlen, false,
data->prealloc, errp); data->prealloc, 0, errp);
} }
@ -299,7 +299,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
static int coroutine_fn static int coroutine_fn
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{ {
BlockCrypto *crypto = bs->opaque; BlockCrypto *crypto = bs->opaque;
uint64_t payload_offset = uint64_t payload_offset =
@ -312,7 +313,7 @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
offset += payload_offset; offset += payload_offset;
return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
} }
static void block_crypto_close(BlockDriverState *bs) static void block_crypto_close(BlockDriverState *bs)

View File

@ -702,6 +702,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
#endif #endif
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
if (S_ISREG(st.st_mode)) {
/* When extending regular files, we get zeros from the OS */
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
}
ret = 0; ret = 0;
fail: fail:
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
@ -2080,7 +2084,7 @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
struct stat st; struct stat st;

View File

@ -469,7 +469,7 @@ static void raw_close(BlockDriverState *bs)
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
LONG low, high; LONG low, high;

View File

@ -1228,6 +1228,7 @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
int64_t offset, int64_t offset,
bool exact, bool exact,
PreallocMode prealloc, PreallocMode prealloc,
BdrvRequestFlags flags,
Error **errp) Error **errp)
{ {
BDRVGlusterState *s = bs->opaque; BDRVGlusterState *s = bs->opaque;

View File

@ -3339,7 +3339,8 @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
* 'offset' bytes in length. * 'offset' bytes in length.
*/ */
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
@ -3393,10 +3394,40 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
goto out; goto out;
} }
/*
* If the image has a backing file that is large enough that it would
* provide data for the new area, we cannot leave it unallocated because
* then the backing file content would become visible. Instead, zero-fill
* the new area.
*
* Note that if the image has a backing file, but was opened without the
* backing file, taking care of keeping things consistent with that backing
* file is the user's responsibility.
*/
if (new_bytes && bs->backing) {
int64_t backing_len;
backing_len = bdrv_getlength(backing_bs(bs));
if (backing_len < 0) {
ret = backing_len;
error_setg_errno(errp, -ret, "Could not get backing file size");
goto out;
}
if (backing_len > old_size) {
flags |= BDRV_REQ_ZERO_WRITE;
}
}
if (drv->bdrv_co_truncate) { if (drv->bdrv_co_truncate) {
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp); if (flags & ~bs->supported_truncate_flags) {
error_setg(errp, "Block driver does not support requested flags");
ret = -ENOTSUP;
goto out;
}
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
} else if (bs->file && drv->is_filter) { } else if (bs->file && drv->is_filter) {
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
} else { } else {
error_setg(errp, "Image format driver does not support resize"); error_setg(errp, "Image format driver does not support resize");
ret = -ENOTSUP; ret = -ENOTSUP;
@ -3429,6 +3460,7 @@ typedef struct TruncateCo {
int64_t offset; int64_t offset;
bool exact; bool exact;
PreallocMode prealloc; PreallocMode prealloc;
BdrvRequestFlags flags;
Error **errp; Error **errp;
int ret; int ret;
} TruncateCo; } TruncateCo;
@ -3437,12 +3469,12 @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
{ {
TruncateCo *tco = opaque; TruncateCo *tco = opaque;
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact, tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
tco->prealloc, tco->errp); tco->prealloc, tco->flags, tco->errp);
aio_wait_kick(); aio_wait_kick();
} }
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
{ {
Coroutine *co; Coroutine *co;
TruncateCo tco = { TruncateCo tco = {
@ -3450,6 +3482,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
.offset = offset, .offset = offset,
.exact = exact, .exact = exact,
.prealloc = prealloc, .prealloc = prealloc,
.flags = flags,
.errp = errp, .errp = errp,
.ret = NOT_DONE, .ret = NOT_DONE,
}; };

View File

@ -2124,7 +2124,7 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
int64_t cur_length; int64_t cur_length;

View File

@ -900,7 +900,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
if (s->bdev_length > base_length) { if (s->bdev_length > base_length) {
ret = blk_truncate(s->target, s->bdev_length, false, ret = blk_truncate(s->target, s->bdev_length, false,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
goto immediate_exit; goto immediate_exit;
} }

View File

@ -755,7 +755,8 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
static int coroutine_fn static int coroutine_fn
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{ {
NFSClient *client = bs->opaque; NFSClient *client = bs->opaque;
int ret; int ret;

View File

@ -203,7 +203,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
} else { } else {
ret = bdrv_truncate(bs->file, ret = bdrv_truncate(bs->file,
(s->data_end + space) << BDRV_SECTOR_BITS, (s->data_end + space) << BDRV_SECTOR_BITS,
false, PREALLOC_MODE_OFF, NULL); false, PREALLOC_MODE_OFF, 0, NULL);
} }
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -493,7 +493,7 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
* That means we have to pass exact=true. * That means we have to pass exact=true.
*/ */
ret = bdrv_truncate(bs->file, res->image_end_offset, true, ret = bdrv_truncate(bs->file, res->image_end_offset, true,
PREALLOC_MODE_OFF, &local_err); PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
res->check_errors++; res->check_errors++;
@ -889,7 +889,7 @@ static void parallels_close(BlockDriverState *bs)
/* errors are ignored, so we might as well pass exact=true */ /* errors are ignored, so we might as well pass exact=true */
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true, bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
} }
g_free(s->bat_dirty_bmap); g_free(s->bat_dirty_bmap);

View File

@ -480,7 +480,7 @@ static int get_cluster_offset(BlockDriverState *bs,
return -E2BIG; return -E2BIG;
} }
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size, ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
false, PREALLOC_MODE_OFF, NULL); false, PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -1035,7 +1035,7 @@ static int qcow_make_empty(BlockDriverState *bs)
l1_length) < 0) l1_length) < 0)
return -1; return -1;
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false, ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -1795,7 +1795,7 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
/* Caller must pass aligned values, except at image end */ /* Caller must pass aligned values, except at image end */
assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
end_offset == bs->total_sectors << BDRV_SECTOR_BITS); end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
/* The zero flag is only supported by version 3 and newer */ /* The zero flag is only supported by version 3 and newer */
if (s->qcow_version < 3) { if (s->qcow_version < 3) {

View File

@ -2018,7 +2018,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
} }
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false, ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
PREALLOC_MODE_OFF, &local_err); PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
goto resize_fail; goto resize_fail;

View File

@ -1726,6 +1726,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
bs->supported_zero_flags = header.version >= 3 ? bs->supported_zero_flags = header.version >= 3 ?
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0; BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
/* Repair image if dirty */ /* Repair image if dirty */
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only && if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
@ -3095,7 +3096,7 @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
mode = PREALLOC_MODE_OFF; mode = PREALLOC_MODE_OFF;
} }
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false, ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
mode, errp); mode, 0, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -3511,7 +3512,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
/* Okay, now that we have a valid image, let's give it the right size */ /* Okay, now that we have a valid image, let's give it the right size */
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation, ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
errp); 0, errp);
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Could not resize image: "); error_prepend(errp, "Could not resize image: ");
goto out; goto out;
@ -3964,7 +3965,7 @@ fail:
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t old_length; uint64_t old_length;
@ -4061,7 +4062,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
* always fulfilled, so there is no need to pass it on.) * always fulfilled, so there is no need to pass it on.)
*/ */
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size, bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
false, PREALLOC_MODE_OFF, &local_err); false, PREALLOC_MODE_OFF, 0, &local_err);
if (local_err) { if (local_err) {
warn_reportf_err(local_err, warn_reportf_err(local_err,
"Failed to truncate the tail of the image: "); "Failed to truncate the tail of the image: ");
@ -4083,7 +4084,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
* file should be resized to the exact target size, too, * file should be resized to the exact target size, too,
* so we pass @exact here. * so we pass @exact here.
*/ */
ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp); ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@ -4168,8 +4170,25 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
/* Allocate the data area */ /* Allocate the data area */
new_file_size = allocation_start + new_file_size = allocation_start +
nb_new_data_clusters * s->cluster_size; nb_new_data_clusters * s->cluster_size;
/* Image file grows, so @exact does not matter */ /*
ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp); * Image file grows, so @exact does not matter.
*
* If we need to zero out the new area, try first whether the protocol
* driver can already take care of this.
*/
if (flags & BDRV_REQ_ZERO_WRITE) {
ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
BDRV_REQ_ZERO_WRITE, NULL);
if (ret >= 0) {
flags &= ~BDRV_REQ_ZERO_WRITE;
}
} else {
ret = -1;
}
if (ret < 0) {
ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
errp);
}
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Failed to resize underlying file: "); error_prepend(errp, "Failed to resize underlying file: ");
qcow2_free_clusters(bs, allocation_start, qcow2_free_clusters(bs, allocation_start,
@ -4212,6 +4231,39 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
g_assert_not_reached(); g_assert_not_reached();
} }
if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
/*
* Use zero clusters as much as we can. qcow2_cluster_zeroize()
* requires a cluster-aligned start. The end may be unaligned if it is
* at the end of the image (which it is here).
*/
ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to zero out new clusters");
goto fail;
}
/* Write explicit zeros for the unaligned head */
if (zero_start > old_length) {
uint64_t len = zero_start - old_length;
uint8_t *buf = qemu_blockalign0(bs, len);
QEMUIOVector qiov;
qemu_iovec_init_buf(&qiov, buf, len);
qemu_co_mutex_unlock(&s->lock);
ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
qemu_co_mutex_lock(&s->lock);
qemu_vfree(buf);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to zero out the new area");
goto fail;
}
}
}
if (prealloc != PREALLOC_MODE_OFF) { if (prealloc != PREALLOC_MODE_OFF) {
/* Flush metadata before actually changing the image size */ /* Flush metadata before actually changing the image size */
ret = qcow2_write_caches(bs); ret = qcow2_write_caches(bs);
@ -4348,7 +4400,8 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
if (len < 0) { if (len < 0) {
return len; return len;
} }
return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL); return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
NULL);
} }
if (offset_into_cluster(s, offset)) { if (offset_into_cluster(s, offset)) {
@ -4563,7 +4616,7 @@ static int make_completely_empty(BlockDriverState *bs)
} }
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false, ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
PREALLOC_MODE_OFF, &local_err); PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
goto fail; goto fail;
@ -5371,7 +5424,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
* Amending image options should ensure that the image has * Amending image options should ensure that the image has
* exactly the given new values, so pass exact=true here. * exactly the given new values, so pass exact=true here.
*/ */
ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
blk_unref(blk); blk_unref(blk);
if (ret < 0) { if (ret < 0) {
return ret; return ret;

View File

@ -677,7 +677,7 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
* The QED format associates file length with allocation status, * The QED format associates file length with allocation status,
* so a new file (which is empty) must have a length of 0. * so a new file (which is empty) must have a length of 0.
*/ */
ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@ -1467,6 +1467,7 @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
int64_t offset, int64_t offset,
bool exact, bool exact,
PreallocMode prealloc, PreallocMode prealloc,
BdrvRequestFlags flags,
Error **errp) Error **errp)
{ {
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;

View File

@ -371,7 +371,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -387,7 +387,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
s->size = offset; s->size = offset;
offset += s->offset; offset += s->offset;
return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp); return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
} }
static void raw_eject(BlockDriverState *bs, bool eject_flag) static void raw_eject(BlockDriverState *bs, bool eject_flag)
@ -445,6 +445,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
bs->file->bs->supported_zero_flags); bs->file->bs->supported_zero_flags);
bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
BDRV_REQ_ZERO_WRITE;
if (bs->probed && !bdrv_is_read_only(bs)) { if (bs->probed && !bdrv_is_read_only(bs)) {
bdrv_refresh_filename(bs->file->bs); bdrv_refresh_filename(bs->file->bs);

View File

@ -1108,6 +1108,7 @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
int64_t offset, int64_t offset,
bool exact, bool exact,
PreallocMode prealloc, PreallocMode prealloc,
BdrvRequestFlags flags,
Error **errp) Error **errp)
{ {
int r; int r;

View File

@ -2281,7 +2281,7 @@ static int64_t sd_getlength(BlockDriverState *bs)
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVSheepdogState *s = bs->opaque; BDRVSheepdogState *s = bs->opaque;
int ret, fd; int ret, fd;
@ -2597,7 +2597,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
assert(!flags); assert(!flags);
if (offset > s->inode.vdi_size) { if (offset > s->inode.vdi_size) {
ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL); ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -1298,7 +1298,7 @@ static int64_t ssh_getlength(BlockDriverState *bs)
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp) BdrvRequestFlags flags, Error **errp)
{ {
BDRVSSHState *s = bs->opaque; BDRVSSHState *s = bs->opaque;

View File

@ -875,7 +875,7 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
if (image_type == VDI_TYPE_STATIC) { if (image_type == VDI_TYPE_STATIC) {
ret = blk_truncate(blk, offset + blocks * block_size, false, ret = blk_truncate(blk, offset + blocks * block_size, false,
PREALLOC_MODE_OFF, errp); PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Failed to statically allocate file"); error_prepend(errp, "Failed to statically allocate file");
goto exit; goto exit;

View File

@ -558,7 +558,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
goto exit; goto exit;
} }
ret = bdrv_truncate(bs->file, new_file_size, false, ret = bdrv_truncate(bs->file, new_file_size, false,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }

View File

@ -1264,7 +1264,7 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
} }
return bdrv_truncate(bs->file, *new_offset + s->block_size, false, return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
} }
/* /*
@ -1703,13 +1703,13 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
/* All zeroes, so we can just extend the file - the end of the BAT /* All zeroes, so we can just extend the file - the end of the BAT
* is the furthest thing we have written yet */ * is the furthest thing we have written yet */
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF, ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
errp); 0, errp);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
} else if (type == VHDX_TYPE_FIXED) { } else if (type == VHDX_TYPE_FIXED) {
ret = blk_truncate(blk, data_file_offset + image_size, false, ret = blk_truncate(blk, data_file_offset + image_size, false,
PREALLOC_MODE_OFF, errp); PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }

View File

@ -2077,7 +2077,7 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
} }
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
ret = bdrv_truncate(s->extents[i].file, length, false, ret = bdrv_truncate(s->extents[i].file, length, false,
PREALLOC_MODE_OFF, NULL); PREALLOC_MODE_OFF, 0, NULL);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -2118,7 +2118,7 @@ static int vmdk_init_extent(BlockBackend *blk,
int gd_buf_size; int gd_buf_size;
if (flat) { if (flat) {
ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
goto exit; goto exit;
} }
magic = cpu_to_be32(VMDK4_MAGIC); magic = cpu_to_be32(VMDK4_MAGIC);
@ -2182,7 +2182,7 @@ static int vmdk_init_extent(BlockBackend *blk,
} }
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false, ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
PREALLOC_MODE_OFF, errp); PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }
@ -2523,7 +2523,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
/* bdrv_pwrite write padding zeros to align to sector, we don't need that /* bdrv_pwrite write padding zeros to align to sector, we don't need that
* for description file */ * for description file */
if (desc_offset == 0) { if (desc_offset == 0) {
ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
goto exit; goto exit;
} }

View File

@ -898,7 +898,7 @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
/* Add footer to total size */ /* Add footer to total size */
total_size += HEADER_SIZE; total_size += HEADER_SIZE;
ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -2741,7 +2741,7 @@ void qmp_block_resize(bool has_device, const char *device,
} }
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp); ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
bdrv_drained_end(bs); bdrv_drained_end(bs);
out: out:

View File

@ -25,6 +25,9 @@ The first cluster of a qcow2 image contains the file header:
is stored (NB: The string is not null terminated). 0 if the is stored (NB: The string is not null terminated). 0 if the
image doesn't have a backing file. image doesn't have a backing file.
Note: backing files are incompatible with raw external data
files (auto-clear feature bit 1).
16 - 19: backing_file_size 16 - 19: backing_file_size
Length of the backing file name in bytes. Must not be Length of the backing file name in bytes. Must not be
longer than 1023 bytes. Undefined if the image doesn't have longer than 1023 bytes. Undefined if the image doesn't have

View File

@ -7,12 +7,12 @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
common-obj-$(CONFIG_XEN) += xen-block.o common-obj-$(CONFIG_XEN) += xen-block.o
common-obj-$(CONFIG_ECC) += ecc.o common-obj-$(CONFIG_ECC) += ecc.o
common-obj-$(CONFIG_ONENAND) += onenand.o common-obj-$(CONFIG_ONENAND) += onenand.o
common-obj-$(CONFIG_NVME_PCI) += nvme.o
common-obj-$(CONFIG_SWIM) += swim.o common-obj-$(CONFIG_SWIM) += swim.o
common-obj-$(CONFIG_SH4) += tc58128.o common-obj-$(CONFIG_SH4) += tc58128.o
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
obj-$(CONFIG_NVME_PCI) += nvme.o
obj-y += dataplane/ obj-y += dataplane/

View File

@ -19,10 +19,19 @@
* -drive file=<file>,if=none,id=<drive_id> * -drive file=<file>,if=none,id=<drive_id>
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \ * -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
* cmb_size_mb=<cmb_size_mb[optional]>, \ * cmb_size_mb=<cmb_size_mb[optional]>, \
* [pmrdev=<mem_backend_file_id>,] \
* num_queues=<N[optional]> * num_queues=<N[optional]>
* *
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at * Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now. * offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
*
* cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
* in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
* both provided.
* Enabling pmr emulation can be achieved by pointing to memory-backend-file.
* For example:
* -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
* size=<size> .... -device nvme,...,pmrdev=<mem_id>
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
@ -35,7 +44,9 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "sysemu/hostmem.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "exec/ram_addr.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
@ -1141,6 +1152,26 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
"invalid write to read only CMBSZ, ignored"); "invalid write to read only CMBSZ, ignored");
return; return;
case 0xE00: /* PMRCAP */
NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
"invalid write to PMRCAP register, ignored");
return;
case 0xE04: /* TODO PMRCTL */
break;
case 0xE08: /* PMRSTS */
NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
"invalid write to PMRSTS register, ignored");
return;
case 0xE0C: /* PMREBS */
NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
"invalid write to PMREBS register, ignored");
return;
case 0xE10: /* PMRSWTP */
NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
"invalid write to PMRSWTP register, ignored");
return;
case 0xE14: /* TODO PMRMSC */
break;
default: default:
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
"invalid MMIO write," "invalid MMIO write,"
@ -1169,6 +1200,16 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
} }
if (addr < sizeof(n->bar)) { if (addr < sizeof(n->bar)) {
/*
* When PMRWBM bit 1 is set then read from
* from PMRSTS should ensure prior writes
* made it to persistent media
*/
if (addr == 0xE08 &&
(NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
qemu_ram_writeback(n->pmrdev->mr.ram_block,
0, n->pmrdev->size);
}
memcpy(&val, ptr + addr, size); memcpy(&val, ptr + addr, size);
} else { } else {
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
@ -1332,6 +1373,23 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
error_setg(errp, "serial property not set"); error_setg(errp, "serial property not set");
return; return;
} }
if (!n->cmb_size_mb && n->pmrdev) {
if (host_memory_backend_is_mapped(n->pmrdev)) {
char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
error_setg(errp, "can't use already busy memdev: %s", path);
g_free(path);
return;
}
if (!is_power_of_2(n->pmrdev->size)) {
error_setg(errp, "pmr backend size needs to be power of 2 in size");
return;
}
host_memory_backend_set_mapped(n->pmrdev, true);
}
blkconf_blocksizes(&n->conf); blkconf_blocksizes(&n->conf);
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
false, errp)) { false, errp)) {
@ -1415,6 +1473,51 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem); PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
} else if (n->pmrdev) {
/* Controller Capabilities register */
NVME_CAP_SET_PMRS(n->bar.cap, 1);
/* PMR Capabities register */
n->bar.pmrcap = 0;
NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
/* Turn on bit 1 support */
NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
/* PMR Control register */
n->bar.pmrctl = 0;
NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
/* PMR Status register */
n->bar.pmrsts = 0;
NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
/* PMR Elasticity Buffer Size register */
n->bar.pmrebs = 0;
NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
/* PMR Sustained Write Throughput register */
n->bar.pmrswtp = 0;
NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
/* PMR Memory Space Control register */
n->bar.pmrmsc = 0;
NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
} }
for (i = 0; i < n->num_namespaces; i++) { for (i = 0; i < n->num_namespaces; i++) {
@ -1445,11 +1548,17 @@ static void nvme_exit(PCIDevice *pci_dev)
if (n->cmb_size_mb) { if (n->cmb_size_mb) {
g_free(n->cmbuf); g_free(n->cmbuf);
} }
if (n->pmrdev) {
host_memory_backend_set_mapped(n->pmrdev, false);
}
msix_uninit_exclusive_bar(pci_dev); msix_uninit_exclusive_bar(pci_dev);
} }
static Property nvme_props[] = { static Property nvme_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf), DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
DEFINE_PROP_STRING("serial", NvmeCtrl, serial), DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0), DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64), DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),

View File

@ -83,6 +83,8 @@ typedef struct NvmeCtrl {
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
char *serial; char *serial;
HostMemoryBackend *pmrdev;
NvmeNamespace *namespaces; NvmeNamespace *namespaces;
NvmeSQueue **sq; NvmeSQueue **sq;
NvmeCQueue **cq; NvmeCQueue **cq;

View File

@ -110,6 +110,10 @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""

View File

@ -339,9 +339,10 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
void bdrv_refresh_filename(BlockDriverState *bs); void bdrv_refresh_filename(BlockDriverState *bs);
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp); PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp);
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact, int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp); PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
int64_t bdrv_nb_sectors(BlockDriverState *bs); int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs); int64_t bdrv_getlength(BlockDriverState *bs);

View File

@ -355,7 +355,7 @@ struct BlockDriver {
*/ */
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
bool exact, PreallocMode prealloc, bool exact, PreallocMode prealloc,
Error **errp); BdrvRequestFlags flags, Error **errp);
int64_t (*bdrv_getlength)(BlockDriverState *bs); int64_t (*bdrv_getlength)(BlockDriverState *bs);
bool has_variable_length; bool has_variable_length;
@ -847,6 +847,14 @@ struct BlockDriverState {
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA, /* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */ * BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
unsigned int supported_zero_flags; unsigned int supported_zero_flags;
/*
* Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
*
* If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
* that any added space reads as all zeros. If this can't be guaranteed,
* the operation must fail.
*/
unsigned int supported_truncate_flags;
/* the following member gives a name to every node on the bs graph. */ /* the following member gives a name to every node on the bs graph. */
char node_name[32]; char node_name[32];

View File

@ -15,6 +15,13 @@ typedef struct NvmeBar {
uint64_t acq; uint64_t acq;
uint32_t cmbloc; uint32_t cmbloc;
uint32_t cmbsz; uint32_t cmbsz;
uint8_t padding[3520]; /* not used by QEMU */
uint32_t pmrcap;
uint32_t pmrctl;
uint32_t pmrsts;
uint32_t pmrebs;
uint32_t pmrswtp;
uint32_t pmrmsc;
} NvmeBar; } NvmeBar;
enum NvmeCapShift { enum NvmeCapShift {
@ -27,6 +34,7 @@ enum NvmeCapShift {
CAP_CSS_SHIFT = 37, CAP_CSS_SHIFT = 37,
CAP_MPSMIN_SHIFT = 48, CAP_MPSMIN_SHIFT = 48,
CAP_MPSMAX_SHIFT = 52, CAP_MPSMAX_SHIFT = 52,
CAP_PMR_SHIFT = 56,
}; };
enum NvmeCapMask { enum NvmeCapMask {
@ -39,6 +47,7 @@ enum NvmeCapMask {
CAP_CSS_MASK = 0xff, CAP_CSS_MASK = 0xff,
CAP_MPSMIN_MASK = 0xf, CAP_MPSMIN_MASK = 0xf,
CAP_MPSMAX_MASK = 0xf, CAP_MPSMAX_MASK = 0xf,
CAP_PMR_MASK = 0x1,
}; };
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK) #define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
@ -69,6 +78,8 @@ enum NvmeCapMask {
<< CAP_MPSMIN_SHIFT) << CAP_MPSMIN_SHIFT)
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\ #define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
<< CAP_MPSMAX_SHIFT) << CAP_MPSMAX_SHIFT)
#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
<< CAP_PMR_SHIFT)
enum NvmeCcShift { enum NvmeCcShift {
CC_EN_SHIFT = 0, CC_EN_SHIFT = 0,
@ -205,6 +216,167 @@ enum NvmeCmbszMask {
#define NVME_CMBSZ_GETSIZE(cmbsz) \ #define NVME_CMBSZ_GETSIZE(cmbsz) \
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz)))) (NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
enum NvmePmrcapShift {
PMRCAP_RDS_SHIFT = 3,
PMRCAP_WDS_SHIFT = 4,
PMRCAP_BIR_SHIFT = 5,
PMRCAP_PMRTU_SHIFT = 8,
PMRCAP_PMRWBM_SHIFT = 10,
PMRCAP_PMRTO_SHIFT = 16,
PMRCAP_CMSS_SHIFT = 24,
};
enum NvmePmrcapMask {
PMRCAP_RDS_MASK = 0x1,
PMRCAP_WDS_MASK = 0x1,
PMRCAP_BIR_MASK = 0x7,
PMRCAP_PMRTU_MASK = 0x3,
PMRCAP_PMRWBM_MASK = 0xf,
PMRCAP_PMRTO_MASK = 0xff,
PMRCAP_CMSS_MASK = 0x1,
};
#define NVME_PMRCAP_RDS(pmrcap) \
((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
#define NVME_PMRCAP_WDS(pmrcap) \
((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
#define NVME_PMRCAP_BIR(pmrcap) \
((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
#define NVME_PMRCAP_PMRTU(pmrcap) \
((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
#define NVME_PMRCAP_PMRWBM(pmrcap) \
((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
#define NVME_PMRCAP_PMRTO(pmrcap) \
((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
#define NVME_PMRCAP_CMSS(pmrcap) \
((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
(pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
enum NvmePmrctlShift {
PMRCTL_EN_SHIFT = 0,
};
enum NvmePmrctlMask {
PMRCTL_EN_MASK = 0x1,
};
#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
#define NVME_PMRCTL_SET_EN(pmrctl, val) \
(pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
enum NvmePmrstsShift {
PMRSTS_ERR_SHIFT = 0,
PMRSTS_NRDY_SHIFT = 8,
PMRSTS_HSTS_SHIFT = 9,
PMRSTS_CBAI_SHIFT = 12,
};
enum NvmePmrstsMask {
PMRSTS_ERR_MASK = 0xff,
PMRSTS_NRDY_MASK = 0x1,
PMRSTS_HSTS_MASK = 0x7,
PMRSTS_CBAI_MASK = 0x1,
};
#define NVME_PMRSTS_ERR(pmrsts) \
((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
#define NVME_PMRSTS_NRDY(pmrsts) \
((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
#define NVME_PMRSTS_HSTS(pmrsts) \
((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
#define NVME_PMRSTS_CBAI(pmrsts) \
((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
(pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
(pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
(pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
(pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
enum NvmePmrebsShift {
PMREBS_PMRSZU_SHIFT = 0,
PMREBS_RBB_SHIFT = 4,
PMREBS_PMRWBZ_SHIFT = 8,
};
enum NvmePmrebsMask {
PMREBS_PMRSZU_MASK = 0xf,
PMREBS_RBB_MASK = 0x1,
PMREBS_PMRWBZ_MASK = 0xffffff,
};
#define NVME_PMREBS_PMRSZU(pmrebs) \
((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
#define NVME_PMREBS_RBB(pmrebs) \
((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
#define NVME_PMREBS_PMRWBZ(pmrebs) \
((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
(pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
#define NVME_PMREBS_SET_RBB(pmrebs, val) \
(pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
(pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
enum NvmePmrswtpShift {
PMRSWTP_PMRSWTU_SHIFT = 0,
PMRSWTP_PMRSWTV_SHIFT = 8,
};
enum NvmePmrswtpMask {
PMRSWTP_PMRSWTU_MASK = 0xf,
PMRSWTP_PMRSWTV_MASK = 0xffffff,
};
#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
(pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
(pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
enum NvmePmrmscShift {
PMRMSC_CMSE_SHIFT = 1,
PMRMSC_CBA_SHIFT = 12,
};
enum NvmePmrmscMask {
PMRMSC_CMSE_MASK = 0x1,
PMRMSC_CBA_MASK = 0xfffffffffffff,
};
#define NVME_PMRMSC_CMSE(pmrmsc) \
((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
#define NVME_PMRMSC_CBA(pmrmsc) \
((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
(pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
(pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
typedef struct NvmeCmd { typedef struct NvmeCmd {
uint8_t opcode; uint8_t opcode;
uint8_t fuse; uint8_t fuse;

View File

@ -87,6 +87,22 @@ Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict, const QDict *qdict,
Visitor *v, Error **errp); Visitor *v, Error **errp);
/**
* user_creatable_add_dict:
* @qdict: the object definition
* @keyval: if true, use a keyval visitor for processing @qdict (i.e.
* assume that all @qdict values are strings); otherwise, use
* the normal QObject visitor (i.e. assume all @qdict values
* have the QType expected by the QOM object type)
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object that is defined by
* @qdict. The object type is taken from the QDict key 'qom-type', its
* ID from the key 'id'. The remaining entries in @qdict are used to
* initialize the object properties.
*/
void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
/** /**
* user_creatable_add_opts: * user_creatable_add_opts:
* @opts: the object definition * @opts: the object definition

View File

@ -237,7 +237,7 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
int bytes); int bytes);
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp); PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes); int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
int64_t pos, int size); int64_t pos, int size);

View File

@ -3897,7 +3897,7 @@ static int img_resize(int argc, char **argv)
* resizing, so pass @exact=true. It is of no use to report * resizing, so pass @exact=true. It is of no use to report
* success when the image has not actually been resized. * success when the image has not actually been resized.
*/ */
ret = blk_truncate(blk, total_size, true, prealloc, &err); ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
if (!ret) { if (!ret) {
qprintf(quiet, "Image resized.\n"); qprintf(quiet, "Image resized.\n");
} else { } else {

View File

@ -1715,7 +1715,7 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
* exact=true. It is better to err on the "emit more errors" side * exact=true. It is better to err on the "emit more errors" side
* than to be overly permissive. * than to be overly permissive.
*/ */
ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err); ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
return ret; return ret;

View File

@ -278,7 +278,6 @@ static void process_options(int argc, char *argv[])
QemuOpts *opts; QemuOpts *opts;
const char *type; const char *type;
QDict *args; QDict *args;
QObject *ret_data = NULL;
/* FIXME The keyval parser rejects 'help' arguments, so we must /* FIXME The keyval parser rejects 'help' arguments, so we must
* unconditionall try QemuOpts first. */ * unconditionall try QemuOpts first. */
@ -291,9 +290,8 @@ static void process_options(int argc, char *argv[])
qemu_opts_del(opts); qemu_opts_del(opts);
args = keyval_parse(optarg, "qom-type", &error_fatal); args = keyval_parse(optarg, "qom-type", &error_fatal);
qmp_object_add(args, &ret_data, &error_fatal); user_creatable_add_dict(args, true, &error_fatal);
qobject_unref(args); qobject_unref(args);
qobject_unref(ret_data);
break; break;
} }
default: default:

View File

@ -6,6 +6,7 @@
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/qmp/qjson.h" #include "qapi/qmp/qjson.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qapi/qobject-input-visitor.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "qemu/help_option.h" #include "qemu/help_option.h"
#include "qemu/module.h" #include "qemu/module.h"
@ -105,6 +106,36 @@ out:
return obj; return obj;
} }
void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
{
Visitor *v;
Object *obj;
g_autofree char *type = NULL;
g_autofree char *id = NULL;
type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
if (!type) {
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
return;
}
qdict_del(qdict, "qom-type");
id = g_strdup(qdict_get_try_str(qdict, "id"));
if (!id) {
error_setg(errp, QERR_MISSING_PARAMETER, "id");
return;
}
qdict_del(qdict, "id");
if (keyval) {
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
} else {
v = qobject_input_visitor_new(QOBJECT(qdict));
}
obj = user_creatable_add_type(type, id, qdict, v, errp);
visit_free(v);
object_unref(obj);
}
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
{ {

View File

@ -21,7 +21,6 @@
#include "qapi/qapi-commands-qom.h" #include "qapi/qapi-commands-qom.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/qobject-input-visitor.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "qom/qom-qobject.h" #include "qom/qom-qobject.h"
@ -245,24 +244,6 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
{ {
QObject *props; QObject *props;
QDict *pdict; QDict *pdict;
Visitor *v;
Object *obj;
g_autofree char *type = NULL;
g_autofree char *id = NULL;
type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
if (!type) {
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
return;
}
qdict_del(qdict, "qom-type");
id = g_strdup(qdict_get_try_str(qdict, "id"));
if (!id) {
error_setg(errp, QERR_MISSING_PARAMETER, "id");
return;
}
qdict_del(qdict, "id");
props = qdict_get(qdict, "props"); props = qdict_get(qdict, "props");
if (props) { if (props) {
@ -282,10 +263,7 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
qobject_unref(pdict); qobject_unref(pdict);
} }
v = qobject_input_visitor_new(QOBJECT(qdict)); user_creatable_add_dict(qdict, false, errp);
obj = user_creatable_add_type(type, id, qdict, v, errp);
visit_free(v);
object_unref(obj);
} }
void qmp_object_del(const char *id, Error **errp) void qmp_object_del(const char *id, Error **errp)

View File

@ -143,7 +143,6 @@ $QEMU_IO -c 'read -P 0 0 1M' \
echo echo
$QEMU_IO -c 'read -P 0 0 1M' \ $QEMU_IO -c 'read -P 0 0 1M' \
-c 'read -P 0x11 1M 1M' \ -c 'read -P 0x11 1M 1M' \
-c 'read -P 0 2M 2M' \
-c 'read -P 0x11 4M 1M' \ -c 'read -P 0x11 4M 1M' \
-c 'read -P 0 5M 1M' \ -c 'read -P 0 5M 1M' \
-f raw "$TEST_IMG.data" | -f raw "$TEST_IMG.data" |
@ -180,8 +179,15 @@ $QEMU_IO -c 'read -P 0 0 1M' \
-f $IMGFMT "$TEST_IMG" | -f $IMGFMT "$TEST_IMG" |
_filter_qemu_io _filter_qemu_io
# Discarded clusters are only marked as such in the qcow2 metadata, but
# they can contain stale data in the external data file. Instead, zero
# clusters must be zeroed in the external data file too.
echo echo
$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data" $QEMU_IO -c 'read -P 0 0 1M' \
-c 'read -P 0x11 1M 1M' \
-c 'read -P 0 3M 3M' \
-f raw "$TEST_IMG".data |
_filter_qemu_io
echo -n "qcow2 file size after I/O: " echo -n "qcow2 file size after I/O: "
du -b $TEST_IMG | cut -f1 du -b $TEST_IMG | cut -f1

View File

@ -74,8 +74,6 @@ read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576 read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 2097152/2097152 bytes at offset 2097152
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 4194304 read 1048576/1048576 bytes at offset 4194304
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 5242880 read 1048576/1048576 bytes at offset 5242880
@ -108,7 +106,12 @@ read 1048576/1048576 bytes at offset 1048576
read 4194304/4194304 bytes at offset 2097152 read 4194304/4194304 bytes at offset 2097152
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Images are identical. read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 3145728/3145728 bytes at offset 3145728
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qcow2 file size after I/O: 327680 qcow2 file size after I/O: 327680
=== bdrv_co_block_status test for file and offset=0 === === bdrv_co_block_status test for file and offset=0 ===

155
tests/qemu-iotests/274 Executable file
View File

@ -0,0 +1,155 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
#
# Some tests for short backing files and short overlays
import iotests
iotests.verify_image_format(supported_fmts=['qcow2'])
iotests.verify_platform(['linux'])
size_short = 1 * 1024 * 1024
size_long = 2 * 1024 * 1024
size_diff = size_long - size_short
def create_chain() -> None:
iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
str(size_long))
iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
str(size_short))
iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
str(size_long))
iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
def create_vm() -> iotests.VM:
vm = iotests.VM()
vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
% iotests.imgfmt)
vm.add_drive(top, 'backing=mid,node-name=top')
return vm
with iotests.FilePath('base') as base, \
iotests.FilePath('mid') as mid, \
iotests.FilePath('top') as top:
iotests.log('== Commit tests ==')
create_chain()
iotests.log('=== Check visible data ===')
iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
iotests.log('=== Checking allocation status ===')
iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
'-c', 'alloc %d %d' % (size_short, size_diff),
base)
iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
'-c', 'alloc %d %d' % (size_short, size_diff),
mid)
iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
'-c', 'alloc %d %d' % (size_short, size_diff),
top)
iotests.log('=== Checking map ===')
iotests.qemu_img_log('map', '--output=json', base)
iotests.qemu_img_log('map', '--output=human', base)
iotests.qemu_img_log('map', '--output=json', mid)
iotests.qemu_img_log('map', '--output=human', mid)
iotests.qemu_img_log('map', '--output=json', top)
iotests.qemu_img_log('map', '--output=human', top)
iotests.log('=== Testing qemu-img commit (top -> mid) ===')
iotests.qemu_img_log('commit', top)
iotests.img_info_log(mid)
iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
iotests.log('=== Testing HMP commit (top -> mid) ===')
create_chain()
with create_vm() as vm:
vm.launch()
vm.qmp_log('human-monitor-command', command_line='commit drive0')
iotests.img_info_log(mid)
iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
iotests.log('=== Testing QMP active commit (top -> mid) ===')
create_chain()
with create_vm() as vm:
vm.launch()
vm.qmp_log('block-commit', device='top', base_node='mid',
job_id='job0', auto_dismiss=False)
vm.run_job('job0', wait=5)
iotests.img_info_log(mid)
iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
iotests.log('== Resize tests ==')
# Use different sizes for different allocation modes:
#
# We want to have at least one test where 32 bit truncation in the size of
# the overlapping area becomes visible. This is covered by the
# prealloc='off' case (1G to 6G is an overlap of 5G).
#
# However, we can only do this for modes that don't preallocate data
# because otherwise we might run out of space on the test host.
#
# We also want to test some unaligned combinations.
for (prealloc, base_size, top_size_old, top_size_new, off) in [
('off', '6G', '1G', '8G', '5G'),
('metadata', '32G', '30G', '33G', '31G'),
('falloc', '10M', '5M', '15M', '9M'),
('full', '16M', '8M', '12M', '11M'),
('off', '384k', '253k', '512k', '253k'),
('off', '400k', '256k', '512k', '336k'),
('off', '512k', '256k', '500k', '436k')]:
iotests.log('=== preallocation=%s ===' % prealloc)
iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
top_size_old)
iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
# After this, top_size_old to base_size should be allocated/zeroed.
#
# In theory, leaving base_size to top_size_new unallocated would be
# correct, but in practice, if we zero out anything, we zero out
# everything up to top_size_new.
iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
'--preallocation', prealloc, top, top_size_new)
iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
iotests.qemu_io_log('-c', 'map', top)
iotests.qemu_img_log('map', '--output=json', top)

268
tests/qemu-iotests/274.out Normal file
View File

@ -0,0 +1,268 @@
== Commit tests ==
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Check visible data ===
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Checking allocation status ===
1048576/1048576 bytes allocated at offset 0 bytes
1048576/1048576 bytes allocated at offset 1 MiB
0/1048576 bytes allocated at offset 0 bytes
0/0 bytes allocated at offset 1 MiB
0/1048576 bytes allocated at offset 0 bytes
0/1048576 bytes allocated at offset 1 MiB
=== Checking map ===
[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
Offset Length Mapped to File
0 0x200000 0x50000 TEST_DIR/PID-base
[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
Offset Length Mapped to File
0 0x100000 0x50000 TEST_DIR/PID-base
[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
Offset Length Mapped to File
0 0x100000 0x50000 TEST_DIR/PID-base
=== Testing qemu-img commit (top -> mid) ===
Image committed.
image: TEST_IMG
file format: IMGFMT
virtual size: 2 MiB (2097152 bytes)
cluster_size: 65536
backing file: TEST_DIR/PID-base
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing HMP commit (top -> mid) ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
{"return": ""}
image: TEST_IMG
file format: IMGFMT
virtual size: 2 MiB (2097152 bytes)
cluster_size: 65536
backing file: TEST_DIR/PID-base
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing QMP active commit (top -> mid) ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 2097152/2097152 bytes at offset 0
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
{"return": {}}
{"execute": "job-complete", "arguments": {"id": "job0"}}
{"return": {}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
image: TEST_IMG
file format: IMGFMT
virtual size: 2 MiB (2097152 bytes)
cluster_size: 65536
backing file: TEST_DIR/PID-base
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Resize tests ==
=== preallocation=off ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 5368709120
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 5368709120
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
=== preallocation=metadata ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 33285996544
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 33285996544
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
=== preallocation=falloc ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 9437184
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 9437184
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
=== preallocation=full ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 11534336
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 11534336
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
=== preallocation=off ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 259072
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 259072
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
=== preallocation=off ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 344064
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 344064
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
=== preallocation=off ===
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
wrote 65536/65536 bytes at offset 446464
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image resized.
read 65536/65536 bytes at offset 446464
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]

View File

@ -286,6 +286,7 @@
270 rw backing quick 270 rw backing quick
272 rw 272 rw
273 backing quick 273 backing quick
274 rw backing
277 rw quick 277 rw quick
279 rw backing quick 279 rw backing quick
280 rw migration quick 280 rw migration quick

View File

@ -338,8 +338,9 @@ def filter_img_info(output, filename):
for line in output.split('\n'): for line in output.split('\n'):
if 'disk size' in line or 'actual-size' in line: if 'disk size' in line or 'actual-size' in line:
continue continue
line = line.replace(filename, 'TEST_IMG') \ line = line.replace(filename, 'TEST_IMG')
.replace(imgfmt, 'IMGFMT') line = filter_testfiles(line)
line = line.replace(imgfmt, 'IMGFMT')
line = re.sub('iters: [0-9]+', 'iters: XXX', line) line = re.sub('iters: [0-9]+', 'iters: XXX', line)
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)

View File

@ -46,7 +46,8 @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
static int coroutine_fn static int coroutine_fn
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
PreallocMode prealloc, Error **errp) PreallocMode prealloc, BdrvRequestFlags flags,
Error **errp)
{ {
return 0; return 0;
} }
@ -185,18 +186,18 @@ static void test_sync_op_truncate(BdrvChild *c)
int ret; int ret;
/* Normal success path */ /* Normal success path */
ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
g_assert_cmpint(ret, ==, 0); g_assert_cmpint(ret, ==, 0);
/* Early error: Negative offset */ /* Early error: Negative offset */
ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL); ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
g_assert_cmpint(ret, ==, -EINVAL); g_assert_cmpint(ret, ==, -EINVAL);
/* Error: Read-only image */ /* Error: Read-only image */
c->bs->read_only = true; c->bs->read_only = true;
c->bs->open_flags &= ~BDRV_O_RDWR; c->bs->open_flags &= ~BDRV_O_RDWR;
ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL); ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
g_assert_cmpint(ret, ==, -EACCES); g_assert_cmpint(ret, ==, -EACCES);
c->bs->read_only = false; c->bs->read_only = false;