diff --git a/block.c b/block.c index 9ae5c0ed2f..7dc8fe289a 100644 --- a/block.c +++ b/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; diff --git a/block/commit.c b/block/commit.c index 27537d995b..14e5bb394c 100644 --- a/block/commit.c +++ b/block/commit.c @@ -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. */ diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index e53a1609d7..8a75366c92 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -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; } } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e0fe322500..fa7ac1f7cb 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -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; } diff --git a/block/ssh.c b/block/ssh.c index 859249113d..12fd4f39e8 100644 --- a/block/ssh.c +++ b/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, }; diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index fad672c1ae..33b169ffd4 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -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 diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 index 96dc048d59..e3ee65c606 100755 --- a/tests/qemu-iotests/126 +++ b/tests/qemu-iotests/126 @@ -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" diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138 index f353ac8219..6a731370db 100755 --- a/tests/qemu-iotests/138 +++ b/tests/qemu-iotests/138 @@ -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 diff --git a/tests/qemu-iotests/138.out b/tests/qemu-iotests/138.out index 3fe911f85a..aca7d47a80 100644 --- a/tests/qemu-iotests/138.out +++ b/tests/qemu-iotests/138.out @@ -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 diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index dfd3c51bd1..b3816136f7 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -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 diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 979d5cf745..ec9823793a 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -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) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index a543e546c2..93f87389b6 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -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 diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 997dc910cb..f811f69135 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -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))