Block patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTYT60AAoJEH8JsnLIjy/WQIoP/2n2/YoSOgtv3IwV1YdjzmLK fAVYhkZz+ElvMuoM/Mj9k1VEYlIImCrx2Y8vwLEM0tDbRa4+J2vORAOgt4EaY2G7 OxEQoxdX380Cug94pJtupGhZmvkLPa/slnoOHoL2X1IfhD52k0xORVRPFy4nSaV0 f2zOjhPNHCE5ZOnHZshgUjtPUqglJlsBKBlWnXE0EZLBk0jbZO0oRWNEtXZRS3Tp GQQEqtG46gEuGJcJ6F1f9bDCLJ6KAdCmHMK3weY7niDSem84p35I76xfM/oGHYmb Y5CgQXDys2STXshw9mAeSUfn4QfYW9JZvQAWGrTYM/y4/hbQKsi8jfbqSYinWcjm qfBH/nEAqKGgVEmQ4jLlWIa7/Lr0WsirdZZmhBXZcgkfg6+gUP6uw+kDJprqd385 45mVu1AldLKVV4jBhAahuSLGdv8CErndGqVckVHaSPtl4XJxhZmemPJB4JAbczdM LZiQwRuVeYZC+ssQotr2ov5pzWg3n6IzFW6Zt0T7YWmluOAy9vTfm29IdUV7nxKl Ht6sm4vLLMtB3snHvLdpTOAXxTJ66J2IqpRGhIgNu71dKLjFU5IEgj5oddw38iiG sY2CA6DfWSwRmPfaVsH/F8o/T0vONQ9SrX40459UNADm81qvu70IuR8cr8b4xKXX vC9SwuNBO1upONNkX/4B =VH6g -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block patches # gpg: Signature made Wed 30 Apr 2014 19:19:32 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (31 commits) curl: Fix hang reading from slow connections curl: Ensure all informationals are checked for completion curl: Eliminate unnecessary use of curl_multi_socket_all curl: Remove unnecessary explicit calls to internal event handler curl: Remove erroneous sleep waiting for curl completion curl: Fix return from curl_read_cb with invalid state curl: Remove unnecessary use of goto curl: Fix long line block/vdi: Error out immediately in vdi_create() block/bochs: Fix error handling for seek_to_sector() qcow2: Check min_size in qcow2_grow_l1_table() qcow2: Catch bdrv_getlength() error block: Use correct width in format strings qcow2: Avoid overflow in alloc_clusters_noref() block: Use error_abort in bdrv_image_info_specific_dump() block: Fix open_flags in bdrv_reopen() Revert "block: another bdrv_append fix" block: Unlink temporary files in raw-posix/win32 block: Remove BDRV_O_COPY_ON_READ for bs->file block: Create bdrv_backing_flags() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e50bf23438
108
block.c
108
block.c
|
@ -774,6 +774,45 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
||||||
bs->copy_on_read--;
|
bs->copy_on_read--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->file should get, based on the given flags for
|
||||||
|
* the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_inherited_flags(int flags)
|
||||||
|
{
|
||||||
|
/* Enable protocol handling, disable format probing for bs->file */
|
||||||
|
flags |= BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
|
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||||
|
* so we can enable both unconditionally on lower layers. */
|
||||||
|
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
||||||
|
|
||||||
|
/* The backing file of a temporary snapshot is read-only */
|
||||||
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
|
flags &= ~BDRV_O_RDWR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear flags that only apply to the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the flags that bs->backing_hd should get, based on the given flags
|
||||||
|
* for the parent BDS
|
||||||
|
*/
|
||||||
|
static int bdrv_backing_flags(int flags)
|
||||||
|
{
|
||||||
|
/* backing files always opened read-only */
|
||||||
|
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
|
||||||
|
|
||||||
|
/* snapshot=on is handled on the top layer */
|
||||||
|
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||||
|
@ -792,7 +831,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
/*
|
/*
|
||||||
* Snapshots should be writable.
|
* Snapshots should be writable.
|
||||||
*/
|
*/
|
||||||
if (bs->is_temporary) {
|
if (flags & BDRV_O_TEMPORARY) {
|
||||||
open_flags |= BDRV_O_RDWR;
|
open_flags |= BDRV_O_RDWR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,13 +990,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||||
bdrv_refresh_limits(bs);
|
bdrv_refresh_limits(bs);
|
||||||
assert(bdrv_opt_mem_align(bs) != 0);
|
assert(bdrv_opt_mem_align(bs) != 0);
|
||||||
assert((bs->request_alignment != 0) || bs->sg);
|
assert((bs->request_alignment != 0) || bs->sg);
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
assert(bs->filename[0] != '\0');
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_and_fail:
|
free_and_fail:
|
||||||
|
@ -1069,7 +1101,7 @@ fail:
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||||
{
|
{
|
||||||
char *backing_filename = g_malloc0(PATH_MAX);
|
char *backing_filename = g_malloc0(PATH_MAX);
|
||||||
int back_flags, ret = 0;
|
int ret = 0;
|
||||||
BlockDriver *back_drv = NULL;
|
BlockDriver *back_drv = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
@ -1097,14 +1129,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||||
back_drv = bdrv_find_format(bs->backing_format);
|
back_drv = bdrv_find_format(bs->backing_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* backing files always opened read-only */
|
|
||||||
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
|
|
||||||
BDRV_O_COPY_ON_READ);
|
|
||||||
|
|
||||||
assert(bs->backing_hd == NULL);
|
assert(bs->backing_hd == NULL);
|
||||||
ret = bdrv_open(&bs->backing_hd,
|
ret = bdrv_open(&bs->backing_hd,
|
||||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||||
back_flags, back_drv, &local_err);
|
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||||
|
@ -1232,10 +1260,10 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||||
qstring_from_str(tmp_filename));
|
qstring_from_str(tmp_filename));
|
||||||
|
|
||||||
bs_snapshot = bdrv_new("", &error_abort);
|
bs_snapshot = bdrv_new("", &error_abort);
|
||||||
bs_snapshot->is_temporary = 1;
|
|
||||||
|
|
||||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||||
bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
|
(bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY,
|
||||||
|
bdrv_qcow2, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1333,10 +1361,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
|
|
||||||
assert(file == NULL);
|
assert(file == NULL);
|
||||||
ret = bdrv_open_image(&file, filename, options, "file",
|
ret = bdrv_open_image(&file, filename, options, "file",
|
||||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
|
bdrv_inherited_flags(flags),
|
||||||
BDRV_O_PROTOCOL, true, &local_err);
|
true, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the right image format driver */
|
/* Find the right image format driver */
|
||||||
|
@ -1347,7 +1375,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_setg(errp, "Invalid driver: '%s'", drvname);
|
error_setg(errp, "Invalid driver: '%s'", drvname);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1357,18 +1385,18 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Must specify either driver or file");
|
error_setg(errp, "Must specify either driver or file");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open the image */
|
/* Open the image */
|
||||||
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file && (bs->file != file)) {
|
if (file && (bs->file != file)) {
|
||||||
|
@ -1430,14 +1458,10 @@ done:
|
||||||
*pbs = bs;
|
*pbs = bs;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unlink_and_fail:
|
fail:
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
bdrv_unref(file);
|
bdrv_unref(file);
|
||||||
}
|
}
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(filename);
|
|
||||||
}
|
|
||||||
fail:
|
|
||||||
QDECREF(bs->options);
|
QDECREF(bs->options);
|
||||||
QDECREF(options);
|
QDECREF(options);
|
||||||
bs->options = NULL;
|
bs->options = NULL;
|
||||||
|
@ -1501,8 +1525,11 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||||
QSIMPLEQ_INIT(bs_queue);
|
QSIMPLEQ_INIT(bs_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* bdrv_open() masks this flag out */
|
||||||
|
flags &= ~BDRV_O_PROTOCOL;
|
||||||
|
|
||||||
if (bs->file) {
|
if (bs->file) {
|
||||||
bdrv_reopen_queue(bs_queue, bs->file, flags);
|
bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||||
|
@ -1717,11 +1744,6 @@ void bdrv_close(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
bs->drv->bdrv_close(bs);
|
bs->drv->bdrv_close(bs);
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
#ifdef _WIN32
|
|
||||||
if (bs->is_temporary) {
|
|
||||||
unlink(bs->filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
bs->copy_on_read = 0;
|
bs->copy_on_read = 0;
|
||||||
|
@ -1845,7 +1867,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||||
BlockDriverState *bs_src)
|
BlockDriverState *bs_src)
|
||||||
{
|
{
|
||||||
/* move some fields that need to stay attached to the device */
|
/* move some fields that need to stay attached to the device */
|
||||||
bs_dest->open_flags = bs_src->open_flags;
|
|
||||||
|
|
||||||
/* dev info */
|
/* dev info */
|
||||||
bs_dest->dev_ops = bs_src->dev_ops;
|
bs_dest->dev_ops = bs_src->dev_ops;
|
||||||
|
@ -3601,10 +3622,25 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriver *drv;
|
BlockDriver *drv;
|
||||||
|
int count = 0;
|
||||||
|
const char **formats = NULL;
|
||||||
|
|
||||||
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
||||||
it(opaque, drv->format_name);
|
if (drv->format_name) {
|
||||||
|
bool found = false;
|
||||||
|
int i = count;
|
||||||
|
while (formats && i && !found) {
|
||||||
|
found = !strcmp(formats[--i], drv->format_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
formats = g_realloc(formats, (count + 1) * sizeof(char *));
|
||||||
|
formats[count++] = drv->format_name;
|
||||||
|
it(opaque, drv->format_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_free(formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is to find block backend bs */
|
/* This function is to find block backend bs */
|
||||||
|
|
|
@ -187,13 +187,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
uint64_t offset = sector_num * 512;
|
uint64_t offset = sector_num * 512;
|
||||||
uint64_t extent_index, extent_offset, bitmap_offset;
|
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||||
char bitmap_entry;
|
char bitmap_entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
// seek to sector
|
// seek to sector
|
||||||
extent_index = offset / s->extent_size;
|
extent_index = offset / s->extent_size;
|
||||||
extent_offset = (offset % s->extent_size) / 512;
|
extent_offset = (offset % s->extent_size) / 512;
|
||||||
|
|
||||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_offset = s->data_offset +
|
bitmap_offset = s->data_offset +
|
||||||
|
@ -201,13 +202,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
(s->extent_blocks + s->bitmap_blocks));
|
(s->extent_blocks + s->bitmap_blocks));
|
||||||
|
|
||||||
/* read in bitmap for current extent */
|
/* read in bitmap for current extent */
|
||||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||||
&bitmap_entry, 1) != 1) {
|
&bitmap_entry, 1);
|
||||||
return -1;
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||||
return -1; /* not allocated */
|
return 0; /* not allocated */
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||||
|
@ -220,13 +222,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
while (nb_sectors > 0) {
|
||||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||||
if (block_offset >= 0) {
|
if (block_offset < 0) {
|
||||||
|
return block_offset;
|
||||||
|
} else if (block_offset > 0) {
|
||||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||||
if (ret != 512) {
|
if (ret < 0) {
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
|
}
|
||||||
nb_sectors--;
|
nb_sectors--;
|
||||||
sector_num++;
|
sector_num++;
|
||||||
buf += 512;
|
buf += 512;
|
||||||
|
|
|
@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version),
|
snprintf(version, sizeof(version),
|
||||||
"COW version %d", cow_header.version);
|
"COW version %" PRIu32, cow_header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "cow", version);
|
bs->device_name, "cow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
|
147
block/curl.c
147
block/curl.c
|
@ -71,6 +71,7 @@ typedef struct CURLState
|
||||||
struct BDRVCURLState *s;
|
struct BDRVCURLState *s;
|
||||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
|
curl_socket_t sock_fd;
|
||||||
char *orig_buf;
|
char *orig_buf;
|
||||||
size_t buf_start;
|
size_t buf_start;
|
||||||
size_t buf_off;
|
size_t buf_off;
|
||||||
|
@ -92,6 +93,7 @@ typedef struct BDRVCURLState {
|
||||||
|
|
||||||
static void curl_clean_state(CURLState *s);
|
static void curl_clean_state(CURLState *s);
|
||||||
static void curl_multi_do(void *arg);
|
static void curl_multi_do(void *arg);
|
||||||
|
static void curl_multi_read(void *arg);
|
||||||
|
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||||
|
@ -113,16 +115,20 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||||
void *s, void *sp)
|
void *s, void *sp)
|
||||||
{
|
{
|
||||||
|
CURLState *state = NULL;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||||
|
state->sock_fd = fd;
|
||||||
|
|
||||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CURL_POLL_IN:
|
case CURL_POLL_IN:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_OUT:
|
case CURL_POLL_OUT:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_INOUT:
|
case CURL_POLL_INOUT:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
|
qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_REMOVE:
|
case CURL_POLL_REMOVE:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
||||||
|
@ -155,7 +161,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||||
|
|
||||||
if (!s || !s->orig_buf)
|
if (!s || !s->orig_buf)
|
||||||
goto read_end;
|
return 0;
|
||||||
|
|
||||||
if (s->buf_off >= s->buf_len) {
|
if (s->buf_off >= s->buf_len) {
|
||||||
/* buffer full, read nothing */
|
/* buffer full, read nothing */
|
||||||
|
@ -180,7 +186,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read_end:
|
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +220,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for unfinished chunks
|
// Wait for unfinished chunks
|
||||||
if ((start >= state->buf_start) &&
|
if (state->in_use &&
|
||||||
|
(start >= state->buf_start) &&
|
||||||
(start <= buf_fend) &&
|
(start <= buf_fend) &&
|
||||||
(end >= state->buf_start) &&
|
(end >= state->buf_start) &&
|
||||||
(end <= buf_fend))
|
(end <= buf_fend))
|
||||||
|
@ -237,68 +243,69 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||||
return FIND_RET_NONE;
|
return FIND_RET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_read(BDRVCURLState *s)
|
static void curl_multi_check_completion(BDRVCURLState *s)
|
||||||
{
|
{
|
||||||
int msgs_in_queue;
|
int msgs_in_queue;
|
||||||
|
|
||||||
/* Try to find done transfers, so we can free the easy
|
/* Try to find done transfers, so we can free the easy
|
||||||
* handle again. */
|
* handle again. */
|
||||||
do {
|
for (;;) {
|
||||||
CURLMsg *msg;
|
CURLMsg *msg;
|
||||||
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
||||||
|
|
||||||
|
/* Quit when there are no more completions */
|
||||||
if (!msg)
|
if (!msg)
|
||||||
break;
|
break;
|
||||||
if (msg->msg == CURLMSG_NONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (msg->msg) {
|
if (msg->msg == CURLMSG_DONE) {
|
||||||
case CURLMSG_DONE:
|
CURLState *state = NULL;
|
||||||
{
|
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
|
||||||
CURLState *state = NULL;
|
(char **)&state);
|
||||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
|
|
||||||
|
|
||||||
/* ACBs for successful messages get completed in curl_read_cb */
|
/* ACBs for successful messages get completed in curl_read_cb */
|
||||||
if (msg->data.result != CURLE_OK) {
|
if (msg->data.result != CURLE_OK) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < CURL_NUM_ACB; i++) {
|
for (i = 0; i < CURL_NUM_ACB; i++) {
|
||||||
CURLAIOCB *acb = state->acb[i];
|
CURLAIOCB *acb = state->acb[i];
|
||||||
|
|
||||||
if (acb == NULL) {
|
if (acb == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
acb->common.cb(acb->common.opaque, -EIO);
|
|
||||||
qemu_aio_release(acb);
|
|
||||||
state->acb[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
curl_clean_state(state);
|
acb->common.cb(acb->common.opaque, -EIO);
|
||||||
break;
|
qemu_aio_release(acb);
|
||||||
|
state->acb[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
msgs_in_queue = 0;
|
curl_clean_state(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(msgs_in_queue);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_do(void *arg)
|
static void curl_multi_do(void *arg)
|
||||||
{
|
{
|
||||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
CURLState *s = (CURLState *)arg;
|
||||||
int running;
|
int running;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!s->multi) {
|
if (!s->s->multi) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = curl_multi_socket_all(s->multi, &running);
|
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||||
|
|
||||||
curl_multi_read(s);
|
}
|
||||||
|
|
||||||
|
static void curl_multi_read(void *arg)
|
||||||
|
{
|
||||||
|
CURLState *s = (CURLState *)arg;
|
||||||
|
|
||||||
|
curl_multi_do(arg);
|
||||||
|
curl_multi_check_completion(s->s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void curl_multi_timeout_do(void *arg)
|
static void curl_multi_timeout_do(void *arg)
|
||||||
|
@ -313,7 +320,7 @@ static void curl_multi_timeout_do(void *arg)
|
||||||
|
|
||||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
|
|
||||||
curl_multi_read(s);
|
curl_multi_check_completion(s);
|
||||||
#else
|
#else
|
||||||
abort();
|
abort();
|
||||||
#endif
|
#endif
|
||||||
|
@ -337,44 +344,42 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!state) {
|
if (!state) {
|
||||||
g_usleep(100);
|
qemu_aio_wait();
|
||||||
curl_multi_do(s);
|
|
||||||
}
|
}
|
||||||
} while(!state);
|
} while(!state);
|
||||||
|
|
||||||
if (state->curl)
|
if (!state->curl) {
|
||||||
goto has_curl;
|
state->curl = curl_easy_init();
|
||||||
|
if (!state->curl) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||||
|
(void *)curl_read_cb);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
||||||
|
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
||||||
|
|
||||||
state->curl = curl_easy_init();
|
/* Restrict supported protocols to avoid security issues in the more
|
||||||
if (!state->curl)
|
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
||||||
return NULL;
|
* CVE-2013-0249.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
*
|
||||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
* Restricting protocols is only supported from 7.19.4 upwards.
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
|
*/
|
||||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FOLLOWLOCATION, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_NOSIGNAL, 1);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg);
|
|
||||||
curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1);
|
|
||||||
|
|
||||||
/* Restrict supported protocols to avoid security issues in the more
|
|
||||||
* obscure protocols. For example, do not allow POP3/SMTP/IMAP see
|
|
||||||
* CVE-2013-0249.
|
|
||||||
*
|
|
||||||
* Restricting protocols is only supported from 7.19.4 upwards.
|
|
||||||
*/
|
|
||||||
#if LIBCURL_VERSION_NUM >= 0x071304
|
#if LIBCURL_VERSION_NUM >= 0x071304
|
||||||
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS);
|
||||||
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_VERBOSE
|
#ifdef DEBUG_VERBOSE
|
||||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
has_curl:
|
|
||||||
|
|
||||||
state->s = s;
|
state->s = s;
|
||||||
|
|
||||||
|
@ -531,13 +536,11 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
// initialize the multi interface!
|
// initialize the multi interface!
|
||||||
|
|
||||||
s->multi = curl_multi_init();
|
s->multi = curl_multi_init();
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||||
#endif
|
#endif
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -566,6 +569,7 @@ static const AIOCBInfo curl_aiocb_info = {
|
||||||
static void curl_readv_bh_cb(void *p)
|
static void curl_readv_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
CURLState *state;
|
CURLState *state;
|
||||||
|
int running;
|
||||||
|
|
||||||
CURLAIOCB *acb = p;
|
CURLAIOCB *acb = p;
|
||||||
BDRVCURLState *s = acb->common.bs->opaque;
|
BDRVCURLState *s = acb->common.bs->opaque;
|
||||||
|
@ -614,8 +618,9 @@ static void curl_readv_bh_cb(void *p)
|
||||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||||
|
|
||||||
curl_multi_add_handle(s->multi, state->curl);
|
curl_multi_add_handle(s->multi, state->curl);
|
||||||
curl_multi_do(s);
|
|
||||||
|
|
||||||
|
/* Tell curl it needs to kick things off */
|
||||||
|
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||||
|
|
|
@ -248,8 +248,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||||
error_report("sector count %" PRIu64 " for chunk %u is "
|
error_report("sector count %" PRIu64 " for chunk %" PRIu32
|
||||||
"larger than max (%u)",
|
" is larger than max (%u)",
|
||||||
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -269,8 +269,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
||||||
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||||
error_report("length %" PRIu64 " for chunk %u is larger "
|
error_report("length %" PRIu64 " for chunk %" PRIu32
|
||||||
"than max (%u)",
|
" is larger than max (%u)",
|
||||||
s->lengths[i], i, DMG_LENGTHS_MAX);
|
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -325,11 +325,11 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||||
|
|
||||||
s->common.len = bdrv_getlength(bs);
|
s->common.len = bdrv_getlength(bs);
|
||||||
if (s->common.len <= 0) {
|
if (s->common.len <= 0) {
|
||||||
block_job_completed(&s->common, s->common.len);
|
ret = s->common.len;
|
||||||
return;
|
goto immediate_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
|
length = DIV_ROUND_UP(s->common.len, s->granularity);
|
||||||
s->in_flight_bitmap = bitmap_new(length);
|
s->in_flight_bitmap = bitmap_new(length);
|
||||||
|
|
||||||
/* If we have no backing file yet in the destination, we cannot let
|
/* If we have no backing file yet in the destination, we cannot let
|
||||||
|
@ -339,7 +339,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||||
bdrv_get_backing_filename(s->target, backing_filename,
|
bdrv_get_backing_filename(s->target, backing_filename,
|
||||||
sizeof(backing_filename));
|
sizeof(backing_filename));
|
||||||
if (backing_filename[0] && !s->target->backing_hd) {
|
if (backing_filename[0] && !s->target->backing_hd) {
|
||||||
bdrv_get_info(s->target, &bdi);
|
ret = bdrv_get_info(s->target, &bdi);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto immediate_exit;
|
||||||
|
}
|
||||||
if (s->granularity < bdi.cluster_size) {
|
if (s->granularity < bdi.cluster_size) {
|
||||||
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
||||||
s->cow_bitmap = bitmap_new(length);
|
s->cow_bitmap = bitmap_new(length);
|
||||||
|
|
|
@ -532,12 +532,11 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
||||||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||||
ImageInfoSpecific *info_spec)
|
ImageInfoSpecific *info_spec)
|
||||||
{
|
{
|
||||||
Error *local_err = NULL;
|
|
||||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||||
QObject *obj, *data;
|
QObject *obj, *data;
|
||||||
|
|
||||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
||||||
&local_err);
|
&error_abort);
|
||||||
obj = qmp_output_get_qobject(ov);
|
obj = qmp_output_get_qobject(ov);
|
||||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||||
|
|
|
@ -119,7 +119,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
}
|
}
|
||||||
if (header.version != QCOW_VERSION) {
|
if (header.version != QCOW_VERSION) {
|
||||||
char version[64];
|
char version[64];
|
||||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||||
|
header.version);
|
||||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
bs->device_name, "qcow", version);
|
bs->device_name, "qcow", version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
|
|
@ -42,6 +42,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||||
if (min_size <= s->l1_size)
|
if (min_size <= s->l1_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Do a sanity check on min_size before trying to calculate new_l1_size
|
||||||
|
* (this prevents overflows during the while loop for the calculation of
|
||||||
|
* new_l1_size) */
|
||||||
|
if (min_size > INT_MAX / sizeof(uint64_t)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
if (exact_size) {
|
if (exact_size) {
|
||||||
new_l1_size = min_size;
|
new_l1_size = min_size;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1360,9 +1367,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
|
||||||
for (i = 0; i < nb_clusters; i++) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
uint64_t old_offset;
|
uint64_t old_l2_entry;
|
||||||
|
|
||||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||||
|
@ -1373,12 +1380,22 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||||
* holding s->lock, so that doesn't work today.
|
* holding s->lock, so that doesn't work today.
|
||||||
*/
|
*/
|
||||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
switch (qcow2_get_cluster_type(old_l2_entry)) {
|
||||||
continue;
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
}
|
if (!bs->backing_hd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
case QCOW2_CLUSTER_ZERO:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First remove L2 entries */
|
/* First remove L2 entries */
|
||||||
|
@ -1390,7 +1407,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then decrease the refcount */
|
/* Then decrease the refcount */
|
||||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
|
|
@ -653,6 +653,13 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure that all offsets in the "allocated" range are representable
|
||||||
|
* in an int64_t */
|
||||||
|
if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) {
|
||||||
|
return -EFBIG;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC2
|
#ifdef DEBUG_ALLOC2
|
||||||
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||||
size,
|
size,
|
||||||
|
@ -1480,6 +1487,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size = bdrv_getlength(bs->file);
|
size = bdrv_getlength(bs->file);
|
||||||
|
if (size < 0) {
|
||||||
|
res->check_errors++;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
nb_clusters = size_to_clusters(s, size);
|
nb_clusters = size_to_clusters(s, size);
|
||||||
if (nb_clusters > INT_MAX) {
|
if (nb_clusters > INT_MAX) {
|
||||||
res->check_errors++;
|
res->check_errors++;
|
||||||
|
|
|
@ -124,8 +124,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||||
|
|
||||||
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
||||||
if (ext.len >= sizeof(bs->backing_format)) {
|
if (ext.len >= sizeof(bs->backing_format)) {
|
||||||
error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
|
error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
|
||||||
" (>=%zu)", ext.len, sizeof(bs->backing_format));
|
" too large (>=%zu)", ext.len,
|
||||||
|
sizeof(bs->backing_format));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||||
|
@ -483,7 +484,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (header.version < 2 || header.version > 3) {
|
if (header.version < 2 || header.version > 3) {
|
||||||
report_unsupported(bs, errp, "QCOW version %d", header.version);
|
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -493,7 +494,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
/* Initialise cluster size */
|
/* Initialise cluster size */
|
||||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
|
||||||
|
header.cluster_bits);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +593,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
s->refcount_order = header.refcount_order;
|
s->refcount_order = header.refcount_order;
|
||||||
|
|
||||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||||
error_setg(errp, "Unsupported encryption method: %i",
|
error_setg(errp, "Unsupported encryption method: %" PRIu32,
|
||||||
header.crypt_method);
|
header.crypt_method);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -366,7 +366,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename = NULL;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
@ -446,6 +446,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
|
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||||
|
unlink(filename);
|
||||||
|
}
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,9 @@ static void raw_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
CloseHandle(s->hfile);
|
CloseHandle(s->hfile);
|
||||||
|
if (bs->open_flags & BDRV_O_TEMPORARY) {
|
||||||
|
unlink(bs->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
|
|
|
@ -1099,7 +1099,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsp->result != SD_RES_SUCCESS) {
|
if (rsp->result != SD_RES_SUCCESS) {
|
||||||
error_report("cannot get vdi info, %s, %s %d %s",
|
error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||||
sd_strerror(rsp->result), filename, snapid, tag);
|
sd_strerror(rsp->result), filename, snapid, tag);
|
||||||
if (rsp->result == SD_RES_NO_VDI) {
|
if (rsp->result == SD_RES_NO_VDI) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
|
@ -2316,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||||
sn_tab[found].vm_state_size = inode.vm_state_size;
|
sn_tab[found].vm_state_size = inode.vm_state_size;
|
||||||
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
||||||
|
|
||||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
|
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
|
||||||
inode.snap_id);
|
"%" PRIu32, inode.snap_id);
|
||||||
pstrcpy(sn_tab[found].name,
|
pstrcpy(sn_tab[found].name,
|
||||||
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
||||||
inode.tag);
|
inode.tag);
|
||||||
|
|
28
block/vdi.c
28
block/vdi.c
|
@ -408,34 +408,35 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.signature != VDI_SIGNATURE) {
|
if (header.signature != VDI_SIGNATURE) {
|
||||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
|
||||||
|
")", header.signature);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.version != VDI_VERSION_1_1) {
|
} else if (header.version != VDI_VERSION_1_1) {
|
||||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
|
||||||
header.version >> 16, header.version & 0xffff);
|
")", header.version >> 16, header.version & 0xffff);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||||
/* We only support block maps which start on a sector boundary. */
|
/* We only support block maps which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||||
"0x%x)", header.offset_bmap);
|
"0x%" PRIx32 ")", header.offset_bmap);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||||
/* We only support data blocks which start on a sector boundary. */
|
/* We only support data blocks which start on a sector boundary. */
|
||||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
|
||||||
header.offset_data);
|
PRIx32 ")", header.offset_data);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.sector_size != SECTOR_SIZE) {
|
} else if (header.sector_size != SECTOR_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
|
||||||
header.sector_size, SECTOR_SIZE);
|
" is not %u)", header.sector_size, SECTOR_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||||
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
error_setg(errp, "unsupported VDI image (block size %" PRIu32
|
||||||
header.block_size, DEFAULT_CLUSTER_SIZE);
|
" is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (header.disk_size >
|
} else if (header.disk_size >
|
||||||
|
@ -755,6 +756,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||||
vdi_header_to_le(&header);
|
vdi_header_to_le(&header);
|
||||||
if (write(fd, &header, sizeof(header)) < 0) {
|
if (write(fd, &header, sizeof(header)) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bmap_size > 0) {
|
if (bmap_size > 0) {
|
||||||
|
@ -768,6 +770,8 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||||
}
|
}
|
||||||
if (write(fd, bmap, bmap_size) < 0) {
|
if (write(fd, bmap, bmap_size) < 0) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
g_free(bmap);
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
g_free(bmap);
|
g_free(bmap);
|
||||||
}
|
}
|
||||||
|
@ -775,10 +779,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||||
if (image_type == VDI_TYPE_STATIC) {
|
if (image_type == VDI_TYPE_STATIC) {
|
||||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
|
goto close_and_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(fd) < 0) {
|
close_and_exit:
|
||||||
|
if ((close(fd) < 0) && !result) {
|
||||||
result = -errno;
|
result = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ typedef enum {
|
||||||
|
|
||||||
#define BDRV_O_RDWR 0x0002
|
#define BDRV_O_RDWR 0x0002
|
||||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||||
|
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
|
||||||
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
||||||
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
|
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
|
||||||
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
|
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
|
||||||
|
|
|
@ -299,7 +299,6 @@ struct BlockDriverState {
|
||||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||||
this file image */
|
this file image */
|
||||||
char backing_format[16]; /* if non-zero and backing_file exists */
|
char backing_format[16]; /* if non-zero and backing_file exists */
|
||||||
int is_temporary;
|
|
||||||
|
|
||||||
BlockDriverState *backing_hd;
|
BlockDriverState *backing_hd;
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
|
|
26
qemu-img.c
26
qemu-img.c
|
@ -33,6 +33,9 @@
|
||||||
#include "block/qapi.h"
|
#include "block/qapi.h"
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \
|
||||||
|
", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
||||||
|
|
||||||
typedef struct img_cmd_t {
|
typedef struct img_cmd_t {
|
||||||
const char *name;
|
const char *name;
|
||||||
int (*handler)(int argc, char **argv);
|
int (*handler)(int argc, char **argv);
|
||||||
|
@ -75,7 +78,7 @@ static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
||||||
static void QEMU_NORETURN help(void)
|
static void QEMU_NORETURN help(void)
|
||||||
{
|
{
|
||||||
const char *help_msg =
|
const char *help_msg =
|
||||||
"qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
QEMU_IMG_VERSION
|
||||||
"usage: qemu-img command [command options]\n"
|
"usage: qemu-img command [command options]\n"
|
||||||
"QEMU disk image utility\n"
|
"QEMU disk image utility\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -2789,6 +2792,12 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const img_cmd_t *cmd;
|
const img_cmd_t *cmd;
|
||||||
const char *cmdname;
|
const char *cmdname;
|
||||||
|
int c;
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_POSIX
|
#ifdef CONFIG_POSIX
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
@ -2803,15 +2812,24 @@ int main(int argc, char **argv)
|
||||||
error_exit("Not enough arguments");
|
error_exit("Not enough arguments");
|
||||||
}
|
}
|
||||||
cmdname = argv[1];
|
cmdname = argv[1];
|
||||||
argc--; argv++;
|
|
||||||
|
|
||||||
/* find the command */
|
/* find the command */
|
||||||
for(cmd = img_cmds; cmd->name != NULL; cmd++) {
|
for (cmd = img_cmds; cmd->name != NULL; cmd++) {
|
||||||
if (!strcmp(cmdname, cmd->name)) {
|
if (!strcmp(cmdname, cmd->name)) {
|
||||||
return cmd->handler(argc, argv);
|
return cmd->handler(argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c = getopt_long(argc, argv, "h", long_options, NULL);
|
||||||
|
|
||||||
|
if (c == 'h') {
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
if (c == 'v') {
|
||||||
|
printf(QEMU_IMG_VERSION);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* not found */
|
/* not found */
|
||||||
error_exit("Command not found: %s", cmdname);
|
error_exit("Command not found: %s", cmdname);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ mv "$TEST_IMG" "$TEST_IMG.orig"
|
||||||
for backing_option in "-B " "-o backing_file="; do
|
for backing_option in "-B " "-o backing_file="; do
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo Testing conversion with $backing_option$TEST_IMG.base | _filter_testdir | _filter_imgfmt
|
echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt
|
||||||
echo
|
echo
|
||||||
$QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG"
|
$QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG"
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,10 @@ function run_qemu_img()
|
||||||
size=128M
|
size=128M
|
||||||
|
|
||||||
_make_test_img $size
|
_make_test_img $size
|
||||||
$QEMU_IO -c 'write 0 1M' $TEST_IMG | _filter_qemu_io
|
$QEMU_IO -c 'write 0 1M' "$TEST_IMG" | _filter_qemu_io
|
||||||
$QEMU_IO -c 'write 2M 1M' $TEST_IMG | _filter_qemu_io
|
$QEMU_IO -c 'write 2M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||||
$QEMU_IO -c 'write 4M 1M' $TEST_IMG | _filter_qemu_io
|
$QEMU_IO -c 'write 4M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||||
$QEMU_IO -c 'write 32M 1M' $TEST_IMG | _filter_qemu_io
|
$QEMU_IO -c 'write 32M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
$QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\
|
$QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\
|
||||||
_filter_testdir | sed -e 's/\r/\n/g'
|
_filter_testdir | sed -e 's/\r/\n/g'
|
||||||
|
|
61
tests/qemu-iotests/090
Executable file
61
tests/qemu-iotests/090
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test for discarding compressed clusters on qcow2 images
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
IMG_SIZE=128K
|
||||||
|
|
||||||
|
_make_test_img $IMG_SIZE
|
||||||
|
|
||||||
|
$QEMU_IO -c 'write -c -P 42 0 64k' \
|
||||||
|
-c 'write -c -P 23 64k 64k' \
|
||||||
|
-c 'discard 64k 64k' \
|
||||||
|
"$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
$QEMU_IO -c 'read -P 0 64k 64k' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
12
tests/qemu-iotests/090.out
Normal file
12
tests/qemu-iotests/090.out
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
QA output created by 090
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
|
||||||
|
wrote 65536/65536 bytes at offset 0
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 65536/65536 bytes at offset 65536
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
discard 65536/65536 bytes at offset 65536
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 65536/65536 bytes at offset 65536
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
*** done
|
|
@ -178,10 +178,10 @@ _rm_test_img()
|
||||||
local img=$1
|
local img=$1
|
||||||
if [ "$IMGFMT" = "vmdk" ]; then
|
if [ "$IMGFMT" = "vmdk" ]; then
|
||||||
# Remove all the extents for vmdk
|
# Remove all the extents for vmdk
|
||||||
$QEMU_IMG info $img 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
|
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
|
||||||
| xargs -I {} rm -f "{}"
|
| xargs -I {} rm -f "{}"
|
||||||
fi
|
fi
|
||||||
rm -f $img
|
rm -f "$img"
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_test_img()
|
_cleanup_test_img()
|
||||||
|
|
|
@ -95,3 +95,4 @@
|
||||||
086 rw auto quick
|
086 rw auto quick
|
||||||
087 rw auto
|
087 rw auto
|
||||||
088 rw auto
|
088 rw auto
|
||||||
|
090 rw auto quick
|
||||||
|
|
Loading…
Reference in a new issue