Block patches:
- Fixes to qcow2's implementation of qemu-img check - Our SSH driver now supports bdrv_refresh_filename() - Miscellaneous fixes -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJc0aFqAAoJEPQH2wBh1c9AfWoIAIDzFnhe4cFoLN9WLrZi9t4P F7bJAYwIZKPiZzeAmesMYh3NQIE4hcUHwfYiv7wgcCL6GCRPNW66QFj2yqBnPYjB XZ+CmDxGvWphkctzpn3wc3dC6ydiUDinMH0QRI5fMd07gAK+PnOb6YnvGYydJsFN X8qJeJ0PE//92KNdEr6oJHNNYT5KE01zdkcc1Hv7azcLMXquU9r3B/csOvqU/7iQ YLsqNs5rLnYehAgLh12v9A2NiDZOuOezPVGV9xjnmpsgg3gAVOPBccTwr7o6Wko2 hPqYOzEU3ZEamEIfQROaVzBqt6QAKz9GsFPisbaTy5VoOKUOSsywd2jiWby4imA= =hahF -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2019-05-07' into staging Block patches: - Fixes to qcow2's implementation of qemu-img check - Our SSH driver now supports bdrv_refresh_filename() - Miscellaneous fixes # gpg: Signature made Tue 07 May 2019 16:16:58 BST # gpg: using RSA key F407DB0061D5CF40 # 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-2019-05-07: iotests: Fix iotests 110 and 126 commit: Use bdrv_append() in commit_start() block: Assert that drv->bdrv_child_perm is set in bdrv_child_perm() block/ssh: Implement .bdrv_dirname() block/ssh: Implement .bdrv_refresh_filename() qcow2: discard bitmap when removed qcow2-refcount: don't mask corruptions under internal errors qcow2-refcount: check_refcounts_l2: don't count fixed cluster as allocated qcow2-refcount: check_refcounts_l2: reduce ignored overlaps qcow2-refcount: avoid eating RAM qcow2-refcount: fix check_oflag_copied Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
812b835fb4
9
block.c
9
block.c
@ -1743,11 +1743,10 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
|
||||
uint64_t parent_perm, uint64_t parent_shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
if (bs->drv && bs->drv->bdrv_child_perm) {
|
||||
bs->drv->bdrv_child_perm(bs, c, role, reopen_queue,
|
||||
parent_perm, parent_shared,
|
||||
nperm, nshared);
|
||||
}
|
||||
assert(bs->drv && bs->drv->bdrv_child_perm);
|
||||
bs->drv->bdrv_child_perm(bs, c, role, reopen_queue,
|
||||
parent_perm, parent_shared,
|
||||
nperm, nshared);
|
||||
/* TODO Take force_share from reopen_queue */
|
||||
if (child_bs && child_bs->force_share) {
|
||||
*nshared = BLK_PERM_ALL;
|
||||
|
@ -303,23 +303,14 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
commit_top_bs->total_sectors = top->total_sectors;
|
||||
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
|
||||
|
||||
bdrv_set_backing_hd(commit_top_bs, top, &local_err);
|
||||
bdrv_append(commit_top_bs, top, &local_err);
|
||||
if (local_err) {
|
||||
bdrv_unref(commit_top_bs);
|
||||
commit_top_bs = NULL;
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
bdrv_replace_node(top, commit_top_bs, &local_err);
|
||||
if (local_err) {
|
||||
bdrv_unref(commit_top_bs);
|
||||
commit_top_bs = NULL;
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->commit_top_bs = commit_top_bs;
|
||||
bdrv_unref(commit_top_bs);
|
||||
|
||||
/* Block all nodes between top and base, because they will
|
||||
* disappear from the chain after this operation. */
|
||||
|
@ -202,7 +202,7 @@ static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
|
||||
continue;
|
||||
}
|
||||
|
||||
qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER);
|
||||
qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_ALWAYS);
|
||||
bitmap_table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1520,12 +1520,31 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t start, last, cluster_offset, k, refcount;
|
||||
int64_t file_len;
|
||||
int ret;
|
||||
|
||||
if (size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_len = bdrv_getlength(bs->file->bs);
|
||||
if (file_len < 0) {
|
||||
return file_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Last cluster of qcow2 image may be semi-allocated, so it may be OK to
|
||||
* reference some space after file end but it should be less than one
|
||||
* cluster.
|
||||
*/
|
||||
if (offset + size - file_len >= s->cluster_size) {
|
||||
fprintf(stderr, "ERROR: counting reference for region exceeding the "
|
||||
"end of the file by one cluster or more: offset 0x%" PRIx64
|
||||
" size 0x%" PRIx64 "\n", offset, size);
|
||||
res->corruptions++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
start = start_of_cluster(s, offset);
|
||||
last = start_of_cluster(s, offset + size - 1);
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
@ -1572,7 +1591,7 @@ enum {
|
||||
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size, int64_t l2_offset,
|
||||
int flags, BdrvCheckMode fix)
|
||||
int flags, BdrvCheckMode fix, bool active)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t *l2_table, l2_entry;
|
||||
@ -1641,17 +1660,10 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
{
|
||||
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
|
||||
|
||||
if (flags & CHECK_FRAG_INFO) {
|
||||
res->bfi.allocated_clusters++;
|
||||
if (next_contiguous_offset &&
|
||||
offset != next_contiguous_offset) {
|
||||
res->bfi.fragmented_clusters++;
|
||||
}
|
||||
next_contiguous_offset = offset + s->cluster_size;
|
||||
}
|
||||
|
||||
/* Correct offsets are cluster aligned */
|
||||
if (offset_into_cluster(s, offset)) {
|
||||
res->corruptions++;
|
||||
|
||||
if (qcow2_get_cluster_type(bs, l2_entry) ==
|
||||
QCOW2_CLUSTER_ZERO_ALLOC)
|
||||
{
|
||||
@ -1663,11 +1675,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
if (fix & BDRV_FIX_ERRORS) {
|
||||
uint64_t l2e_offset =
|
||||
l2_offset + (uint64_t)i * sizeof(uint64_t);
|
||||
int ign = active ? QCOW2_OL_ACTIVE_L2 :
|
||||
QCOW2_OL_INACTIVE_L2;
|
||||
|
||||
l2_entry = QCOW_OFLAG_ZERO;
|
||||
l2_table[i] = cpu_to_be64(l2_entry);
|
||||
ret = qcow2_pre_write_overlap_check(bs,
|
||||
QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
|
||||
ret = qcow2_pre_write_overlap_check(bs, ign,
|
||||
l2e_offset, sizeof(uint64_t), false);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: Overlap check failed\n");
|
||||
@ -1686,21 +1699,28 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
/* Do not abort, continue checking the rest of this
|
||||
* L2 table's entries */
|
||||
} else {
|
||||
res->corruptions--;
|
||||
res->corruptions_fixed++;
|
||||
/* Skip marking the cluster as used
|
||||
* (it is unused now) */
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
res->corruptions++;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
|
||||
"not properly aligned; L2 entry corrupted.\n", offset);
|
||||
res->corruptions++;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & CHECK_FRAG_INFO) {
|
||||
res->bfi.allocated_clusters++;
|
||||
if (next_contiguous_offset &&
|
||||
offset != next_contiguous_offset) {
|
||||
res->bfi.fragmented_clusters++;
|
||||
}
|
||||
next_contiguous_offset = offset + s->cluster_size;
|
||||
}
|
||||
|
||||
/* Mark cluster as used */
|
||||
if (!has_data_file(bs)) {
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table,
|
||||
@ -1743,7 +1763,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
void **refcount_table,
|
||||
int64_t *refcount_table_size,
|
||||
int64_t l1_table_offset, int l1_size,
|
||||
int flags, BdrvCheckMode fix)
|
||||
int flags, BdrvCheckMode fix, bool active)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t *l1_table = NULL, l2_offset, l1_size2;
|
||||
@ -1799,7 +1819,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||
/* Process and check L2 entries */
|
||||
ret = check_refcounts_l2(bs, res, refcount_table,
|
||||
refcount_table_size, l2_offset, flags,
|
||||
fix);
|
||||
fix, active);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -1846,7 +1866,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
for (i = 0; i < s->l1_size; i++) {
|
||||
uint64_t l1_entry = s->l1_table[i];
|
||||
uint64_t l2_offset = l1_entry & L1E_OFFSET_MASK;
|
||||
bool l2_dirty = false;
|
||||
int l2_dirty = 0;
|
||||
|
||||
if (!l2_offset) {
|
||||
continue;
|
||||
@ -1859,6 +1879,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
continue;
|
||||
}
|
||||
if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) {
|
||||
res->corruptions++;
|
||||
fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d "
|
||||
"l1_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
|
||||
repair ? "Repairing" : "ERROR", i, l1_entry, refcount);
|
||||
@ -1871,9 +1892,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
res->check_errors++;
|
||||
goto fail;
|
||||
}
|
||||
res->corruptions--;
|
||||
res->corruptions_fixed++;
|
||||
} else {
|
||||
res->corruptions++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1905,6 +1925,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
}
|
||||
}
|
||||
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
|
||||
res->corruptions++;
|
||||
fprintf(stderr, "%s OFLAG_COPIED data cluster: "
|
||||
"l2_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
|
||||
repair ? "Repairing" : "ERROR", l2_entry, refcount);
|
||||
@ -1912,16 +1933,13 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
l2_table[j] = cpu_to_be64(refcount == 1
|
||||
? l2_entry | QCOW_OFLAG_COPIED
|
||||
: l2_entry & ~QCOW_OFLAG_COPIED);
|
||||
l2_dirty = true;
|
||||
res->corruptions_fixed++;
|
||||
} else {
|
||||
res->corruptions++;
|
||||
l2_dirty++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l2_dirty) {
|
||||
if (l2_dirty > 0) {
|
||||
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
|
||||
l2_offset, s->cluster_size,
|
||||
false);
|
||||
@ -1940,6 +1958,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
res->check_errors++;
|
||||
goto fail;
|
||||
}
|
||||
res->corruptions -= l2_dirty;
|
||||
res->corruptions_fixed += l2_dirty;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1977,6 +1997,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
}
|
||||
|
||||
if (cluster >= *nb_clusters) {
|
||||
res->corruptions++;
|
||||
fprintf(stderr, "%s refcount block %" PRId64 " is outside image\n",
|
||||
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
|
||||
|
||||
@ -2016,6 +2037,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
goto resize_fail;
|
||||
}
|
||||
|
||||
res->corruptions--;
|
||||
res->corruptions_fixed++;
|
||||
ret = qcow2_inc_refcounts_imrt(bs, res,
|
||||
refcount_table, nb_clusters,
|
||||
@ -2029,12 +2051,9 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
continue;
|
||||
|
||||
resize_fail:
|
||||
res->corruptions++;
|
||||
*rebuild = true;
|
||||
fprintf(stderr, "ERROR could not resize image: %s\n",
|
||||
strerror(-ret));
|
||||
} else {
|
||||
res->corruptions++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -2090,7 +2109,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
/* current L1 table */
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
|
||||
fix);
|
||||
fix, true);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@ -2119,7 +2138,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
continue;
|
||||
}
|
||||
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
|
||||
sn->l1_table_offset, sn->l1_size, 0, fix);
|
||||
sn->l1_table_offset, sn->l1_size, 0, fix,
|
||||
false);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
73
block/ssh.c
73
block/ssh.c
@ -75,6 +75,14 @@ typedef struct BDRVSSHState {
|
||||
|
||||
/* Used to warn if 'flush' is not supported. */
|
||||
bool unsafe_flush_warning;
|
||||
|
||||
/*
|
||||
* Store the user name for ssh_refresh_filename() because the
|
||||
* default depends on the system you are on -- therefore, when we
|
||||
* generate a filename, it should always contain the user name we
|
||||
* are actually using.
|
||||
*/
|
||||
char *user;
|
||||
} BDRVSSHState;
|
||||
|
||||
static void ssh_state_init(BDRVSSHState *s)
|
||||
@ -87,6 +95,8 @@ static void ssh_state_init(BDRVSSHState *s)
|
||||
|
||||
static void ssh_state_free(BDRVSSHState *s)
|
||||
{
|
||||
g_free(s->user);
|
||||
|
||||
if (s->sftp_handle) {
|
||||
libssh2_sftp_close(s->sftp_handle);
|
||||
}
|
||||
@ -628,14 +638,13 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
|
||||
int ssh_flags, int creat_mode, Error **errp)
|
||||
{
|
||||
int r, ret;
|
||||
const char *user;
|
||||
long port = 0;
|
||||
|
||||
if (opts->has_user) {
|
||||
user = opts->user;
|
||||
s->user = g_strdup(opts->user);
|
||||
} else {
|
||||
user = g_get_user_name();
|
||||
if (!user) {
|
||||
s->user = g_strdup(g_get_user_name());
|
||||
if (!s->user) {
|
||||
error_setg_errno(errp, errno, "Can't get user name");
|
||||
ret = -errno;
|
||||
goto err;
|
||||
@ -685,7 +694,7 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
|
||||
}
|
||||
|
||||
/* Authenticate. */
|
||||
ret = authenticate(s, user, errp);
|
||||
ret = authenticate(s, s->user, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
@ -1242,6 +1251,58 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
|
||||
return ssh_grow_file(s, offset, errp);
|
||||
}
|
||||
|
||||
static void ssh_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
BDRVSSHState *s = bs->opaque;
|
||||
const char *path, *host_key_check;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* None of these options can be represented in a plain "host:port"
|
||||
* format, so if any was given, we have to abort.
|
||||
*/
|
||||
if (s->inet->has_ipv4 || s->inet->has_ipv6 || s->inet->has_to ||
|
||||
s->inet->has_numeric)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
path = qdict_get_try_str(bs->full_open_options, "path");
|
||||
assert(path); /* mandatory option */
|
||||
|
||||
host_key_check = qdict_get_try_str(bs->full_open_options, "host_key_check");
|
||||
|
||||
ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"ssh://%s@%s:%s%s%s%s",
|
||||
s->user, s->inet->host, s->inet->port, path,
|
||||
host_key_check ? "?host_key_check=" : "",
|
||||
host_key_check ?: "");
|
||||
if (ret >= sizeof(bs->exact_filename)) {
|
||||
/* An overflow makes the filename unusable, so do not report any */
|
||||
bs->exact_filename[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static char *ssh_bdrv_dirname(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
if (qdict_haskey(bs->full_open_options, "host_key_check")) {
|
||||
/*
|
||||
* We cannot generate a simple prefix if we would have to
|
||||
* append a query string.
|
||||
*/
|
||||
error_setg(errp,
|
||||
"Cannot generate a base directory with host_key_check set");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bs->exact_filename[0] == '\0') {
|
||||
error_setg(errp, "Cannot generate a base directory for this ssh node");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return path_combine(bs->exact_filename, "");
|
||||
}
|
||||
|
||||
static const char *const ssh_strong_runtime_opts[] = {
|
||||
"host",
|
||||
"port",
|
||||
@ -1268,6 +1329,8 @@ static BlockDriver bdrv_ssh = {
|
||||
.bdrv_getlength = ssh_getlength,
|
||||
.bdrv_co_truncate = ssh_co_truncate,
|
||||
.bdrv_co_flush_to_disk = ssh_co_flush,
|
||||
.bdrv_refresh_filename = ssh_refresh_filename,
|
||||
.bdrv_dirname = ssh_bdrv_dirname,
|
||||
.create_opts = &ssh_create_opts,
|
||||
.strong_runtime_opts = ssh_strong_runtime_opts,
|
||||
};
|
||||
|
@ -53,8 +53,12 @@ TEST_IMG="$TEST_IMG.base" _make_test_img 64M
|
||||
_make_test_img -b "$TEST_IMG_REL.base" 64M
|
||||
# qemu should be able to reconstruct the filename, so relative backing names
|
||||
# should work
|
||||
# (We have to filter the backing file format because vmdk always
|
||||
# reports it (as vmdk), whereas other image formats would do so only
|
||||
# with the backing_fmt creation option, which neither vmdk nor qcow
|
||||
# support)
|
||||
TEST_IMG="json:{'driver':'$IMGFMT','file':{'driver':'file','filename':'$TEST_IMG'}}" \
|
||||
_img_info | _filter_img_info
|
||||
_img_info | _filter_img_info | grep -v 'backing file format'
|
||||
|
||||
echo
|
||||
echo '=== Non-reconstructable filename ==='
|
||||
@ -78,7 +82,7 @@ TEST_IMG="json:{
|
||||
}
|
||||
]
|
||||
}
|
||||
}" _img_info | _filter_img_info
|
||||
}" _img_info | _filter_img_info | grep -v 'backing file format'
|
||||
|
||||
echo
|
||||
echo '=== Backing name is always relative to the backed image ==='
|
||||
@ -110,7 +114,7 @@ TEST_IMG="json:{
|
||||
}
|
||||
]
|
||||
}
|
||||
}" _img_info | _filter_img_info
|
||||
}" _img_info | _filter_img_info | grep -v 'backing file format'
|
||||
|
||||
|
||||
# success, all done
|
||||
|
@ -62,8 +62,12 @@ TOP_IMG="$TEST_DIR/image:top.$IMGFMT"
|
||||
TEST_IMG=$BASE_IMG _make_test_img 64M
|
||||
TEST_IMG=$TOP_IMG _make_test_img -b ./image:base.$IMGFMT
|
||||
|
||||
# The default cluster size depends on the image format
|
||||
TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
|
||||
# (1) The default cluster size depends on the image format
|
||||
# (2) vmdk only supports vmdk backing files, so it always reports the
|
||||
# format of its backing file as such (but neither it nor qcow
|
||||
# support the backing_fmt creation option, so we cannot use that to
|
||||
# harmonize the output across all image formats this test supports)
|
||||
TEST_IMG=$TOP_IMG _img_info | grep -ve 'cluster_size' -e 'backing file format'
|
||||
|
||||
_rm_test_img "$BASE_IMG"
|
||||
_rm_test_img "$TOP_IMG"
|
||||
@ -79,7 +83,7 @@ TOP_IMG="file:image:top.$IMGFMT"
|
||||
TEST_IMG=$BASE_IMG _make_test_img 64M
|
||||
TEST_IMG=$TOP_IMG _make_test_img -b "$BASE_IMG"
|
||||
|
||||
TEST_IMG=$TOP_IMG _img_info | grep -v 'cluster_size'
|
||||
TEST_IMG=$TOP_IMG _img_info | grep -ve 'cluster_size' -e 'backing file format'
|
||||
|
||||
_rm_test_img "$BASE_IMG"
|
||||
_rm_test_img "image:top.$IMGFMT"
|
||||
|
@ -54,15 +54,13 @@ $QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
|
||||
# Put the data cluster at a multiple of 2 TB, resulting in the image apparently
|
||||
# having a multiple of 2^32 clusters
|
||||
# (To be more specific: It is at 32 PB)
|
||||
poke_file "$TEST_IMG" 2048 "\x80\x80\x00\x00\x00\x00\x00\x00"
|
||||
poke_file "$TEST_IMG" $((2048 + 8)) "\x00\x80\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
# An offset of 32 PB results in qemu-img check having to allocate an in-memory
|
||||
# refcount table of 128 TB (16 bit refcounts, 512 byte clusters).
|
||||
# This should be generally too much for any system and thus fail.
|
||||
# What this test is checking is that the qcow2 driver actually tries to allocate
|
||||
# such a large amount of memory (and is consequently aborting) instead of having
|
||||
# truncated the cluster count somewhere (which would result in much less memory
|
||||
# being allocated and then a segfault occurring).
|
||||
# refcount table of 128 TB (16 bit refcounts, 512 byte clusters), if qemu-img
|
||||
# don't check that referenced data cluster is far beyond the end of file.
|
||||
# But starting from 4.0, qemu-img does this check, and instead of "Cannot
|
||||
# allocate memory", we have an error showing that l2 entry is invalid.
|
||||
_check_test_img
|
||||
|
||||
# success, all done
|
||||
|
@ -5,5 +5,8 @@ QA output created by 138
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
qemu-img: Check failed: Cannot allocate memory
|
||||
ERROR: counting reference for region exceeding the end of the file by one cluster or more: offset 0x80000000000000 size 0x200
|
||||
|
||||
1 errors were found on the image.
|
||||
Data may be corrupted, or further writes to the image may corrupt it.
|
||||
*** done
|
||||
|
@ -66,7 +66,7 @@ with iotests.FilePath('t.img') as disk_path, \
|
||||
'size': 4194304 })
|
||||
vm.shutdown()
|
||||
|
||||
iotests.img_info_log(remote_path, filter_path=disk_path)
|
||||
iotests.img_info_log(remote_path)
|
||||
iotests.log("")
|
||||
iotests.img_info_log(disk_path)
|
||||
|
||||
@ -91,7 +91,7 @@ with iotests.FilePath('t.img') as disk_path, \
|
||||
'size': 8388608 })
|
||||
vm.shutdown()
|
||||
|
||||
iotests.img_info_log(remote_path, filter_path=disk_path)
|
||||
iotests.img_info_log(remote_path)
|
||||
|
||||
vm.launch()
|
||||
blockdev_create(vm, { 'driver': 'ssh',
|
||||
@ -108,7 +108,7 @@ with iotests.FilePath('t.img') as disk_path, \
|
||||
'size': 4194304 })
|
||||
vm.shutdown()
|
||||
|
||||
iotests.img_info_log(remote_path, filter_path=disk_path)
|
||||
iotests.img_info_log(remote_path)
|
||||
|
||||
md5_key = subprocess.check_output(
|
||||
'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
|
||||
@ -146,7 +146,7 @@ with iotests.FilePath('t.img') as disk_path, \
|
||||
'size': 8388608 })
|
||||
vm.shutdown()
|
||||
|
||||
iotests.img_info_log(remote_path, filter_path=disk_path)
|
||||
iotests.img_info_log(remote_path)
|
||||
|
||||
sha1_key = subprocess.check_output(
|
||||
'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
|
||||
@ -184,7 +184,7 @@ with iotests.FilePath('t.img') as disk_path, \
|
||||
'size': 4194304 })
|
||||
vm.shutdown()
|
||||
|
||||
iotests.img_info_log(remote_path, filter_path=disk_path)
|
||||
iotests.img_info_log(remote_path)
|
||||
|
||||
#
|
||||
# Invalid path and user
|
||||
|
@ -5,7 +5,7 @@
|
||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||
{"return": {}}
|
||||
|
||||
image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
|
||||
image: TEST_IMG
|
||||
file format: IMGFMT
|
||||
virtual size: 4 MiB (4194304 bytes)
|
||||
|
||||
@ -21,7 +21,7 @@ virtual size: 4 MiB (4194304 bytes)
|
||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||
{"return": {}}
|
||||
|
||||
image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
|
||||
image: TEST_IMG
|
||||
file format: IMGFMT
|
||||
virtual size: 8 MiB (8388608 bytes)
|
||||
|
||||
@ -30,7 +30,7 @@ virtual size: 8 MiB (8388608 bytes)
|
||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||
{"return": {}}
|
||||
|
||||
image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
|
||||
image: TEST_IMG
|
||||
file format: IMGFMT
|
||||
virtual size: 4 MiB (4194304 bytes)
|
||||
|
||||
@ -45,7 +45,7 @@ Job failed: remote host key does not match host_key_check 'wrong'
|
||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||
{"return": {}}
|
||||
|
||||
image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
|
||||
image: TEST_IMG
|
||||
file format: IMGFMT
|
||||
virtual size: 8 MiB (8388608 bytes)
|
||||
|
||||
@ -60,7 +60,7 @@ Job failed: remote host key does not match host_key_check 'wrong'
|
||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||
{"return": {}}
|
||||
|
||||
image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}}
|
||||
image: TEST_IMG
|
||||
file format: IMGFMT
|
||||
virtual size: 4 MiB (4194304 bytes)
|
||||
|
||||
|
@ -158,7 +158,7 @@ else
|
||||
TEST_IMG="nbd:127.0.0.1:10810"
|
||||
elif [ "$IMGPROTO" = "ssh" ]; then
|
||||
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
|
||||
REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR"
|
||||
REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR"
|
||||
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
|
||||
elif [ "$IMGPROTO" = "nfs" ]; then
|
||||
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
|
||||
|
@ -411,7 +411,7 @@ def remote_filename(path):
|
||||
if imgproto == 'file':
|
||||
return path
|
||||
elif imgproto == 'ssh':
|
||||
return "ssh://127.0.0.1%s" % (path)
|
||||
return "ssh://%s@127.0.0.1:22%s" % (os.environ.get('USER'), path)
|
||||
else:
|
||||
raise Exception("Protocol %s not supported" % (imgproto))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user