summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-05-22 17:20:09 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-05-22 17:20:09 +0100
commit0d2ed6039cf86fe3a78671e32b5e3eb17d725762 (patch)
tree96ced81e7026fb89b0e6dda603a2a757f538fe70
parentbb2fa17f182ee0b45b53474f76679944fc891f04 (diff)
parent4120201d2fcfc24404fe6eb6b761b66bc35bca16 (diff)
downloadqemu-0d2ed6039cf86fe3a78671e32b5e3eb17d725762.zip
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer core and image format patches # gpg: Signature made Fri May 22 16:21:03 2015 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (22 commits) MAINTAINERS: Split "Block QAPI, monitor, command line" off core MAINTAINERS: Add header files to Block Layer Core section tests: add test case for encrypted qcow2 read/write qemu-io: prompt for encryption keys when required util: allow \n to terminate password input util: move read_password method out of qemu-img into osdep/oslib qcow2/qcow: protect against uninitialized encryption key qemu-iotests: Make debugging python tests easier qemu-iotests: qemu-img info on afl VMDK image with a huge capacity block: Detect multiplication overflow in bdrv_getlength qemu-io: Use getopt() correctly qcow2: style fixes in qcow2-cache.c qcow2: make qcow2_cache_put() a void function qcow2: use a hash to look for entries in the L2 cache qcow2: remove qcow2_cache_find_entry_to_replace() qcow2: use an LRU algorithm to replace entries from the L2 cache qcow2: simplify qcow2_cache_put() and qcow2_cache_entry_mark_dirty() qcow2: use one single memory block for the L2/refcount cache tables vmdk: Fix overflow if l1_size is 0x20000000 vmdk: Fix next_cluster_sector for compressed write ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS9
-rw-r--r--block.c1
-rw-r--r--block/qcow.c10
-rw-r--r--block/qcow2-cache.c171
-rw-r--r--block/qcow2-cluster.c65
-rw-r--r--block/qcow2-refcount.c42
-rw-r--r--block/qcow2.c18
-rw-r--r--block/qcow2.h5
-rw-r--r--block/vmdk.c17
-rw-r--r--hw/block/nvme.c3
-rw-r--r--include/qemu/osdep.h2
-rw-r--r--qemu-img.c93
-rw-r--r--qemu-io-cmds.c16
-rw-r--r--qemu-io.c23
-rwxr-xr-xtests/qemu-iotests/0595
-rw-r--r--tests/qemu-iotests/059.out3
-rwxr-xr-xtests/qemu-iotests/13469
-rw-r--r--tests/qemu-iotests/134.out46
-rwxr-xr-xtests/qemu-iotests/check12
-rw-r--r--tests/qemu-iotests/common6
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py14
-rw-r--r--tests/qemu-iotests/sample_images/afl9.vmdk.bz2bin0 -> 178 bytes
-rw-r--r--util/oslib-posix.c67
-rw-r--r--util/oslib-win32.c24
25 files changed, 429 insertions, 293 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index b3552b2c19..0463696dd3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -785,6 +785,7 @@ S: Supported
F: block*
F: block/
F: hw/block/
+F: include/block/
F: qemu-img*
F: qemu-io*
F: tests/qemu-iotests/
@@ -812,6 +813,14 @@ F: block/stream.h
F: block/mirror.c
T: git git://github.com/codyprime/qemu-kvm-jtc.git block
+Block QAPI, monitor, command line
+M: Markus Armbruster <armbru@redhat.com>
+S: Supported
+F: blockdev.c
+F: block/qapi.c
+F: qapi/block*.json
+T: git git://repo.or.cz/qemu/armbru.git block-next
+
Character Devices
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
diff --git a/block.c b/block.c
index 325f7272fe..f42d70e791 100644
--- a/block.c
+++ b/block.c
@@ -2341,6 +2341,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
{
int64_t ret = bdrv_nb_sectors(bs);
+ ret = ret > INT64_MAX / BDRV_SECTOR_SIZE ? -EFBIG : ret;
return ret < 0 ? ret : ret * BDRV_SECTOR_SIZE;
}
diff --git a/block/qcow.c b/block/qcow.c
index ab893284d2..911e59fd0b 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -269,6 +269,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
+ assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
@@ -411,9 +412,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
- if (s->crypt_method &&
+ if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
+ assert(s->crypt_method);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
@@ -590,7 +592,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
if (ret < 0) {
break;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
encrypt_sectors(s, sector_num, buf, buf,
n, 0,
&s->aes_decrypt_key);
@@ -661,7 +664,8 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
ret = -EIO;
break;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
if (!cluster_data) {
cluster_data = g_malloc0(s->cluster_size);
}
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index b1155492a3..ed92a098c4 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -28,62 +28,68 @@
#include "trace.h"
typedef struct Qcow2CachedTable {
- void* table;
- int64_t offset;
- bool dirty;
- int cache_hits;
- int ref;
+ int64_t offset;
+ bool dirty;
+ uint64_t lru_counter;
+ int ref;
} Qcow2CachedTable;
struct Qcow2Cache {
- Qcow2CachedTable* entries;
- struct Qcow2Cache* depends;
+ Qcow2CachedTable *entries;
+ struct Qcow2Cache *depends;
int size;
bool depends_on_flush;
+ void *table_array;
+ uint64_t lru_counter;
};
+static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
+ Qcow2Cache *c, int table)
+{
+ BDRVQcowState *s = bs->opaque;
+ return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
+}
+
+static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
+ Qcow2Cache *c, void *table)
+{
+ BDRVQcowState *s = bs->opaque;
+ ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
+ int idx = table_offset / s->cluster_size;
+ assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
+ return idx;
+}
+
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
{
BDRVQcowState *s = bs->opaque;
Qcow2Cache *c;
- int i;
c = g_new0(Qcow2Cache, 1);
c->size = num_tables;
c->entries = g_try_new0(Qcow2CachedTable, num_tables);
- if (!c->entries) {
- goto fail;
- }
-
- for (i = 0; i < c->size; i++) {
- c->entries[i].table = qemu_try_blockalign(bs->file, s->cluster_size);
- if (c->entries[i].table == NULL) {
- goto fail;
- }
+ c->table_array = qemu_try_blockalign(bs->file,
+ (size_t) num_tables * s->cluster_size);
+
+ if (!c->entries || !c->table_array) {
+ qemu_vfree(c->table_array);
+ g_free(c->entries);
+ g_free(c);
+ c = NULL;
}
return c;
-
-fail:
- if (c->entries) {
- for (i = 0; i < c->size; i++) {
- qemu_vfree(c->entries[i].table);
- }
- }
- g_free(c->entries);
- g_free(c);
- return NULL;
}
-int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
+int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
{
int i;
for (i = 0; i < c->size; i++) {
assert(c->entries[i].ref == 0);
- qemu_vfree(c->entries[i].table);
}
+ qemu_vfree(c->table_array);
g_free(c->entries);
g_free(c);
@@ -151,8 +157,8 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
}
- ret = bdrv_pwrite(bs->file, c->entries[i].offset, c->entries[i].table,
- s->cluster_size);
+ ret = bdrv_pwrite(bs->file, c->entries[i].offset,
+ qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
if (ret < 0) {
return ret;
}
@@ -228,42 +234,12 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
for (i = 0; i < c->size; i++) {
assert(c->entries[i].ref == 0);
c->entries[i].offset = 0;
- c->entries[i].cache_hits = 0;
+ c->entries[i].lru_counter = 0;
}
- return 0;
-}
-
-static int qcow2_cache_find_entry_to_replace(Qcow2Cache *c)
-{
- int i;
- int min_count = INT_MAX;
- int min_index = -1;
-
-
- for (i = 0; i < c->size; i++) {
- if (c->entries[i].ref) {
- continue;
- }
-
- if (c->entries[i].cache_hits < min_count) {
- min_index = i;
- min_count = c->entries[i].cache_hits;
- }
-
- /* Give newer hits priority */
- /* TODO Check how to optimize the replacement strategy */
- if (c->entries[i].cache_hits > 1) {
- c->entries[i].cache_hits /= 2;
- }
- }
+ c->lru_counter = 0;
- if (min_index == -1) {
- /* This can't happen in current synchronous code, but leave the check
- * here as a reminder for whoever starts using AIO with the cache */
- abort();
- }
- return min_index;
+ return 0;
}
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
@@ -272,19 +248,37 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
BDRVQcowState *s = bs->opaque;
int i;
int ret;
+ int lookup_index;
+ uint64_t min_lru_counter = UINT64_MAX;
+ int min_lru_index = -1;
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
offset, read_from_disk);
/* Check if the table is already cached */
- for (i = 0; i < c->size; i++) {
- if (c->entries[i].offset == offset) {
+ i = lookup_index = (offset / s->cluster_size * 4) % c->size;
+ do {
+ const Qcow2CachedTable *t = &c->entries[i];
+ if (t->offset == offset) {
goto found;
}
+ if (t->ref == 0 && t->lru_counter < min_lru_counter) {
+ min_lru_counter = t->lru_counter;
+ min_lru_index = i;
+ }
+ if (++i == c->size) {
+ i = 0;
+ }
+ } while (i != lookup_index);
+
+ if (min_lru_index == -1) {
+ /* This can't happen in current synchronous code, but leave the check
+ * here as a reminder for whoever starts using AIO with the cache */
+ abort();
}
- /* If not, write a table back and replace it */
- i = qcow2_cache_find_entry_to_replace(c);
+ /* Cache miss: write a table back and replace it */
+ i = min_lru_index;
trace_qcow2_cache_get_replace_entry(qemu_coroutine_self(),
c == s->l2_table_cache, i);
if (i < 0) {
@@ -304,22 +298,19 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
}
- ret = bdrv_pread(bs->file, offset, c->entries[i].table, s->cluster_size);
+ ret = bdrv_pread(bs->file, offset, qcow2_cache_get_table_addr(bs, c, i),
+ s->cluster_size);
if (ret < 0) {
return ret;
}
}
- /* Give the table some hits for the start so that it won't be replaced
- * immediately. The number 32 is completely arbitrary. */
- c->entries[i].cache_hits = 32;
c->entries[i].offset = offset;
/* And return the right table */
found:
- c->entries[i].cache_hits++;
c->entries[i].ref++;
- *table = c->entries[i].table;
+ *table = qcow2_cache_get_table_addr(bs, c, i);
trace_qcow2_cache_get_done(qemu_coroutine_self(),
c == s->l2_table_cache, i);
@@ -339,36 +330,24 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
return qcow2_cache_do_get(bs, c, offset, table, false);
}
-int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
+void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
{
- int i;
+ int i = qcow2_cache_get_table_idx(bs, c, *table);
- for (i = 0; i < c->size; i++) {
- if (c->entries[i].table == *table) {
- goto found;
- }
- }
- return -ENOENT;
-
-found:
c->entries[i].ref--;
*table = NULL;
+ if (c->entries[i].ref == 0) {
+ c->entries[i].lru_counter = ++c->lru_counter;
+ }
+
assert(c->entries[i].ref >= 0);
- return 0;
}
-void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
+void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
+ void *table)
{
- int i;
-
- for (i = 0; i < c->size; i++) {
- if (c->entries[i].table == table) {
- goto found;
- }
- }
- abort();
-
-found:
+ int i = qcow2_cache_get_table_idx(bs, c, table);
+ assert(c->entries[i].offset != 0);
c->entries[i].dirty = true;
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index ed2b44d291..1a5c97a5ae 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -253,17 +253,14 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
memcpy(l2_table, old_table, s->cluster_size);
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &old_table);
- if (ret < 0) {
- goto fail;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &old_table);
}
/* write the l2 table to the file */
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
trace_qcow2_l2_allocate_write_l2(bs, l1_index);
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
goto fail;
@@ -403,7 +400,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
goto out;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
qcow2_encrypt_sectors(s, start_sect + n_start,
iov.iov_base, iov.iov_base, n, 1,
&s->aes_encrypt_key);
@@ -692,12 +690,9 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
/* compressed clusters never have the copied flag */
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
l2_table[l2_index] = cpu_to_be64(cluster_offset);
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- return 0;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
return cluster_offset;
}
@@ -771,7 +766,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
if (ret < 0) {
goto err;
}
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
assert(l2_index + m->nb_clusters <= s->l2_size);
for (i = 0; i < m->nb_clusters; i++) {
@@ -789,10 +784,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- goto err;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
/*
* If this was a COW, we need to decrease the refcount of the old cluster.
@@ -944,7 +936,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *l2_table;
unsigned int nb_clusters;
unsigned int keep_clusters;
- int ret, pret;
+ int ret;
trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_offset,
*bytes);
@@ -1011,10 +1003,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
/* Cleanup */
out:
- pret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (pret < 0) {
- return pret;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
/* Only return a host offset if we actually made progress. Otherwise we
* would make requirements for handle_alloc() that it can't fulfill */
@@ -1139,10 +1128,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
* wrong with our code. */
assert(nb_clusters > 0);
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- return ret;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
/* Allocate, if necessary at a given offset in the image file */
alloc_cluster_offset = start_of_cluster(s, *host_offset);
@@ -1470,7 +1456,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
}
/* First remove L2 entries */
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
if (!full_discard && s->qcow_version >= 3) {
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
} else {
@@ -1481,10 +1467,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
}
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- return ret;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
return nb_clusters;
}
@@ -1558,7 +1541,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
old_offset = be64_to_cpu(l2_table[l2_index + i]);
/* Update L2 entries */
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
if (old_offset & QCOW_OFLAG_COMPRESSED) {
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
@@ -1567,10 +1550,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
}
}
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- return ret;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
return nb_clusters;
}
@@ -1760,14 +1740,10 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
if (is_active_l1) {
if (l2_dirty) {
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
qcow2_cache_depends_on_flush(s->l2_table_cache);
}
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
- if (ret < 0) {
- l2_table = NULL;
- goto fail;
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
} else {
if (l2_dirty) {
ret = qcow2_pre_write_overlap_check(bs,
@@ -1798,12 +1774,7 @@ fail:
if (!is_active_l1) {
qemu_vfree(l2_table);
} else {
- if (ret < 0) {
- qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
- } else {
- ret = qcow2_cache_put(bs, s->l2_table_cache,
- (void **)&l2_table);
- }
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
}
}
return ret;
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index f47260b808..0632fc3bc0 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -265,10 +265,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
block_index = cluster_index & (s->refcount_block_size - 1);
*refcount = s->get_refcount(refcount_block, block_index);
- ret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
- if (ret < 0) {
- return ret;
- }
+ qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
return 0;
}
@@ -424,7 +421,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
/* Now the new refcount block needs to be written to disk */
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
- qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
+ qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail_block;
@@ -448,10 +445,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
return -EAGAIN;
}
- ret = qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
- if (ret < 0) {
- goto fail_block;
- }
+ qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
/*
* If we come here, we need to grow the refcount table. Again, a new
@@ -723,13 +717,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
/* Load the refcount block and allocate it if needed */
if (table_index != old_table_index) {
if (refcount_block) {
- ret = qcow2_cache_put(bs, s->refcount_block_cache,
- &refcount_block);
- if (ret < 0) {
- goto fail;
- }
+ qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
}
-
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
if (ret < 0) {
goto fail;
@@ -737,7 +726,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
}
old_table_index = table_index;
- qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
+ qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+ refcount_block);
/* we can update the count and save it */
block_index = cluster_index & (s->refcount_block_size - 1);
@@ -773,11 +763,7 @@ fail:
/* Write last changed block to disk */
if (refcount_block) {
- int wret;
- wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
- if (wret < 0) {
- return ret < 0 ? ret : wret;
- }
+ qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
}
/*
@@ -833,6 +819,11 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
uint64_t i, nb_clusters, refcount;
int ret;
+ /* We can't allocate clusters if they may still be queued for discard. */
+ if (s->cache_discards) {
+ qcow2_process_discards(bs, 0);
+ }
+
nb_clusters = size_to_clusters(s, size);
retry:
for(i = 0; i < nb_clusters; i++) {
@@ -1177,15 +1168,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
s->refcount_block_cache);
}
l2_table[j] = cpu_to_be64(offset);
- qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache,
+ l2_table);
}
}
- ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- if (ret < 0) {
- goto fail;
- }
-
+ qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
if (addend != 0) {
ret = qcow2_update_cluster_refcount(bs, l2_offset >>
diff --git a/block/qcow2.c b/block/qcow2.c
index b9a72e39d4..f7b4cc6a32 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1037,6 +1037,7 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
+ assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
@@ -1224,7 +1225,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
goto fail;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
+
/*
* For encrypted images, read everything into a temporary
* contiguous buffer on which the AES functions can work.
@@ -1255,7 +1258,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
if (ret < 0) {
goto fail;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors, 0, &s->aes_decrypt_key);
qemu_iovec_from_buf(qiov, bytes_done,
@@ -1315,7 +1319,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
trace_qcow2_writev_start_part(qemu_coroutine_self());
index_in_cluster = sector_num & (s->cluster_sectors - 1);
cur_nr_sectors = remaining_sectors;
- if (s->crypt_method &&
+ if (bs->encrypted &&
cur_nr_sectors >
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) {
cur_nr_sectors =
@@ -1334,7 +1338,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
qemu_iovec_concat(&hd_qiov, qiov, bytes_done,
cur_nr_sectors * 512);
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
if (!cluster_data) {
cluster_data = qemu_try_blockalign(bs->file,
QCOW_MAX_CRYPT_CLUSTERS
@@ -1484,7 +1489,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
* that means we don't have to worry about reopening them here.
*/
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
crypt_method = s->crypt_method;
memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
@@ -1513,7 +1519,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
- if (crypt_method) {
+ if (bs->encrypted) {
s->crypt_method = crypt_method;
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
diff --git a/block/qcow2.h b/block/qcow2.h
index 422b825138..0076512af4 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -574,7 +574,8 @@ int qcow2_read_snapshots(BlockDriverState *bs);
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
-void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
+void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
+ void *table);
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
Qcow2Cache *dependency);
@@ -586,6 +587,6 @@ int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
-int qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
#endif
diff --git a/block/vmdk.c b/block/vmdk.c
index 1c5e2ef1b3..b66745dfdd 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -451,7 +451,8 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
Error **errp)
{
int ret;
- int l1_size, i;
+ size_t l1_size;
+ int i;
/* read the L1 table */
l1_size = extent->l1_size * sizeof(uint32_t);
@@ -1302,6 +1303,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
uLongf buf_len;
const uint8_t *write_buf = buf;
int write_len = nb_sectors * 512;
+ int64_t write_offset;
+ int64_t write_end_sector;
if (extent->compressed) {
if (!extent->has_marker) {
@@ -1320,10 +1323,14 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
write_buf = (uint8_t *)data;
write_len = buf_len + sizeof(VmdkGrainMarker);
}
- ret = bdrv_pwrite(extent->file,
- cluster_offset + offset_in_cluster,
- write_buf,
- write_len);
+ write_offset = cluster_offset + offset_in_cluster,
+ ret = bdrv_pwrite(extent->file, write_offset, write_buf, write_len);
+
+ write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE);
+
+ extent->next_cluster_sector = MAX(extent->next_cluster_sector,
+ write_end_sector);
+
if (ret != write_len) {
ret = ret < 0 ? ret : -EIO;
goto out;
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index ad988d7c24..4b6d5e6078 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -479,6 +479,9 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
req->cqe.result =
cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
break;
+ case NVME_VOLATILE_WRITE_CACHE:
+ req->cqe.result = cpu_to_le32(1);
+ break;
default:
return NVME_INVALID_FIELD | NVME_DNR;
}
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index b3300cc239..3247364268 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -259,4 +259,6 @@ void qemu_set_tty_echo(int fd, bool echo);
void os_mem_prealloc(int fd, char *area, size_t sz);
+int qemu_read_password(char *buf, int buf_size);
+
#endif
diff --git a/qemu-img.c b/qemu-img.c
index 8d30e43b53..60c820d002 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -165,97 +165,6 @@ static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
return ret;
}
-#if defined(WIN32)
-/* XXX: put correct support for win32 */
-static int read_password(char *buf, int buf_size)
-{
- int c, i;
-
- printf("Password: ");
- fflush(stdout);
- i = 0;
- for(;;) {
- c = getchar();
- if (c < 0) {
- buf[i] = '\0';
- return -1;
- } else if (c == '\n') {
- break;
- } else if (i < (buf_size - 1)) {
- buf[i++] = c;
- }
- }
- buf[i] = '\0';
- return 0;
-}
-
-#else
-
-#include <termios.h>
-
-static struct termios oldtty;
-
-static void term_exit(void)
-{
- tcsetattr (0, TCSANOW, &oldtty);
-}
-
-static void term_init(void)
-{
- struct termios tty;
-
- tcgetattr (0, &tty);
- oldtty = tty;
-
- tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
- |INLCR|IGNCR|ICRNL|IXON);
- tty.c_oflag |= OPOST;
- tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
- tty.c_cflag &= ~(CSIZE|PARENB);
- tty.c_cflag |= CS8;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
-
- tcsetattr (0, TCSANOW, &tty);
-
- atexit(term_exit);
-}
-
-static int read_password(char *buf, int buf_size)
-{
- uint8_t ch;
- int i, ret;
-
- printf("password: ");
- fflush(stdout);
- term_init();
- i = 0;
- for(;;) {
- ret = read(0, &ch, 1);
- if (ret == -1) {
- if (errno == EAGAIN || errno == EINTR) {
- continue;
- } else {
- break;
- }
- } else if (ret == 0) {
- ret = -1;
- break;
- } else {
- if (ch == '\r') {
- ret = 0;
- break;
- }
- if (i < (buf_size - 1))
- buf[i++] = ch;
- }
- }
- term_exit();
- buf[i] = '\0';
- printf("\n");
- return ret;
-}
-#endif
static int print_block_option_help(const char *filename, const char *fmt)
{
@@ -312,7 +221,7 @@ static BlockBackend *img_open(const char *id, const char *filename,
bs = blk_bs(blk);
if (bdrv_is_encrypted(bs) && require_io) {
qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
- if (read_password(password, sizeof(password)) < 0) {
+ if (qemu_read_password(password, sizeof(password)) < 0) {
error_report("No password given");
goto fail;
}
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 1afcfc01a5..52dc6111bf 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -646,7 +646,7 @@ static int read_f(BlockBackend *blk, int argc, char **argv)
int total = 0;
int pattern = 0, pattern_offset = 0, pattern_count = 0;
- while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
+ while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
switch (c) {
case 'b':
bflag = 1;
@@ -830,7 +830,7 @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
int pattern = 0;
int Pflag = 0;
- while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+ while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) {
case 'C':
Cflag = 1;
@@ -961,7 +961,7 @@ static int write_f(BlockBackend *blk, int argc, char **argv)
int total = 0;
int pattern = 0xcd;
- while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) {
+ while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) {
switch (c) {
case 'b':
bflag = 1;
@@ -1116,7 +1116,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
int pattern = 0xcd;
QEMUIOVector qiov;
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) {
case 'C':
Cflag = 1;
@@ -1228,7 +1228,7 @@ static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
int i;
BlockRequest *reqs;
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) {
case 'C':
Cflag = 1;
@@ -1463,7 +1463,7 @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
ctx->blk = blk;
- while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+ while ((c = getopt(argc, argv, "CP:qv")) != -1) {
switch (c) {
case 'C':
ctx->Cflag = 1;
@@ -1562,7 +1562,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
ctx->blk = blk;
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ while ((c = getopt(argc, argv, "CqP:")) != -1) {
switch (c) {
case 'C':
ctx->Cflag = 1;
@@ -1779,7 +1779,7 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
int64_t offset;
int count;
- while ((c = getopt(argc, argv, "Cq")) != EOF) {
+ while ((c = getopt(argc, argv, "Cq")) != -1) {
switch (c) {
case 'C':
Cflag = 1;
diff --git a/qemu-io.c b/qemu-io.c
index 8e41080cc9..9bc83c6ec1 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -52,6 +52,7 @@ static const cmdinfo_t close_cmd = {
static int openfile(char *name, int flags, QDict *opts)
{
Error *local_err = NULL;
+ BlockDriverState *bs;
if (qemuio_blk) {
fprintf(stderr, "file open already, try 'help close'\n");
@@ -68,7 +69,27 @@ static int openfile(char *name, int flags, QDict *opts)
return 1;
}
+ bs = blk_bs(qemuio_blk);
+ if (bdrv_is_encrypted(bs)) {
+ char password[256];
+ printf("Disk image '%s' is encrypted.\n", name);
+ if (qemu_read_password(password, sizeof(password)) < 0) {
+ error_report("No password given");
+ goto error;
+ }
+ if (bdrv_set_key(bs, password) < 0) {
+ error_report("invalid password");
+ goto error;
+ }
+ }
+
+
return 0;
+
+ error:
+ blk_unref(qemuio_blk);
+ qemuio_blk = NULL;
+ return 1;
}
static void open_help(void)
@@ -120,7 +141,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
QemuOpts *qopts;
QDict *opts;
- while ((c = getopt(argc, argv, "snrgo:")) != EOF) {
+ while ((c = getopt(argc, argv, "snrgo:")) != -1) {
switch (c) {
case 's':
flags |= BDRV_O_SNAPSHOT;
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
index 50ca5ce681..0ded0c3da4 100755
--- a/tests/qemu-iotests/059
+++ b/tests/qemu-iotests/059
@@ -132,6 +132,11 @@ _img_info
$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io
$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io
+echo
+echo "=== Testing afl image with a very large capacity ==="
+_use_sample_img afl9.vmdk.bz2
+_img_info
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index cbb0de4254..67e3cf57e4 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -2336,4 +2336,7 @@ e1000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e1000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
read 1024/1024 bytes at offset 966367641600
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Testing afl image with a very large capacity ===
+qemu-img: Can't get size of device 'image': File too large
*** done
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
new file mode 100755
index 0000000000..1c3820b17e
--- /dev/null
+++ b/tests/qemu-iotests/134
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# Test encrypted read/write using plain bdrv_read/bdrv_write
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=berrange@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+
+size=128M
+IMGOPTS="encryption=on" _make_test_img $size
+
+echo
+echo "== reading whole image =="
+echo "astrochicken" | $QEMU_IO -c "read 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== rewriting whole image =="
+echo "astrochicken" | $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify pattern =="
+echo "astrochicken" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== verify pattern failure with wrong password =="
+echo "platypus" | $QEMU_IO -c "read -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io | _filter_testdir
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/134.out b/tests/qemu-iotests/134.out
new file mode 100644
index 0000000000..a16acb81cd
--- /dev/null
+++ b/tests/qemu-iotests/134.out
@@ -0,0 +1,46 @@
+QA output created by 134
+qemu-img: Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+qemu-img: Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
+
+== reading whole image ==
+Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+Disk image 'TEST_DIR/t.qcow2' is encrypted.
+password:
+read 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== rewriting whole image ==
+Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+Disk image 'TEST_DIR/t.qcow2' is encrypted.
+password:
+wrote 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern ==
+Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+Disk image 'TEST_DIR/t.qcow2' is encrypted.
+password:
+read 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verify pattern failure with wrong password ==
+Encrypted images are deprecated
+Support for them will be removed in a future release.
+You can use 'qemu-img convert' to convert your image to an unencrypted one.
+Disk image 'TEST_DIR/t.qcow2' is encrypted.
+password:
+Pattern verification failed at offset 0, 134217728 bytes
+read 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index baeae80f96..1fa63193ba 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -296,9 +296,15 @@ do
run_command="./$seq"
fi
export OUTPUT_DIR=$PWD
- (cd "$source_iotests";
- MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
- $run_command >$tmp.out 2>&1)
+ if $debug; then
+ (cd "$source_iotests";
+ MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
+ $run_command -d 2>&1 | tee $tmp.out)
+ else
+ (cd "$source_iotests";
+ MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
+ $run_command >$tmp.out 2>&1)
+ fi
sts=$?
$timestamp && _timestamp
stop=`_wallclock`
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index 1e556bbb7d..1030aaf25b 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -32,6 +32,7 @@ check=${check-true}
diff="diff -u"
verbose=false
+debug=false
group=false
xgroup=false
imgopts=false
@@ -132,6 +133,7 @@ s/ .*//p
common options
-v verbose
+ -d debug
check options
-raw test raw (default)
@@ -322,6 +324,10 @@ testlist options
verbose=true
xpand=false
;;
+ -d)
+ debug=true
+ xpand=false
+ ;;
-x) # -x group ... exclude from group file
xgroup=true
xpand=false
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 34b16cb81a..0b817ca32d 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -129,3 +129,4 @@
129 rw auto quick
130 rw auto quick
131 rw auto quick
+134 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e93e62387b..04a294d747 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -338,6 +338,8 @@ def notrun(reason):
def main(supported_fmts=[], supported_oses=['linux']):
'''Run tests'''
+ debug = '-d' in sys.argv
+ verbosity = 1
if supported_fmts and (imgfmt not in supported_fmts):
notrun('not suitable for this image format: %s' % imgfmt)
@@ -347,14 +349,20 @@ def main(supported_fmts=[], supported_oses=['linux']):
# We need to filter out the time taken from the output so that qemu-iotest
# can reliably diff the results against master output.
import StringIO
- output = StringIO.StringIO()
+ if debug:
+ output = sys.stdout
+ verbosity = 2
+ sys.argv.remove('-d')
+ else:
+ output = StringIO.StringIO()
class MyTestRunner(unittest.TextTestRunner):
- def __init__(self, stream=output, descriptions=True, verbosity=1):
+ def __init__(self, stream=output, descriptions=True, verbosity=verbosity):
unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
# unittest.main() will use sys.exit() so expect a SystemExit exception
try:
unittest.main(testRunner=MyTestRunner)
finally:
- sys.stderr.write(re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', output.getvalue()))
+ if not debug:
+ sys.stderr.write(re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', output.getvalue()))
diff --git a/tests/qemu-iotests/sample_images/afl9.vmdk.bz2 b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
new file mode 100644
index 0000000000..03615d36a1
--- /dev/null
+++ b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
Binary files differ
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 37ffd96245..3ae4987b6b 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -50,6 +50,7 @@ extern int daemon(int, int);
#include <termios.h>
#include <unistd.h>
+#include <termios.h>
#include <glib/gprintf.h>
@@ -415,3 +416,69 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
}
}
+
+
+static struct termios oldtty;
+
+static void term_exit(void)
+{
+ tcsetattr(0, TCSANOW, &oldtty);
+}
+
+static void term_init(void)
+{
+ struct termios tty;
+
+ tcgetattr(0, &tty);
+ oldtty = tty;
+
+ tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+ |INLCR|IGNCR|ICRNL|IXON);
+ tty.c_oflag |= OPOST;
+ tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+ tty.c_cflag &= ~(CSIZE|PARENB);
+ tty.c_cflag |= CS8;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VTIME] = 0;
+
+ tcsetattr(0, TCSANOW, &tty);
+
+ atexit(term_exit);
+}
+
+int qemu_read_password(char *buf, int buf_size)
+{
+ uint8_t ch;
+ int i, ret;
+
+ printf("password: ");
+ fflush(stdout);
+ term_init();
+ i = 0;
+ for (;;) {
+ ret = read(0, &ch, 1);
+ if (ret == -1) {
+ if (errno == EAGAIN || errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ } else if (ret == 0) {
+ ret = -1;
+ break;
+ } else {
+ if (ch == '\r' ||
+ ch == '\n') {
+ ret = 0;
+ break;
+ }
+ if (i < (buf_size - 1)) {
+ buf[i++] = ch;
+ }
+ }
+ }
+ term_exit();
+ buf[i] = '\0';
+ printf("\n");
+ return ret;
+}
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 87cfbe0834..730a6707a0 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -470,3 +470,27 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
memset(area + pagesize * i, 0, 1);
}
}
+
+
+/* XXX: put correct support for win32 */
+int qemu_read_password(char *buf, int buf_size)
+{
+ int c, i;
+
+ printf("Password: ");
+ fflush(stdout);
+ i = 0;
+ for (;;) {
+ c = getchar();
+ if (c < 0) {
+ buf[i] = '\0';
+ return -1;
+ } else if (c == '\n') {
+ break;
+ } else if (i < (buf_size - 1)) {
+ buf[i++] = c;
+ }
+ }
+ buf[i] = '\0';
+ return 0;
+}