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>
master
Peter Maydell 2019-05-09 16:31:12 +01:00
commit 812b835fb4
13 changed files with 159 additions and 77 deletions

View File

@ -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;

View File

@ -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. */

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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))