Block patches:
- Drop BDRV_SECTOR_SIZE from qcow2 - Allow Python iotests to be added to the auto group (and add some) - Fix for the backup job - Fix memleak in bdrv_refresh_filename() - Use GStrings in two places for greater efficiency (than manually handling string allocation) -----BEGIN PGP SIGNATURE----- iQFGBAABCAAwFiEEkb62CjDbPohX0Rgp9AfbAGHVz0AFAl48C4YSHG1yZWl0ekBy ZWRoYXQuY29tAAoJEPQH2wBh1c9A1GsH/2qYR3qqZM6y3fJB0sfaARaKiTS9ac9f QQTAs2TEgXkzjdXUgIZu2ieJXPKDK+li7wYGVuMsaHPviscbJH3dKcDprjASHalR u7N913u+PB0eY3aTkHyZZwdoxCGQvMAvrHqkyAXrSdgqssodZ7Uj9/jjpGg0z3Io JE/eu11RdrOX7eOSZbEAYuaRg4VtrBuYIqwSihlRk0cBxjAScfW2ppa2P/Q8+VPa v9bTlFvWQALjG/b0uZx5EgbGztyYzy6PuhdDb+B0S9IsGRidtsxCYZ4pmwQuroJ4 9mITIj0OAzN3Nw80SqTEmW0jtBecmiOOHrCxEREWYjNSP1MbVF5qSTI= =abrL -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-02-06' into staging Block patches: - Drop BDRV_SECTOR_SIZE from qcow2 - Allow Python iotests to be added to the auto group (and add some) - Fix for the backup job - Fix memleak in bdrv_refresh_filename() - Use GStrings in two places for greater efficiency (than manually handling string allocation) # gpg: Signature made Thu 06 Feb 2020 12:50:14 GMT # gpg: using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40 # gpg: issuer "mreitz@redhat.com" # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full] # Primary key fingerprint: 91BE B60A 30DB 3E88 57D1 1829 F407 DB00 61D5 CF40 * remotes/maxreitz/tags/pull-block-2020-02-06: iotests: add test for backup-top failure on permission activation block/backup-top: fix failure path qcow2: Use BDRV_SECTOR_SIZE instead of the hardcoded value qcow2: Don't require aligned offsets in qcow2_co_copy_range_from() qcow2: Use bs->bl.request_alignment when updating an L1 entry qcow2: Tighten cluster_offset alignment assertions qcow2: Don't round the L1 table allocation up to the sector size iotests: Enable more tests in the 'auto' group to improve test coverage iotests: Skip Python-based tests if QEMU does not support virtio-blk iotests: Check for the availability of the required devices in 267 and 127 iotests: Test 183 does not work on macOS and OpenBSD iotests: Test 041 only works on certain systems iotests: remove 'linux' from default supported platforms qcow2: Use a GString in report_unsupported_feature() block: fix memleaks in bdrv_refresh_filename block: Use a GString in bdrv_perm_names() qcow2: Assert that host cluster offsets fit in L2 table entries Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
863d2ed582
12
block.c
12
block.c
|
@ -1998,18 +1998,19 @@ char *bdrv_perm_names(uint64_t perm)
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
char *result = g_strdup("");
|
GString *result = g_string_sized_new(30);
|
||||||
struct perm_name *p;
|
struct perm_name *p;
|
||||||
|
|
||||||
for (p = permissions; p->name; p++) {
|
for (p = permissions; p->name; p++) {
|
||||||
if (perm & p->perm) {
|
if (perm & p->perm) {
|
||||||
char *old = result;
|
if (result->len > 0) {
|
||||||
result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
|
g_string_append(result, ", ");
|
||||||
g_free(old);
|
}
|
||||||
|
g_string_append(result, p->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return g_string_free(result, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6441,6 +6442,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
|
||||||
child->bs->exact_filename);
|
child->bs->exact_filename);
|
||||||
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
|
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
|
||||||
|
|
||||||
|
qobject_unref(bs->full_open_options);
|
||||||
bs->full_open_options = qobject_ref(child->bs->full_open_options);
|
bs->full_open_options = qobject_ref(child->bs->full_open_options);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -190,6 +190,7 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||||
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
|
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
|
||||||
filter_node_name,
|
filter_node_name,
|
||||||
BDRV_O_RDWR, errp);
|
BDRV_O_RDWR, errp);
|
||||||
|
bool appended = false;
|
||||||
|
|
||||||
if (!top) {
|
if (!top) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -212,8 +213,9 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||||
bdrv_append(top, source, &local_err);
|
bdrv_append(top, source, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_prepend(&local_err, "Cannot append backup-top filter: ");
|
error_prepend(&local_err, "Cannot append backup-top filter: ");
|
||||||
goto append_failed;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
appended = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bdrv_append() finished successfully, now we can require permissions
|
* bdrv_append() finished successfully, now we can require permissions
|
||||||
|
@ -224,14 +226,14 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_prepend(&local_err,
|
error_prepend(&local_err,
|
||||||
"Cannot set permissions for backup-top filter: ");
|
"Cannot set permissions for backup-top filter: ");
|
||||||
goto failed_after_append;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->bcs = block_copy_state_new(top->backing, state->target,
|
state->bcs = block_copy_state_new(top->backing, state->target,
|
||||||
cluster_size, write_flags, &local_err);
|
cluster_size, write_flags, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_prepend(&local_err, "Cannot create block-copy-state: ");
|
error_prepend(&local_err, "Cannot create block-copy-state: ");
|
||||||
goto failed_after_append;
|
goto fail;
|
||||||
}
|
}
|
||||||
*bcs = state->bcs;
|
*bcs = state->bcs;
|
||||||
|
|
||||||
|
@ -239,14 +241,15 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||||
|
|
||||||
return top;
|
return top;
|
||||||
|
|
||||||
failed_after_append:
|
fail:
|
||||||
|
if (appended) {
|
||||||
state->active = false;
|
state->active = false;
|
||||||
bdrv_backup_top_drop(top);
|
bdrv_backup_top_drop(top);
|
||||||
|
} else {
|
||||||
append_failed:
|
|
||||||
bdrv_drained_end(source);
|
|
||||||
bdrv_unref_child(top, state->target);
|
|
||||||
bdrv_unref(top);
|
bdrv_unref(top);
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_drained_end(source);
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -124,12 +124,11 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
|
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
|
||||||
new_l1_table = qemu_try_blockalign(bs->file->bs,
|
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_size2);
|
||||||
ROUND_UP(new_l1_size2, 512));
|
|
||||||
if (new_l1_table == NULL) {
|
if (new_l1_table == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memset(new_l1_table, 0, ROUND_UP(new_l1_size2, 512));
|
memset(new_l1_table, 0, new_l1_size2);
|
||||||
|
|
||||||
if (s->l1_size) {
|
if (s->l1_size) {
|
||||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||||
|
@ -217,26 +216,31 @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Writes one sector of the L1 table to the disk (can't update single entries
|
* Writes an L1 entry to disk (note that depending on the alignment
|
||||||
* and we really don't want bdrv_pread to perform a read-modify-write)
|
* requirements this function may write more that just one entry in
|
||||||
|
* order to prevent bdrv_pwrite from performing a read-modify-write)
|
||||||
*/
|
*/
|
||||||
#define L1_ENTRIES_PER_SECTOR (512 / 8)
|
|
||||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||||
{
|
{
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
|
|
||||||
int l1_start_index;
|
int l1_start_index;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
int bufsize = MAX(sizeof(uint64_t),
|
||||||
|
MIN(bs->file->bs->bl.request_alignment, s->cluster_size));
|
||||||
|
int nentries = bufsize / sizeof(uint64_t);
|
||||||
|
g_autofree uint64_t *buf = g_try_new0(uint64_t, nentries);
|
||||||
|
|
||||||
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
if (buf == NULL) {
|
||||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
|
return -ENOMEM;
|
||||||
i++)
|
}
|
||||||
{
|
|
||||||
|
l1_start_index = QEMU_ALIGN_DOWN(l1_index, nentries);
|
||||||
|
for (i = 0; i < MIN(nentries, s->l1_size - l1_start_index); i++) {
|
||||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
|
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
|
||||||
s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false);
|
s->l1_table_offset + 8 * l1_start_index, bufsize, false);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +248,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
||||||
ret = bdrv_pwrite_sync(bs->file,
|
ret = bdrv_pwrite_sync(bs->file,
|
||||||
s->l1_table_offset + 8 * l1_start_index,
|
s->l1_table_offset + 8 * l1_start_index,
|
||||||
buf, sizeof(buf));
|
buf, bufsize);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -777,6 +781,10 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
|
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
|
||||||
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
|
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
|
||||||
|
|
||||||
|
/* The offset and size must fit in their fields of the L2 table entry */
|
||||||
|
assert((cluster_offset & s->cluster_offset_mask) == cluster_offset);
|
||||||
|
assert((nb_csectors & s->csize_mask) == nb_csectors);
|
||||||
|
|
||||||
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
||||||
((uint64_t)nb_csectors << s->csize_shift);
|
((uint64_t)nb_csectors << s->csize_shift);
|
||||||
|
|
||||||
|
@ -972,6 +980,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
|
|
||||||
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
|
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
|
||||||
for (i = 0; i < m->nb_clusters; i++) {
|
for (i = 0; i < m->nb_clusters; i++) {
|
||||||
|
uint64_t offset = cluster_offset + (i << s->cluster_bits);
|
||||||
/* if two concurrent writes happen to the same unallocated cluster
|
/* if two concurrent writes happen to the same unallocated cluster
|
||||||
* each write allocates separate cluster and writes data concurrently.
|
* each write allocates separate cluster and writes data concurrently.
|
||||||
* The first one to complete updates l2 table with pointer to its
|
* The first one to complete updates l2 table with pointer to its
|
||||||
|
@ -982,8 +991,10 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
old_cluster[j++] = l2_slice[l2_index + i];
|
old_cluster[j++] = l2_slice[l2_index + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
|
/* The offset must fit in the offset field of the L2 table entry */
|
||||||
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
|
assert((offset & L2E_OFFSET_MASK) == offset);
|
||||||
|
|
||||||
|
l2_slice[l2_index + i] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1913,6 +1924,9 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The offset must fit in the offset field */
|
||||||
|
assert((offset & L2E_OFFSET_MASK) == offset);
|
||||||
|
|
||||||
if (l2_refcount > 1) {
|
if (l2_refcount > 1) {
|
||||||
/* For shared L2 tables, set the refcount accordingly
|
/* For shared L2 tables, set the refcount accordingly
|
||||||
* (it is already 1 and needs to be l2_refcount) */
|
* (it is already 1 and needs to be l2_refcount) */
|
||||||
|
|
|
@ -1262,7 +1262,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||||
* l1_table_offset when it is the current s->l1_table_offset! Be careful
|
* l1_table_offset when it is the current s->l1_table_offset! Be careful
|
||||||
* when changing this! */
|
* when changing this! */
|
||||||
if (l1_table_offset != s->l1_table_offset) {
|
if (l1_table_offset != s->l1_table_offset) {
|
||||||
l1_table = g_try_malloc0(ROUND_UP(l1_size2, 512));
|
l1_table = g_try_malloc0(l1_size2);
|
||||||
if (l1_size2 && l1_table == NULL) {
|
if (l1_size2 && l1_table == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -1024,8 +1024,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||||
new_l1_table = qemu_try_blockalign(bs->file->bs,
|
new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_bytes);
|
||||||
ROUND_UP(new_l1_bytes, 512));
|
|
||||||
if (new_l1_table == NULL) {
|
if (new_l1_table == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,16 +453,15 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
|
||||||
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
||||||
uint64_t mask)
|
uint64_t mask)
|
||||||
{
|
{
|
||||||
char *features = g_strdup("");
|
g_autoptr(GString) features = g_string_sized_new(60);
|
||||||
char *old;
|
|
||||||
|
|
||||||
while (table && table->name[0] != '\0') {
|
while (table && table->name[0] != '\0') {
|
||||||
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
||||||
if (mask & (1ULL << table->bit)) {
|
if (mask & (1ULL << table->bit)) {
|
||||||
old = features;
|
if (features->len > 0) {
|
||||||
features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
|
g_string_append(features, ", ");
|
||||||
table->name);
|
}
|
||||||
g_free(old);
|
g_string_append_printf(features, "%.46s", table->name);
|
||||||
mask &= ~(1ULL << table->bit);
|
mask &= ~(1ULL << table->bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,14 +469,14 @@ static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
old = features;
|
if (features->len > 0) {
|
||||||
features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
|
g_string_append(features, ", ");
|
||||||
old, *old ? ", " : "", mask);
|
}
|
||||||
g_free(old);
|
g_string_append_printf(features,
|
||||||
|
"Unknown incompatible feature: %" PRIx64, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_setg(errp, "Unsupported qcow2 feature(s): %s", features);
|
error_setg(errp, "Unsupported qcow2 feature(s): %s", features->str);
|
||||||
g_free(features);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1492,7 +1491,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
|
||||||
|
|
||||||
if (s->l1_size > 0) {
|
if (s->l1_size > 0) {
|
||||||
s->l1_table = qemu_try_blockalign(bs->file->bs,
|
s->l1_table = qemu_try_blockalign(bs->file->bs,
|
||||||
ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
|
s->l1_size * sizeof(uint64_t));
|
||||||
if (s->l1_table == NULL) {
|
if (s->l1_table == NULL) {
|
||||||
error_setg(errp, "Could not allocate L1 table");
|
error_setg(errp, "Could not allocate L1 table");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -2168,10 +2167,7 @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
|
||||||
offset, bytes, qiov, qiov_offset);
|
offset, bytes, qiov, qiov_offset);
|
||||||
|
|
||||||
case QCOW2_CLUSTER_NORMAL:
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
if ((file_cluster_offset & 511) != 0) {
|
assert(offset_into_cluster(s, file_cluster_offset) == 0);
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
|
return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
|
||||||
offset, bytes, qiov, qiov_offset);
|
offset, bytes, qiov, qiov_offset);
|
||||||
|
@ -2507,7 +2503,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
|
||||||
goto out_locked;
|
goto out_locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((cluster_offset & 511) == 0);
|
assert(offset_into_cluster(s, cluster_offset) == 0);
|
||||||
|
|
||||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||||
cluster_offset + offset_in_cluster,
|
cluster_offset + offset_in_cluster,
|
||||||
|
@ -3276,7 +3272,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||||
|
|
||||||
/* Validate options and set default values */
|
/* Validate options and set default values */
|
||||||
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
|
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
|
||||||
error_setg(errp, "Image size must be a multiple of 512 bytes");
|
error_setg(errp, "Image size must be a multiple of %u bytes",
|
||||||
|
(unsigned) BDRV_SECTOR_SIZE);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -3832,10 +3829,6 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
|
||||||
case QCOW2_CLUSTER_NORMAL:
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
child = s->data_file;
|
child = s->data_file;
|
||||||
copy_offset += offset_into_cluster(s, src_offset);
|
copy_offset += offset_into_cluster(s, src_offset);
|
||||||
if ((copy_offset & 511) != 0) {
|
|
||||||
ret = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3897,7 +3890,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert((cluster_offset & 511) == 0);
|
assert(offset_into_cluster(s, cluster_offset) == 0);
|
||||||
|
|
||||||
ret = qcow2_pre_write_overlap_check(bs, 0,
|
ret = qcow2_pre_write_overlap_check(bs, 0,
|
||||||
cluster_offset + offset_in_cluster, cur_bytes, true);
|
cluster_offset + offset_in_cluster, cur_bytes, true);
|
||||||
|
@ -3954,8 +3947,9 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset & 511) {
|
if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
|
||||||
error_setg(errp, "The new size must be a multiple of 512");
|
error_setg(errp, "The new size must be a multiple of %u",
|
||||||
|
(unsigned) BDRV_SECTOR_SIZE);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1134,4 +1134,5 @@ class TestOrphanedSource(iotests.QMPTestCase):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
iotests.main(supported_fmts=['qcow2', 'qed'],
|
iotests.main(supported_fmts=['qcow2', 'qed'],
|
||||||
supported_protocols=['file'])
|
supported_protocols=['file'],
|
||||||
|
supported_platforms=['linux', 'freebsd', 'netbsd', 'openbsd'])
|
||||||
|
|
|
@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
_supported_fmt qcow2
|
_supported_fmt qcow2
|
||||||
_supported_proto file
|
_supported_proto file
|
||||||
|
|
||||||
|
_require_devices virtio-scsi scsi-hd
|
||||||
|
|
||||||
IMG_SIZE=64K
|
IMG_SIZE=64K
|
||||||
|
|
||||||
_make_test_img $IMG_SIZE
|
_make_test_img $IMG_SIZE
|
||||||
|
|
|
@ -42,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
. ./common.filter
|
. ./common.filter
|
||||||
. ./common.qemu
|
. ./common.qemu
|
||||||
|
|
||||||
|
_supported_os Linux FreeBSD NetBSD
|
||||||
_supported_fmt qcow2 raw qed quorum
|
_supported_fmt qcow2 raw qed quorum
|
||||||
_supported_proto file
|
_supported_proto file
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ _require_drivers copy-on-read
|
||||||
# and generally impossible with external data files
|
# and generally impossible with external data files
|
||||||
_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
|
_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
|
||||||
|
|
||||||
|
_require_devices virtio-blk
|
||||||
|
|
||||||
do_run_qemu()
|
do_run_qemu()
|
||||||
{
|
{
|
||||||
echo Testing: "$@"
|
echo Testing: "$@"
|
||||||
|
|
92
tests/qemu-iotests/283
Normal file
92
tests/qemu-iotests/283
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Test for backup-top filter permission activation failure
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Virtuozzo International GmbH.
|
||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import iotests
|
||||||
|
|
||||||
|
# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
|
||||||
|
iotests.verify_image_format(supported_fmts=['qcow2'])
|
||||||
|
|
||||||
|
size = 1024 * 1024
|
||||||
|
|
||||||
|
""" Test description
|
||||||
|
|
||||||
|
When performing a backup, all writes on the source subtree must go through the
|
||||||
|
backup-top filter so it can copy all data to the target before it is changed.
|
||||||
|
backup-top filter is appended above source node, to achieve this thing, so all
|
||||||
|
parents of source node are handled. A configuration with side parents of source
|
||||||
|
sub-tree with write permission is unsupported (we'd have append several
|
||||||
|
backup-top filter like nodes to handle such parents). The test create an
|
||||||
|
example of such configuration and checks that a backup is then not allowed
|
||||||
|
(blockdev-backup command should fail).
|
||||||
|
|
||||||
|
The configuration:
|
||||||
|
|
||||||
|
┌────────┐ target ┌─────────────┐
|
||||||
|
│ target │ ◀─────── │ backup_top │
|
||||||
|
└────────┘ └─────────────┘
|
||||||
|
│
|
||||||
|
│ backing
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ source │
|
||||||
|
└─────────────┘
|
||||||
|
│
|
||||||
|
│ file
|
||||||
|
▼
|
||||||
|
┌─────────────┐ write perm ┌───────┐
|
||||||
|
│ base │ ◀──────────── │ other │
|
||||||
|
└─────────────┘ └───────┘
|
||||||
|
|
||||||
|
On activation (see .active field of backup-top state in block/backup-top.c),
|
||||||
|
backup-top is going to unshare write permission on its source child. Write
|
||||||
|
unsharing will be propagated to the "source->base" link and will conflict with
|
||||||
|
other node write permission. So permission update will fail and backup job will
|
||||||
|
not be started.
|
||||||
|
|
||||||
|
Note, that the only thing which prevents backup of running on such
|
||||||
|
configuration is default permission propagation scheme. It may be altered by
|
||||||
|
different block drivers, so backup will run in invalid configuration. But
|
||||||
|
something is better than nothing. Also, before the previous commit (commit
|
||||||
|
preceding this test creation), starting backup on such configuration led to
|
||||||
|
crash, so current "something" is a lot better, and this test actual goal is
|
||||||
|
to check that crash is fixed :)
|
||||||
|
"""
|
||||||
|
|
||||||
|
vm = iotests.VM()
|
||||||
|
vm.launch()
|
||||||
|
|
||||||
|
vm.qmp_log('blockdev-add', **{'node-name': 'target', 'driver': 'null-co'})
|
||||||
|
|
||||||
|
vm.qmp_log('blockdev-add', **{
|
||||||
|
'node-name': 'source',
|
||||||
|
'driver': 'blkdebug',
|
||||||
|
'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
|
||||||
|
})
|
||||||
|
|
||||||
|
vm.qmp_log('blockdev-add', **{
|
||||||
|
'node-name': 'other',
|
||||||
|
'driver': 'blkdebug',
|
||||||
|
'image': 'base',
|
||||||
|
'take-child-perms': ['write']
|
||||||
|
})
|
||||||
|
|
||||||
|
vm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
|
||||||
|
|
||||||
|
vm.shutdown()
|
8
tests/qemu-iotests/283.out
Normal file
8
tests/qemu-iotests/283.out
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}}
|
||||||
|
{"return": {}}
|
||||||
|
{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": {"driver": "null-co", "node-name": "base", "size": 1048576}, "node-name": "source"}}
|
||||||
|
{"return": {}}
|
||||||
|
{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}}
|
||||||
|
{"return": {}}
|
||||||
|
{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
|
||||||
|
{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}}
|
|
@ -655,7 +655,15 @@ fi
|
||||||
python_usable=false
|
python_usable=false
|
||||||
if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)'
|
if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)'
|
||||||
then
|
then
|
||||||
|
# Our python framework also requires virtio-blk
|
||||||
|
if "$QEMU_PROG" -M none -device help | grep -q virtio-blk >/dev/null 2>&1
|
||||||
|
then
|
||||||
python_usable=true
|
python_usable=true
|
||||||
|
else
|
||||||
|
python_unusable_because="Missing virtio-blk in QEMU binary"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
python_unusable_because="Unsupported Python version"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
|
default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
|
||||||
|
@ -843,7 +851,7 @@ do
|
||||||
run_command="$PYTHON $seq"
|
run_command="$PYTHON $seq"
|
||||||
else
|
else
|
||||||
run_command="false"
|
run_command="false"
|
||||||
echo "Unsupported Python version" > $seq.notrun
|
echo "$python_unusable_because" > $seq.notrun
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
run_command="./$seq"
|
run_command="./$seq"
|
||||||
|
|
|
@ -713,5 +713,19 @@ _require_large_file()
|
||||||
rm "$TEST_IMG"
|
rm "$TEST_IMG"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check that a set of devices is available in the QEMU binary
|
||||||
|
#
|
||||||
|
_require_devices()
|
||||||
|
{
|
||||||
|
available=$($QEMU -M none -device help | \
|
||||||
|
grep ^name | sed -e 's/^name "//' -e 's/".*$//')
|
||||||
|
for device
|
||||||
|
do
|
||||||
|
if ! echo "$available" | grep -q "$device" ; then
|
||||||
|
_notrun "$device not available"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# make sure this script returns success
|
# make sure this script returns success
|
||||||
true
|
true
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
027 rw auto quick
|
027 rw auto quick
|
||||||
028 rw backing quick
|
028 rw backing quick
|
||||||
029 rw auto quick
|
029 rw auto quick
|
||||||
030 rw backing
|
030 rw auto backing
|
||||||
031 rw auto quick
|
031 rw auto quick
|
||||||
032 rw auto quick
|
032 rw auto quick
|
||||||
033 rw auto quick
|
033 rw auto quick
|
||||||
|
@ -61,8 +61,8 @@
|
||||||
037 rw auto backing quick
|
037 rw auto backing quick
|
||||||
038 rw auto backing quick
|
038 rw auto backing quick
|
||||||
039 rw auto quick
|
039 rw auto quick
|
||||||
040 rw
|
040 rw auto
|
||||||
041 rw backing
|
041 rw auto backing
|
||||||
042 rw auto quick
|
042 rw auto quick
|
||||||
043 rw auto backing
|
043 rw auto backing
|
||||||
044 rw
|
044 rw
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
124 rw backing
|
124 rw backing
|
||||||
125 rw
|
125 rw
|
||||||
126 rw auto backing
|
126 rw auto backing
|
||||||
127 rw backing quick
|
127 rw auto backing quick
|
||||||
128 rw quick
|
128 rw quick
|
||||||
129 rw quick
|
129 rw quick
|
||||||
130 rw quick
|
130 rw quick
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
177 rw auto quick
|
177 rw auto quick
|
||||||
178 img
|
178 img
|
||||||
179 rw auto quick
|
179 rw auto quick
|
||||||
181 rw migration
|
181 rw auto migration
|
||||||
182 rw quick
|
182 rw quick
|
||||||
183 rw migration
|
183 rw migration
|
||||||
184 rw auto quick
|
184 rw auto quick
|
||||||
|
@ -218,7 +218,7 @@
|
||||||
200 rw
|
200 rw
|
||||||
201 rw migration
|
201 rw migration
|
||||||
202 rw quick
|
202 rw quick
|
||||||
203 rw migration
|
203 rw auto migration
|
||||||
204 rw quick
|
204 rw quick
|
||||||
205 rw quick
|
205 rw quick
|
||||||
206 rw
|
206 rw
|
||||||
|
@ -270,7 +270,7 @@
|
||||||
253 rw quick
|
253 rw quick
|
||||||
254 rw backing quick
|
254 rw backing quick
|
||||||
255 rw quick
|
255 rw quick
|
||||||
256 rw quick
|
256 rw auto quick
|
||||||
257 rw
|
257 rw
|
||||||
258 rw quick
|
258 rw quick
|
||||||
260 rw quick
|
260 rw quick
|
||||||
|
@ -289,3 +289,4 @@
|
||||||
279 rw backing quick
|
279 rw backing quick
|
||||||
280 rw migration quick
|
280 rw migration quick
|
||||||
281 rw quick
|
281 rw quick
|
||||||
|
283 auto quick
|
||||||
|
|
|
@ -931,8 +931,13 @@ def verify_protocol(supported=[], unsupported=[]):
|
||||||
if not_sup or (imgproto in unsupported):
|
if not_sup or (imgproto in unsupported):
|
||||||
notrun('not suitable for this protocol: %s' % imgproto)
|
notrun('not suitable for this protocol: %s' % imgproto)
|
||||||
|
|
||||||
def verify_platform(supported_oses=['linux']):
|
def verify_platform(supported=None, unsupported=None):
|
||||||
if True not in [sys.platform.startswith(x) for x in supported_oses]:
|
if unsupported is not None:
|
||||||
|
if any((sys.platform.startswith(x) for x in unsupported)):
|
||||||
|
notrun('not suitable for this OS: %s' % sys.platform)
|
||||||
|
|
||||||
|
if supported is not None:
|
||||||
|
if not any((sys.platform.startswith(x) for x in supported)):
|
||||||
notrun('not suitable for this OS: %s' % sys.platform)
|
notrun('not suitable for this OS: %s' % sys.platform)
|
||||||
|
|
||||||
def verify_cache_mode(supported_cache_modes=[]):
|
def verify_cache_mode(supported_cache_modes=[]):
|
||||||
|
@ -1028,7 +1033,8 @@ def execute_unittest(output, verbosity, debug):
|
||||||
sys.stderr.write(out)
|
sys.stderr.write(out)
|
||||||
|
|
||||||
def execute_test(test_function=None,
|
def execute_test(test_function=None,
|
||||||
supported_fmts=[], supported_oses=['linux'],
|
supported_fmts=[],
|
||||||
|
supported_platforms=None,
|
||||||
supported_cache_modes=[], supported_aio_modes={},
|
supported_cache_modes=[], supported_aio_modes={},
|
||||||
unsupported_fmts=[], supported_protocols=[],
|
unsupported_fmts=[], supported_protocols=[],
|
||||||
unsupported_protocols=[]):
|
unsupported_protocols=[]):
|
||||||
|
@ -1046,7 +1052,7 @@ def execute_test(test_function=None,
|
||||||
verbosity = 1
|
verbosity = 1
|
||||||
verify_image_format(supported_fmts, unsupported_fmts)
|
verify_image_format(supported_fmts, unsupported_fmts)
|
||||||
verify_protocol(supported_protocols, unsupported_protocols)
|
verify_protocol(supported_protocols, unsupported_protocols)
|
||||||
verify_platform(supported_oses)
|
verify_platform(supported=supported_platforms)
|
||||||
verify_cache_mode(supported_cache_modes)
|
verify_cache_mode(supported_cache_modes)
|
||||||
verify_aio_mode(supported_aio_modes)
|
verify_aio_mode(supported_aio_modes)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue