Block patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTehNaAAoJEH8JsnLIjy/Ws+QP/0C7GTkY+CAgSSoQmIKr96lf k0iRIypxMw68S6NEXtiqFn1yLVv41+puamrznmOSBqxZwwWLpu+J28M8i3M3lr2Q /bs7l22+HfakfJ6AJkYXaLPqAlRdCnM3HOLWpDuVFLeaLlHV14w4oWCIAs/lA6Tg n4S4nKpWUzm97NnNvQjf953kSFZ/xfH72PcICE5vyaQBnrDMMUnRyffdnVBEGMjd hhx/demJNXt+01XxC4VrnvpibGvMthEbQoRwemFi2snD6YXhk9XcT+jiD2VMrgCr fC316vdAFAiVNvI+JjCRE/1gaMRI+m0tNpymzGWnbnEc8P86KUaitASRc150NDSO UgpDg7oneMXC66OdZXG0XqojiAQ8sqHrvMpV+YiirJUbwIcD5ITDKt9omuIjOWjj ENXHOk2U87xoFfqBRRbsuO+U2QtfPDFA4jRjh5ppUy/0xuW/YL3SBCSdUHR8jalM H8mYcC9zKsL7D71Nh6spU4btNK2xjZT+vPoiurHNyiBSVniHagsKPGtzQCqhJEa+ y9xCBCyqZvHBvQ2w1pE4DBOIvt3L0kKd7pRxRch9letCA6Fo/ktb7rvkDkcPVh50 I0kphrnWqGLgC+8oMvh/gjwtzvWkTCfc8jhvzAcBGaInQr+spSaduCAnrGTpfBh1 vfvc1o3NUVhvqipMgdzq =LnQj -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block patches # gpg: Signature made Mon 19 May 2014 15:21:14 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (22 commits) block: optimize zero writes with bdrv_write_zeroes blockdev: add a function to parse enum ids from strings util: add qemu_iovec_is_zero qcow1: Stricter backing file length check qcow1: Validate image size (CVE-2014-0223) qcow1: Validate L2 table size (CVE-2014-0222) qcow1: Check maximum cluster size qcow1: Make padding in the header explicit curl: Add usage documentation curl: Add sslverify option curl: Remove broken parsing of options from url curl: Fix build when curl_multi_socket_action isn't available qemu-iotests: Fix blkdebug in VM drive in 030 qemu-iotests: Fix core dump suppression in test 039 iotests: Add test for the JSON protocol block: Allow JSON filenames check-qdict: Add test for qdict_join() qdict: Add qdict_join() block: add test for vhdx image created by Disk2VHD block: vhdx - account for identical header sections ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ca8c0fab95
60
block.c
60
block.c
@ -1274,6 +1274,33 @@ out:
|
||||
g_free(tmp_filename);
|
||||
}
|
||||
|
||||
static QDict *parse_json_filename(const char *filename, Error **errp)
|
||||
{
|
||||
QObject *options_obj;
|
||||
QDict *options;
|
||||
int ret;
|
||||
|
||||
ret = strstart(filename, "json:", &filename);
|
||||
assert(ret);
|
||||
|
||||
options_obj = qobject_from_json(filename);
|
||||
if (!options_obj) {
|
||||
error_setg(errp, "Could not parse the JSON options");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qobject_type(options_obj) != QTYPE_QDICT) {
|
||||
qobject_decref(options_obj);
|
||||
error_setg(errp, "Invalid JSON object given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
options = qobject_to_qdict(options_obj);
|
||||
qdict_flatten(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||
*
|
||||
@ -1337,6 +1364,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
if (filename && g_str_has_prefix(filename, "json:")) {
|
||||
QDict *json_options = parse_json_filename(filename, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Options given in the filename have lower priority than options
|
||||
* specified directly */
|
||||
qdict_join(options, json_options, false);
|
||||
QDECREF(json_options);
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
@ -3248,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
|
||||
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
|
||||
qemu_iovec_is_zero(qiov)) {
|
||||
flags |= BDRV_REQ_ZERO_WRITE;
|
||||
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
/* Do nothing, write notifier decided to fail this request */
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
@ -3864,7 +3914,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
if (!bs->drv->bdrv_co_get_block_status) {
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
|
||||
if (bs->drv->protocol_name) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
@ -3883,6 +3933,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum, pnum);
|
||||
}
|
||||
|
||||
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
|
||||
ret |= BDRV_BLOCK_ALLOCATED;
|
||||
}
|
||||
|
||||
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
|
||||
if (bdrv_unallocated_blocks_are_zero(bs)) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
@ -3959,9 +4013,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return
|
||||
(ret & BDRV_BLOCK_DATA) ||
|
||||
((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
|
||||
return (ret & BDRV_BLOCK_ALLOCATED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
79
block/curl.c
79
block/curl.c
@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
// #define DEBUG
|
||||
@ -37,6 +38,21 @@
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#define HAVE_SOCKET_ACTION
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKET_ACTION
|
||||
/* If curl_multi_socket_action isn't available, define it statically here in
|
||||
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
|
||||
* less efficient but still safe. */
|
||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
curl_socket_t sockfd,
|
||||
int ev_bitmask,
|
||||
int *running_handles)
|
||||
{
|
||||
return curl_multi_socket(multi_handle, sockfd, running_handles);
|
||||
}
|
||||
#define curl_multi_socket_action __curl_multi_socket_action
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
@ -46,12 +62,16 @@
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_SIZE (256 * 1024)
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
|
||||
#define FIND_RET_NONE 0
|
||||
#define FIND_RET_OK 1
|
||||
#define FIND_RET_WAIT 2
|
||||
|
||||
#define CURL_BLOCK_OPT_URL "url"
|
||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
|
||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
size_t readahead_size;
|
||||
bool sslverify;
|
||||
bool accept_range;
|
||||
} BDRVCURLState;
|
||||
|
||||
@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
|
||||
(long) s->sslverify);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
#define RA_OPTSTR ":readahead="
|
||||
char *file;
|
||||
char *ra;
|
||||
const char *ra_val;
|
||||
int parse_state = 0;
|
||||
|
||||
file = g_strdup(filename);
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
ra = file + strlen(file) - 1;
|
||||
while (ra >= file) {
|
||||
if (parse_state == 0) {
|
||||
if (*ra == ':') {
|
||||
parse_state++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (parse_state == 1) {
|
||||
if (*ra > '9' || *ra < '0') {
|
||||
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
|
||||
if (opt_start > file &&
|
||||
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
|
||||
ra_val = ra + 1;
|
||||
ra -= strlen(RA_OPTSTR) - 1;
|
||||
*ra = '\0';
|
||||
qdict_put(options, "readahead", qstring_from_str(ra_val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ra--;
|
||||
}
|
||||
|
||||
qdict_put(options, "url", qstring_from_str(file));
|
||||
|
||||
g_free(file);
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "url",
|
||||
.name = CURL_BLOCK_OPT_URL,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to open",
|
||||
},
|
||||
{
|
||||
.name = "readahead",
|
||||
.name = CURL_BLOCK_OPT_READAHEAD,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Readahead size",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_SSLVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Verify SSL certificate"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
|
||||
READ_AHEAD_DEFAULT);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
file = qemu_opt_get(opts, "url");
|
||||
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
|
||||
|
||||
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
|
||||
if (file == NULL) {
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
|
@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (bs->io_limits_enabled) {
|
||||
ThrottleConfig cfg;
|
||||
|
44
block/qcow.c
44
block/qcow.c
@ -48,9 +48,10 @@ typedef struct QCowHeader {
|
||||
uint64_t size; /* in bytes */
|
||||
uint8_t cluster_bits;
|
||||
uint8_t l2_bits;
|
||||
uint16_t padding;
|
||||
uint32_t crypt_method;
|
||||
uint64_t l1_table_offset;
|
||||
} QCowHeader;
|
||||
} QEMU_PACKED QCowHeader;
|
||||
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
|
||||
int cluster_sectors;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
unsigned int l1_size;
|
||||
uint64_t cluster_offset_mask;
|
||||
uint64_t l1_table_offset;
|
||||
uint64_t *l1_table;
|
||||
@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift, ret;
|
||||
unsigned int len, i, shift;
|
||||
int ret;
|
||||
QCowHeader header;
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||
@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.size <= 1 || header.cluster_bits < 9) {
|
||||
error_setg(errp, "invalid value in qcow header");
|
||||
if (header.size <= 1) {
|
||||
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
|
||||
error_setg(errp, "Cluster size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
|
||||
* so bytes = num_entries << 3. */
|
||||
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
|
||||
error_setg(errp, "L2 table size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "invalid encryption method in qcow header");
|
||||
ret = -EINVAL;
|
||||
@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* read the level 1 table */
|
||||
shift = s->cluster_bits + s->l2_bits;
|
||||
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (header.size > UINT64_MAX - (1LL << shift)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else {
|
||||
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
s->l1_size = l1_size;
|
||||
}
|
||||
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
|
||||
@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023) {
|
||||
len = 1023;
|
||||
error_setg(errp, "Backing file name too long");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
||||
|
@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
/* The Microsoft Disk2VHD tool will create 2 identical
|
||||
* headers, with identical sequence numbers. If the headers are
|
||||
* identical, don't consider the file corrupt */
|
||||
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
|
||||
s->curr_header = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
43
blockdev.c
43
blockdev.c
@ -288,6 +288,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (!strcmp(buf, lookup[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
error_setg(errp, "invalid parameter value: %s", buf);
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
@ -324,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QemuOpts *opts;
|
||||
const char *id;
|
||||
bool has_driver_specific_opts;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
BlockDriver *drv = NULL;
|
||||
|
||||
/* Check common options by copying from bs_opts to opts, all other options
|
||||
@ -452,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
detect_zeroes =
|
||||
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
|
||||
qemu_opt_get(opts, "detect-zeroes"),
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||
!(bdrv_flags & BDRV_O_UNMAP)) {
|
||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||
"without setting discard operation to unmap");
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
@ -462,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
||||
dinfo->refcount = 1;
|
||||
if (serial != NULL) {
|
||||
dinfo->serial = g_strdup(serial);
|
||||
@ -2455,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "copy-on-read",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "copy read data from backing file into image file",
|
||||
},{
|
||||
.name = "detect-zeroes",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "try to optimize zero writes (off, on, unmap)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
5
hmp.c
5
hmp.c
@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
|
@ -120,6 +120,8 @@ typedef enum {
|
||||
/* BDRV_BLOCK_DATA: data is read from bs->file or another file
|
||||
* BDRV_BLOCK_ZERO: sectors read as zero
|
||||
* BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
|
||||
* BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
|
||||
* layer (as opposed to the backing file)
|
||||
* BDRV_BLOCK_RAW: used internally to indicate that the request
|
||||
* was answered by the raw driver and that one
|
||||
* should look in bs->file directly.
|
||||
@ -141,10 +143,11 @@ typedef enum {
|
||||
* f t f not allocated or unknown offset, read as zero
|
||||
* f f f not allocated or unknown offset, read from backing_hd
|
||||
*/
|
||||
#define BDRV_BLOCK_DATA 1
|
||||
#define BDRV_BLOCK_ZERO 2
|
||||
#define BDRV_BLOCK_OFFSET_VALID 4
|
||||
#define BDRV_BLOCK_RAW 8
|
||||
#define BDRV_BLOCK_DATA 0x01
|
||||
#define BDRV_BLOCK_ZERO 0x02
|
||||
#define BDRV_BLOCK_OFFSET_VALID 0x04
|
||||
#define BDRV_BLOCK_RAW 0x08
|
||||
#define BDRV_BLOCK_ALLOCATED 0x10
|
||||
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
|
||||
|
||||
typedef enum {
|
||||
|
@ -364,6 +364,7 @@ struct BlockDriverState {
|
||||
BlockJob *job;
|
||||
|
||||
QDict *options;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
};
|
||||
|
||||
int get_tmp_filename(char *filename, int size);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qemu/queue.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define QDICT_BUCKET_MAX 512
|
||||
@ -70,4 +71,6 @@ void qdict_flatten(QDict *qdict);
|
||||
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
|
||||
void qdict_array_split(QDict *src, QList **dst);
|
||||
|
||||
void qdict_join(QDict *dest, QDict *src, bool overwrite);
|
||||
|
||||
#endif /* QDICT_H */
|
||||
|
@ -318,6 +318,7 @@ void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes);
|
||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov);
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov);
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov);
|
||||
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
|
||||
|
@ -942,6 +942,8 @@
|
||||
# @encryption_key_missing: true if the backing device is encrypted but an
|
||||
# valid encryption key is missing
|
||||
#
|
||||
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
|
||||
#
|
||||
# @bps: total throughput limit in bytes per second is specified
|
||||
#
|
||||
# @bps_rd: read throughput limit in bytes per second is specified
|
||||
@ -977,6 +979,7 @@
|
||||
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
|
||||
'*backing_file': 'str', 'backing_file_depth': 'int',
|
||||
'encrypted': 'bool', 'encryption_key_missing': 'bool',
|
||||
'detect_zeroes': 'BlockdevDetectZeroesOptions',
|
||||
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
|
||||
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
|
||||
'image': 'ImageInfo',
|
||||
@ -4254,6 +4257,22 @@
|
||||
{ 'enum': 'BlockdevDiscardOptions',
|
||||
'data': [ 'ignore', 'unmap' ] }
|
||||
|
||||
##
|
||||
# @BlockdevDetectZeroesOptions
|
||||
#
|
||||
# Describes the operation mode for the automatic conversion of plain
|
||||
# zero writes by the OS to driver specific optimized zero write commands.
|
||||
#
|
||||
# @off: Disabled (default)
|
||||
# @on: Enabled
|
||||
# @unmap: Enabled and even try to unmap blocks if possible. This requires
|
||||
# also that @BlockdevDiscardOptions is set to unmap for this device.
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'enum': 'BlockdevDetectZeroesOptions',
|
||||
'data': [ 'off', 'on', 'unmap' ] }
|
||||
|
||||
##
|
||||
# @BlockdevAioOptions
|
||||
#
|
||||
@ -4306,20 +4325,22 @@
|
||||
# Options that are available for all block devices, independent of the block
|
||||
# driver.
|
||||
#
|
||||
# @driver: block driver name
|
||||
# @id: #optional id by which the new block device can be referred to.
|
||||
# This is a required option on the top level of blockdev-add, and
|
||||
# currently not allowed on any other level.
|
||||
# @node-name: #optional the name of a block driver state node (Since 2.0)
|
||||
# @discard: #optional discard-related options (default: ignore)
|
||||
# @cache: #optional cache-related options
|
||||
# @aio: #optional AIO backend (default: threads)
|
||||
# @rerror: #optional how to handle read errors on the device
|
||||
# (default: report)
|
||||
# @werror: #optional how to handle write errors on the device
|
||||
# (default: enospc)
|
||||
# @read-only: #optional whether the block device should be read-only
|
||||
# (default: false)
|
||||
# @driver: block driver name
|
||||
# @id: #optional id by which the new block device can be referred to.
|
||||
# This is a required option on the top level of blockdev-add, and
|
||||
# currently not allowed on any other level.
|
||||
# @node-name: #optional the name of a block driver state node (Since 2.0)
|
||||
# @discard: #optional discard-related options (default: ignore)
|
||||
# @cache: #optional cache-related options
|
||||
# @aio: #optional AIO backend (default: threads)
|
||||
# @rerror: #optional how to handle read errors on the device
|
||||
# (default: report)
|
||||
# @werror: #optional how to handle write errors on the device
|
||||
# (default: enospc)
|
||||
# @read-only: #optional whether the block device should be read-only
|
||||
# (default: false)
|
||||
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
|
||||
# (default: off)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
@ -4332,7 +4353,8 @@
|
||||
'*aio': 'BlockdevAioOptions',
|
||||
'*rerror': 'BlockdevOnError',
|
||||
'*werror': 'BlockdevOnError',
|
||||
'*read-only': 'bool' } }
|
||||
'*read-only': 'bool',
|
||||
'*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsFile
|
||||
|
@ -70,11 +70,8 @@ static void add_format_to_seq(void *opaque, const char *fmt_name)
|
||||
{
|
||||
GSequence *seq = opaque;
|
||||
|
||||
if (!g_sequence_lookup(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL)) {
|
||||
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL);
|
||||
}
|
||||
g_sequence_insert_sorted(seq, (gpointer)fmt_name,
|
||||
compare_data, NULL);
|
||||
}
|
||||
|
||||
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
||||
|
@ -414,6 +414,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
|
||||
" [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
|
||||
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
|
||||
" [,readonly=on|off][,copy-on-read=on|off]\n"
|
||||
" [,detect-zeroes=on|off|unmap]\n"
|
||||
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
|
||||
" [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
|
||||
" [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
|
||||
@ -475,6 +476,11 @@ Open drive @option{file} as read-only. Guest write attempts will fail.
|
||||
@item copy-on-read=@var{copy-on-read}
|
||||
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing
|
||||
file sectors into the image file.
|
||||
@item detect-zeroes=@var{detect-zeroes}
|
||||
@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
|
||||
conversion of plain zero writes by the OS to driver specific optimized
|
||||
zero write commands. You may even choose "unmap" if @var{discard} is set
|
||||
to "unmap" to allow a zero write to be converted to an UNMAP operation.
|
||||
@end table
|
||||
|
||||
By default, the @option{cache=writeback} mode is used. It will report data
|
||||
@ -2191,6 +2197,74 @@ qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
|
||||
@end example
|
||||
|
||||
See also @url{http://www.gluster.org}.
|
||||
|
||||
@item HTTP/HTTPS/FTP/FTPS/TFTP
|
||||
QEMU supports read-only access to files accessed over http(s), ftp(s) and tftp.
|
||||
|
||||
Syntax using a single filename:
|
||||
@example
|
||||
<protocol>://[<username>[:<password>]@@]<host>/<path>
|
||||
@end example
|
||||
|
||||
where:
|
||||
@table @option
|
||||
@item protocol
|
||||
'http', 'https', 'ftp', 'ftps', or 'tftp'.
|
||||
|
||||
@item username
|
||||
Optional username for authentication to the remote server.
|
||||
|
||||
@item password
|
||||
Optional password for authentication to the remote server.
|
||||
|
||||
@item host
|
||||
Address of the remote server.
|
||||
|
||||
@item path
|
||||
Path on the remote server, including any query string.
|
||||
@end table
|
||||
|
||||
The following options are also supported:
|
||||
@table @option
|
||||
@item url
|
||||
The full URL when passing options to the driver explicitly.
|
||||
|
||||
@item readahead
|
||||
The amount of data to read ahead with each range request to the remote server.
|
||||
This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it
|
||||
does not have a suffix, it will be assumed to be in bytes. The value must be a
|
||||
multiple of 512 bytes. It defaults to 256k.
|
||||
|
||||
@item sslverify
|
||||
Whether to verify the remote server's certificate when connecting over SSL. It
|
||||
can have the value 'on' or 'off'. It defaults to 'on'.
|
||||
@end table
|
||||
|
||||
Note that when passing options to qemu explicitly, @option{driver} is the value
|
||||
of <protocol>.
|
||||
|
||||
Example: boot from a remote Fedora 20 live ISO image
|
||||
@example
|
||||
qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
|
||||
|
||||
qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
|
||||
@end example
|
||||
|
||||
Example: boot from a remote Fedora 20 cloud image using a local overlay for
|
||||
writes, copy-on-read, and a readahead of 64k
|
||||
@example
|
||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
|
||||
|
||||
qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
|
||||
@end example
|
||||
|
||||
Example: boot from an image stored on a VMware vSphere server with a self-signed
|
||||
certificate using a local overlay for writes and a readahead of 64k
|
||||
@example
|
||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k"@}' /tmp/test.qcow2
|
||||
|
||||
qemu-system-x86_64 -drive file=/tmp/test.qcow2
|
||||
@end example
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
|
@ -2032,6 +2032,8 @@ Each json-object contain the following:
|
||||
- "iops_rd_max": read I/O operations max (json-int)
|
||||
- "iops_wr_max": write I/O operations max (json-int)
|
||||
- "iops_size": I/O size when limiting by iops (json-int)
|
||||
- "detect_zeroes": detect and optimize zero writing (json-string)
|
||||
- Possible values: "off", "on", "unmap"
|
||||
- "image": the detail of the image, it is a json-object containing
|
||||
the following:
|
||||
- "filename": image file name (json-string)
|
||||
@ -2108,6 +2110,7 @@ Example:
|
||||
"iops_rd_max": 0,
|
||||
"iops_wr_max": 0,
|
||||
"iops_size": 0,
|
||||
"detect_zeroes": "on",
|
||||
"image":{
|
||||
"filename":"disks/test.qcow2",
|
||||
"format":"qcow2",
|
||||
|
@ -665,3 +665,35 @@ void qdict_array_split(QDict *src, QList **dst)
|
||||
qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
|
||||
* elements from src to dest.
|
||||
*
|
||||
* If an element from src has a key already present in dest, it will not be
|
||||
* moved unless overwrite is true.
|
||||
*
|
||||
* If overwrite is true, the conflicting values in dest will be discarded and
|
||||
* replaced by the corresponding values from src.
|
||||
*
|
||||
* Therefore, with overwrite being true, the src QDict will always be empty when
|
||||
* this function returns. If overwrite is false, the src QDict will be empty
|
||||
* iff there were no conflicts.
|
||||
*/
|
||||
void qdict_join(QDict *dest, QDict *src, bool overwrite)
|
||||
{
|
||||
const QDictEntry *entry, *next;
|
||||
|
||||
entry = qdict_first(src);
|
||||
while (entry) {
|
||||
next = qdict_next(src, entry);
|
||||
|
||||
if (overwrite || !qdict_haskey(dest, entry->key)) {
|
||||
qobject_incref(entry->value);
|
||||
qdict_put_obj(dest, entry->key, entry->value);
|
||||
qdict_del(src, entry->key);
|
||||
}
|
||||
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
|
||||
QDECREF(test_dict);
|
||||
}
|
||||
|
||||
static void qdict_join_test(void)
|
||||
{
|
||||
QDict *dict1, *dict2;
|
||||
bool overwrite = false;
|
||||
int i;
|
||||
|
||||
dict1 = qdict_new();
|
||||
dict2 = qdict_new();
|
||||
|
||||
|
||||
/* Test everything once without overwrite and once with */
|
||||
do
|
||||
{
|
||||
/* Test empty dicts */
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 0);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
|
||||
/* First iteration: Test movement */
|
||||
/* Second iteration: Test empty source and non-empty destination */
|
||||
qdict_put(dict2, "foo", qint_from_int(42));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 1);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == 42);
|
||||
}
|
||||
|
||||
|
||||
/* Test non-empty source and destination without conflict */
|
||||
qdict_put(dict2, "bar", qint_from_int(23));
|
||||
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 2);
|
||||
g_assert(qdict_size(dict2) == 0);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == 42);
|
||||
g_assert(qdict_get_int(dict1, "bar") == 23);
|
||||
|
||||
|
||||
/* Test conflict */
|
||||
qdict_put(dict2, "foo", qint_from_int(84));
|
||||
|
||||
qdict_join(dict1, dict2, overwrite);
|
||||
|
||||
g_assert(qdict_size(dict1) == 2);
|
||||
g_assert(qdict_size(dict2) == !overwrite);
|
||||
|
||||
g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
|
||||
g_assert(qdict_get_int(dict1, "bar") == 23);
|
||||
|
||||
if (!overwrite) {
|
||||
g_assert(qdict_get_int(dict2, "foo") == 84);
|
||||
}
|
||||
|
||||
|
||||
/* Check the references */
|
||||
g_assert(qdict_get(dict1, "foo")->refcnt == 1);
|
||||
g_assert(qdict_get(dict1, "bar")->refcnt == 1);
|
||||
|
||||
if (!overwrite) {
|
||||
g_assert(qdict_get(dict2, "foo")->refcnt == 1);
|
||||
}
|
||||
|
||||
|
||||
/* Clean up */
|
||||
qdict_del(dict1, "foo");
|
||||
qdict_del(dict1, "bar");
|
||||
|
||||
if (!overwrite) {
|
||||
qdict_del(dict2, "foo");
|
||||
}
|
||||
}
|
||||
while (overwrite ^= true);
|
||||
|
||||
|
||||
QDECREF(dict1);
|
||||
QDECREF(dict2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Errors test-cases
|
||||
*/
|
||||
@ -584,6 +670,7 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/public/iterapi", qdict_iterapi_test);
|
||||
g_test_add_func("/public/flatten", qdict_flatten_test);
|
||||
g_test_add_func("/public/array_split", qdict_array_split_test);
|
||||
g_test_add_func("/public/join", qdict_join_test);
|
||||
|
||||
g_test_add_func("/errors/put_exists", qdict_put_exists_test);
|
||||
g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
|
||||
|
@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
|
||||
qemu_io('-c', 'write -P 0x1 0 512', backing_img)
|
||||
self.vm = iotests.VM().add_drive(test_img)
|
||||
self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
|
@ -47,6 +47,11 @@ _supported_os Linux
|
||||
_default_cache_mode "writethrough"
|
||||
_supported_cache_modes "writethrough"
|
||||
|
||||
_no_dump_exec()
|
||||
{
|
||||
(ulimit -c 0; exec "$@")
|
||||
}
|
||||
|
||||
size=128M
|
||||
|
||||
echo
|
||||
@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must be set
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=on"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must be set
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
|
||||
IMGOPTS="compat=1.1,lazy_refcounts=off"
|
||||
_make_test_img $size
|
||||
|
||||
old_ulimit=$(ulimit -c)
|
||||
ulimit -c 0 # do not produce a core dump on abort(3)
|
||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
|
||||
ulimit -c "$old_ulimit"
|
||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
|
||||
|
||||
# The dirty bit must not be set since lazy_refcounts=off
|
||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
|
||||
|
@ -11,6 +11,7 @@ No errors were found on the image.
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x1
|
||||
ERROR cluster 5 refcount=0 reference=1
|
||||
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
|
||||
@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x1
|
||||
Repairing cluster 5 refcount=0 reference=1
|
||||
wrote 512/512 bytes at offset 0
|
||||
@ -52,6 +54,7 @@ incompatible_features 0x0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./039: Aborted ( ulimit -c 0; exec "$@" )
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
|
||||
|
@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
|
||||
@ -24,7 +24,7 @@ QMP_VERSION
|
||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
@ -44,7 +44,7 @@ Testing:
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": "OK\r\n"}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
@ -64,14 +64,14 @@ Testing:
|
||||
QMP_VERSION
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
|
||||
|
@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
|
||||
$QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
|
||||
| _filter_qemu_io
|
||||
|
||||
_cleanup_test_img
|
||||
_use_sample_img test-disk2vhd.vhdx.bz2
|
||||
|
||||
echo
|
||||
echo "=== Verify image created by Disk2VHD can be opened ==="
|
||||
$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
|
@ -18,4 +18,11 @@ No errors were found on the image.
|
||||
=== Verify open image read-only succeeds after log replay ===
|
||||
read 18874368/18874368 bytes at offset 0
|
||||
18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Verify image created by Disk2VHD can be opened ===
|
||||
image: TEST_DIR/test-disk2vhd.vhdx
|
||||
file format: vhdx
|
||||
virtual size: 256M (268435456 bytes)
|
||||
disk size: 260M
|
||||
cluster_size: 2097152
|
||||
*** done
|
||||
|
130
tests/qemu-iotests/089
Executable file
130
tests/qemu-iotests/089
Executable file
@ -0,0 +1,130 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test case for support of JSON filenames
|
||||
#
|
||||
# Copyright (C) 2014 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=mreitz@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 file
|
||||
_supported_os Linux
|
||||
|
||||
# Using an image filename containing quotation marks will render the JSON data
|
||||
# below invalid. In that case, we have little choice but simply not to run this
|
||||
# test.
|
||||
case $TEST_IMG in
|
||||
*'"'*)
|
||||
_notrun "image filename may not contain quotation marks"
|
||||
;;
|
||||
esac
|
||||
|
||||
IMG_SIZE=64M
|
||||
|
||||
# Taken from test 072
|
||||
echo
|
||||
echo "=== Testing nested image formats ==="
|
||||
echo
|
||||
|
||||
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
|
||||
|
||||
$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
|
||||
-c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
|
||||
|
||||
$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
|
||||
|
||||
$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
|
||||
-c 'read -P 66 1024 512' "json:{
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"filename\": \"$TEST_IMG\"
|
||||
}
|
||||
}
|
||||
}" | _filter_qemu_io
|
||||
|
||||
# This should fail (see test 072)
|
||||
$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
|
||||
# Taken from test 071
|
||||
echo
|
||||
echo "=== Testing blkdebug ==="
|
||||
echo
|
||||
|
||||
_make_test_img $IMG_SIZE
|
||||
|
||||
$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
|
||||
# the same (which they should).
|
||||
$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
|
||||
\"driver\": \"$IMGFMT\",
|
||||
\"file\": {
|
||||
\"driver\": \"blkdebug\",
|
||||
\"inject-error\": [{
|
||||
\"event\": \"l2_load\"
|
||||
}],
|
||||
\"image.filename\": \"$TEST_IMG\"
|
||||
}
|
||||
}" | _filter_qemu_io
|
||||
|
||||
|
||||
echo
|
||||
echo "=== Testing qemu-img info output ==="
|
||||
echo
|
||||
|
||||
$QEMU_IMG info "json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" \
|
||||
| _filter_testdir | _filter_imgfmt
|
||||
|
||||
|
||||
echo
|
||||
echo "=== Testing option merging ==="
|
||||
echo
|
||||
|
||||
# Both options given directly and those given in the filename should be used
|
||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
|
||||
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
|
||||
# Options given directly should be prioritized over those given in the filename
|
||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
|
||||
-c "info" 2>&1 | _filter_testdir | _filter_imgfmt
|
||||
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
54
tests/qemu-iotests/089.out
Normal file
54
tests/qemu-iotests/089.out
Normal file
@ -0,0 +1,54 @@
|
||||
QA output created by 089
|
||||
|
||||
=== Testing nested image formats ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 512/512 bytes at offset 1024
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 512
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 512/512 bytes at offset 1024
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
Pattern verification failed at offset 0, 512 bytes
|
||||
read 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
|
||||
=== Testing blkdebug ===
|
||||
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 512/512 bytes at offset 229376
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read failed: Input/output error
|
||||
|
||||
=== Testing qemu-img info output ===
|
||||
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64M (67108864 bytes)
|
||||
disk size: 324K
|
||||
cluster_size: 65536
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
|
||||
=== Testing option merging ===
|
||||
|
||||
format name: IMGFMT
|
||||
cluster size: 64 KiB
|
||||
vm state offset: 512 MiB
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
format name: IMGFMT
|
||||
cluster size: 64 KiB
|
||||
vm state offset: 512 MiB
|
||||
Format specific information:
|
||||
compat: 1.1
|
||||
lazy refcounts: false
|
||||
*** done
|
98
tests/qemu-iotests/092
Executable file
98
tests/qemu-iotests/092
Executable file
@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# qcow1 format input validation tests
|
||||
#
|
||||
# Copyright (C) 2014 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=kwolf@redhat.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
rm -f $TEST_IMG.snap
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
offset_backing_file_offset=8
|
||||
offset_backing_file_size=16
|
||||
offset_size=24
|
||||
offset_cluster_bits=32
|
||||
offset_l2_bits=33
|
||||
|
||||
echo
|
||||
echo "== Invalid cluster size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid L2 table size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
|
||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid size =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Invalid backing file length =="
|
||||
_make_test_img 64M
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
|
||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
38
tests/qemu-iotests/092.out
Normal file
38
tests/qemu-iotests/092.out
Normal file
@ -0,0 +1,38 @@
|
||||
QA output created by 092
|
||||
|
||||
== Invalid cluster size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid L2 table size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid size ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Invalid backing file length ==
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
|
||||
no file open, try 'help open'
|
||||
*** done
|
@ -150,6 +150,7 @@ _filter_win32()
|
||||
_filter_qemu_io()
|
||||
{
|
||||
_filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
|
||||
-e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\)/:\1/" \
|
||||
-e "s/qemu-io> //g"
|
||||
}
|
||||
|
||||
|
@ -95,5 +95,7 @@
|
||||
086 rw auto quick
|
||||
087 rw auto
|
||||
088 rw auto
|
||||
089 rw auto quick
|
||||
090 rw auto quick
|
||||
091 rw auto
|
||||
092 rw auto quick
|
||||
|
BIN
tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Normal file
BIN
tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Normal file
Binary file not shown.
21
util/iov.c
21
util/iov.c
@ -335,6 +335,27 @@ void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the contents of the iovecs are all zero
|
||||
*/
|
||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < qiov->niov; i++) {
|
||||
size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long));
|
||||
uint8_t *ptr = qiov->iov[i].iov_base;
|
||||
if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) {
|
||||
return false;
|
||||
}
|
||||
for (; offs < qiov->iov[i].iov_len; offs++) {
|
||||
if (ptr[offs]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
Loading…
Reference in New Issue
Block a user