Block layer core and image format patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJVX0lfAAoJEH8JsnLIjy/WFloQAMFIiYVZU7HqXFJn0SpJTFuT XeMLj1rNCWQMNnD3lrwGqRL81rZG8mH+d15gzPfL6gzxZgSIr2VfQrFjMCJHuiBG F8CkaYnKNOqyiAHNkcVsP0Brsn7ZVKTWZzWzAdbP8eVWgjnstmwFURz56bhVyIpY 5b4atvH6GAeKrraZVTMhz1ltT6051EsH7OOYDyIFgMC6RL8X/N+34QIOY65whfqj 9vpCiajGX8deGXpGPPNTMf8Nf2J/06X2xzcIqmq/YaD5fCi7XQJAm755eHcGfKdA HACuKNsFk6VHYeKLsB383FFGuIvYgDT3Vqh1TGCN/jYlVm0kdIKKajW2KCX90l+9 Ep8saQvWYNA6tbIW631qRM3VHWuUI80U8nlVHlNdeBeTglf3Q7QUuur8FsL7S/aR 2ij2JymPaORQ5GZAWfVWpiJd15BOW5uOeP2FpoF5kHAgt2E4KRIEmmSsWNF6L3+E 7cMrl7EknlRQNlz9//SqaSUzFhFSO0w267tpDRQmHKWLVzijo9a1AGgSR9EpqYtj dBjvYgQQQf3aioOhzBd916qO0vMrOsD9XbmIFQAZCW9bIZ/ly9BrZGu419p2DCUs WP45PGwG0WlEKpVAhg7jJz8df2fGh1BxXcKyWHe0BpHLnI9rAUg3YbauO3miY8vc 3xoJZqL+pYrswOdDG3HA =x52M -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
0d2ed6039c
@ -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
|
||||
|
1
block.c
1
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;
|
||||
}
|
||||
|
||||
|
10
block/qcow.c
10
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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
c->table_array = qemu_try_blockalign(bs->file,
|
||||
(size_t) num_tables * s->cluster_size);
|
||||
|
||||
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;
|
||||
}
|
||||
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,63 +234,51 @@ 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;
|
||||
}
|
||||
|
||||
c->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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
|
||||
uint64_t offset, void **table, bool read_from_disk)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 >>
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
17
block/vmdk.c
17
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
93
qemu-img.c
93
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
23
qemu-io.c
23
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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
69
tests/qemu-iotests/134
Executable file
69
tests/qemu-iotests/134
Executable file
@ -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
|
46
tests/qemu-iotests/134.out
Normal file
46
tests/qemu-iotests/134.out
Normal file
@ -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
|
@ -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`
|
||||
|
@ -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
|
||||
|
@ -129,3 +129,4 @@
|
||||
129 rw auto quick
|
||||
130 rw auto quick
|
||||
131 rw auto quick
|
||||
134 rw auto quick
|
||||
|
@ -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()))
|
||||
|
BIN
tests/qemu-iotests/sample_images/afl9.vmdk.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/afl9.vmdk.bz2
Normal file
Binary file not shown.
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user