Merge remote-tracking branch 'stefanha/block' into staging
# By Paolo Bonzini (17) and others # Via Stefan Hajnoczi * stefanha/block: (48 commits) qemu-iotests: filter QEMU monitor \r\n aio: make aio_poll(ctx, true) block with no fds block: clean up bdrv_drain_all() throttling comments qcow2: use start_of_cluster() and offset_into_cluster() everywhere qemu-img: decrease progress update interval on convert qemu-img: round down request length to an aligned sector qemu-img: dynamically adjust iobuffer size during convert block/iscsi: set bs->bl.opt_transfer_length block: add opt_transfer_length to BlockLimits block/iscsi: set bdi->cluster_size qemu-img: fix usage instruction for qemu-img convert qemu-img: add support for skipping zeroes in input during convert qemu-nbd: add doc for option -f qemu-iotests: add test for snapshot in qemu-img convert qemu-img: add -l for snapshot in convert qemu-iotests: add 058 internal snapshot export with qemu-nbd case qemu-nbd: support internal snapshot export snapshot: distinguish id and name in load_tmp qemu-iotests: Split qcow2 only cases in 048 qemu-iotests: Clean up spaces in usage output ... Message-id: 1386347807-27359-1-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori <aliguori@amazon.com>
This commit is contained in:
commit
93531372f0
@ -217,11 +217,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
|
|
||||||
ctx->walking_handlers--;
|
ctx->walking_handlers--;
|
||||||
|
|
||||||
/* early return if we only have the aio_notify() fd */
|
|
||||||
if (ctx->pollfds->len == 1) {
|
|
||||||
return progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait until next event */
|
/* wait until next event */
|
||||||
ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
|
ret = qemu_poll_ns((GPollFD *)ctx->pollfds->data,
|
||||||
ctx->pollfds->len,
|
ctx->pollfds->len,
|
||||||
|
@ -161,11 +161,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
|||||||
|
|
||||||
ctx->walking_handlers--;
|
ctx->walking_handlers--;
|
||||||
|
|
||||||
/* early return if we only have the aio_notify() fd */
|
|
||||||
if (count == 1) {
|
|
||||||
return progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait until next event */
|
/* wait until next event */
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
int ret;
|
int ret;
|
||||||
|
176
block.c
176
block.c
@ -79,6 +79,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
QEMUIOVector *qiov,
|
QEMUIOVector *qiov,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
|
BdrvRequestFlags flags,
|
||||||
BlockDriverCompletionFunc *cb,
|
BlockDriverCompletionFunc *cb,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
bool is_write);
|
bool is_write);
|
||||||
@ -1556,13 +1557,8 @@ void bdrv_drain_all(void)
|
|||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
|
||||||
while (busy) {
|
while (busy) {
|
||||||
/* FIXME: We do not have timer support here, so this is effectively
|
|
||||||
* a busy wait.
|
|
||||||
*/
|
|
||||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||||
if (bdrv_start_throttled_reqs(bs)) {
|
bdrv_start_throttled_reqs(bs);
|
||||||
busy = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
busy = bdrv_requests_pending_all();
|
busy = bdrv_requests_pending_all();
|
||||||
@ -2770,14 +2766,21 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
|||||||
while (nb_sectors > 0 && !ret) {
|
while (nb_sectors > 0 && !ret) {
|
||||||
int num = nb_sectors;
|
int num = nb_sectors;
|
||||||
|
|
||||||
/* align request */
|
/* Align request. Block drivers can expect the "bulk" of the request
|
||||||
if (bs->bl.write_zeroes_alignment &&
|
* to be aligned.
|
||||||
num >= bs->bl.write_zeroes_alignment &&
|
*/
|
||||||
sector_num % bs->bl.write_zeroes_alignment) {
|
if (bs->bl.write_zeroes_alignment
|
||||||
if (num > bs->bl.write_zeroes_alignment) {
|
&& num > bs->bl.write_zeroes_alignment) {
|
||||||
|
if (sector_num % bs->bl.write_zeroes_alignment != 0) {
|
||||||
|
/* Make a small request up to the first aligned sector. */
|
||||||
num = bs->bl.write_zeroes_alignment;
|
num = bs->bl.write_zeroes_alignment;
|
||||||
|
num -= sector_num % bs->bl.write_zeroes_alignment;
|
||||||
|
} else if ((sector_num + num) % bs->bl.write_zeroes_alignment != 0) {
|
||||||
|
/* Shorten the request to the last aligned sector. num cannot
|
||||||
|
* underflow because num > bs->bl.write_zeroes_alignment.
|
||||||
|
*/
|
||||||
|
num -= (sector_num + num) % bs->bl.write_zeroes_alignment;
|
||||||
}
|
}
|
||||||
num -= sector_num % bs->bl.write_zeroes_alignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* limit request size */
|
/* limit request size */
|
||||||
@ -2795,16 +2798,20 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
|||||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||||
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
iov.iov_len = num * BDRV_SECTOR_SIZE;
|
||||||
if (iov.iov_base == NULL) {
|
if (iov.iov_base == NULL) {
|
||||||
/* allocate bounce buffer only once and ensure that it
|
iov.iov_base = qemu_blockalign(bs, num * BDRV_SECTOR_SIZE);
|
||||||
* is big enough for this and all future requests.
|
memset(iov.iov_base, 0, num * BDRV_SECTOR_SIZE);
|
||||||
*/
|
|
||||||
size_t bufsize = num <= nb_sectors ? num : max_write_zeroes;
|
|
||||||
iov.iov_base = qemu_blockalign(bs, bufsize * BDRV_SECTOR_SIZE);
|
|
||||||
memset(iov.iov_base, 0, bufsize * BDRV_SECTOR_SIZE);
|
|
||||||
}
|
}
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
|
|
||||||
ret = drv->bdrv_co_writev(bs, sector_num, num, &qiov);
|
ret = drv->bdrv_co_writev(bs, sector_num, num, &qiov);
|
||||||
|
|
||||||
|
/* Keep bounce buffer around if it is big enough for all
|
||||||
|
* all future requests.
|
||||||
|
*/
|
||||||
|
if (num < max_write_zeroes) {
|
||||||
|
qemu_vfree(iov.iov_base);
|
||||||
|
iov.iov_base = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sector_num += num;
|
sector_num += num;
|
||||||
@ -2887,7 +2894,7 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
|
|||||||
int64_t sector_num, int nb_sectors,
|
int64_t sector_num, int nb_sectors,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
|
trace_bdrv_co_write_zeroes(bs, sector_num, nb_sectors, flags);
|
||||||
|
|
||||||
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||||
@ -3669,7 +3676,7 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
{
|
{
|
||||||
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
||||||
cb, opaque, false);
|
cb, opaque, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3679,7 +3686,18 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
{
|
{
|
||||||
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, 0,
|
||||||
|
cb, opaque, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
|
{
|
||||||
|
trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque);
|
||||||
|
|
||||||
|
return bdrv_co_aio_rw_vector(bs, sector_num, NULL, nb_sectors,
|
||||||
|
BDRV_REQ_ZERO_WRITE | flags,
|
||||||
cb, opaque, true);
|
cb, opaque, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3851,8 +3869,10 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
|||||||
/* Run the aio requests. */
|
/* Run the aio requests. */
|
||||||
mcb->num_requests = num_reqs;
|
mcb->num_requests = num_reqs;
|
||||||
for (i = 0; i < num_reqs; i++) {
|
for (i = 0; i < num_reqs; i++) {
|
||||||
bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
|
bdrv_co_aio_rw_vector(bs, reqs[i].sector, reqs[i].qiov,
|
||||||
reqs[i].nb_sectors, multiwrite_cb, mcb);
|
reqs[i].nb_sectors, reqs[i].flags,
|
||||||
|
multiwrite_cb, mcb,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -3994,10 +4014,10 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
|||||||
|
|
||||||
if (!acb->is_write) {
|
if (!acb->is_write) {
|
||||||
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
|
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
|
||||||
acb->req.nb_sectors, acb->req.qiov, 0);
|
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||||
} else {
|
} else {
|
||||||
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
|
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
|
||||||
acb->req.nb_sectors, acb->req.qiov, 0);
|
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
|
acb->bh = qemu_bh_new(bdrv_co_em_bh, acb);
|
||||||
@ -4008,6 +4028,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||||||
int64_t sector_num,
|
int64_t sector_num,
|
||||||
QEMUIOVector *qiov,
|
QEMUIOVector *qiov,
|
||||||
int nb_sectors,
|
int nb_sectors,
|
||||||
|
BdrvRequestFlags flags,
|
||||||
BlockDriverCompletionFunc *cb,
|
BlockDriverCompletionFunc *cb,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
bool is_write)
|
bool is_write)
|
||||||
@ -4019,6 +4040,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
|||||||
acb->req.sector = sector_num;
|
acb->req.sector = sector_num;
|
||||||
acb->req.nb_sectors = nb_sectors;
|
acb->req.nb_sectors = nb_sectors;
|
||||||
acb->req.qiov = qiov;
|
acb->req.qiov = qiov;
|
||||||
|
acb->req.flags = flags;
|
||||||
acb->is_write = is_write;
|
acb->is_write = is_write;
|
||||||
acb->done = NULL;
|
acb->done = NULL;
|
||||||
|
|
||||||
@ -4302,6 +4324,8 @@ static void coroutine_fn bdrv_discard_co_entry(void *opaque)
|
|||||||
int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors)
|
int nb_sectors)
|
||||||
{
|
{
|
||||||
|
int max_discard;
|
||||||
|
|
||||||
if (!bs->drv) {
|
if (!bs->drv) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
} else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
|
} else if (bdrv_check_request(bs, sector_num, nb_sectors)) {
|
||||||
@ -4317,55 +4341,55 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bs->drv->bdrv_co_discard) {
|
if (!bs->drv->bdrv_co_discard && !bs->drv->bdrv_aio_discard) {
|
||||||
int max_discard = bs->bl.max_discard ?
|
|
||||||
bs->bl.max_discard : MAX_DISCARD_DEFAULT;
|
|
||||||
|
|
||||||
while (nb_sectors > 0) {
|
|
||||||
int ret;
|
|
||||||
int num = nb_sectors;
|
|
||||||
|
|
||||||
/* align request */
|
|
||||||
if (bs->bl.discard_alignment &&
|
|
||||||
num >= bs->bl.discard_alignment &&
|
|
||||||
sector_num % bs->bl.discard_alignment) {
|
|
||||||
if (num > bs->bl.discard_alignment) {
|
|
||||||
num = bs->bl.discard_alignment;
|
|
||||||
}
|
|
||||||
num -= sector_num % bs->bl.discard_alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* limit request size */
|
|
||||||
if (num > max_discard) {
|
|
||||||
num = max_discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bs->drv->bdrv_co_discard(bs, sector_num, num);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
sector_num += num;
|
|
||||||
nb_sectors -= num;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else if (bs->drv->bdrv_aio_discard) {
|
|
||||||
BlockDriverAIOCB *acb;
|
|
||||||
CoroutineIOCompletion co = {
|
|
||||||
.coroutine = qemu_coroutine_self(),
|
|
||||||
};
|
|
||||||
|
|
||||||
acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
|
|
||||||
bdrv_co_io_em_complete, &co);
|
|
||||||
if (acb == NULL) {
|
|
||||||
return -EIO;
|
|
||||||
} else {
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
return co.ret;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
max_discard = bs->bl.max_discard ? bs->bl.max_discard : MAX_DISCARD_DEFAULT;
|
||||||
|
while (nb_sectors > 0) {
|
||||||
|
int ret;
|
||||||
|
int num = nb_sectors;
|
||||||
|
|
||||||
|
/* align request */
|
||||||
|
if (bs->bl.discard_alignment &&
|
||||||
|
num >= bs->bl.discard_alignment &&
|
||||||
|
sector_num % bs->bl.discard_alignment) {
|
||||||
|
if (num > bs->bl.discard_alignment) {
|
||||||
|
num = bs->bl.discard_alignment;
|
||||||
|
}
|
||||||
|
num -= sector_num % bs->bl.discard_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* limit request size */
|
||||||
|
if (num > max_discard) {
|
||||||
|
num = max_discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->drv->bdrv_co_discard) {
|
||||||
|
ret = bs->drv->bdrv_co_discard(bs, sector_num, num);
|
||||||
|
} else {
|
||||||
|
BlockDriverAIOCB *acb;
|
||||||
|
CoroutineIOCompletion co = {
|
||||||
|
.coroutine = qemu_coroutine_self(),
|
||||||
|
};
|
||||||
|
|
||||||
|
acb = bs->drv->bdrv_aio_discard(bs, sector_num, nb_sectors,
|
||||||
|
bdrv_co_io_em_complete, &co);
|
||||||
|
if (acb == NULL) {
|
||||||
|
return -EIO;
|
||||||
|
} else {
|
||||||
|
qemu_coroutine_yield();
|
||||||
|
ret = co.ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret && ret != -ENOTSUP) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sector_num += num;
|
||||||
|
nb_sectors -= num;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
|
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
|
||||||
@ -4684,7 +4708,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
{
|
{
|
||||||
QEMUOptionParameter *param = NULL, *create_options = NULL;
|
QEMUOptionParameter *param = NULL, *create_options = NULL;
|
||||||
QEMUOptionParameter *backing_fmt, *backing_file, *size;
|
QEMUOptionParameter *backing_fmt, *backing_file, *size;
|
||||||
BlockDriverState *bs = NULL;
|
|
||||||
BlockDriver *drv, *proto_drv;
|
BlockDriver *drv, *proto_drv;
|
||||||
BlockDriver *backing_drv = NULL;
|
BlockDriver *backing_drv = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
@ -4763,6 +4786,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
size = get_option_parameter(param, BLOCK_OPT_SIZE);
|
size = get_option_parameter(param, BLOCK_OPT_SIZE);
|
||||||
if (size && size->value.n == -1) {
|
if (size && size->value.n == -1) {
|
||||||
if (backing_file && backing_file->value.s) {
|
if (backing_file && backing_file->value.s) {
|
||||||
|
BlockDriverState *bs;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int back_flags;
|
int back_flags;
|
||||||
@ -4781,6 +4805,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
error_free(local_err);
|
error_free(local_err);
|
||||||
local_err = NULL;
|
local_err = NULL;
|
||||||
|
bdrv_unref(bs);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bdrv_get_geometry(bs, &size);
|
bdrv_get_geometry(bs, &size);
|
||||||
@ -4788,6 +4813,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%" PRId64, size);
|
snprintf(buf, sizeof(buf), "%" PRId64, size);
|
||||||
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
|
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
|
||||||
|
|
||||||
|
bdrv_unref(bs);
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "Image creation needs a size parameter");
|
error_setg(errp, "Image creation needs a size parameter");
|
||||||
goto out;
|
goto out;
|
||||||
@ -4818,9 +4845,6 @@ out:
|
|||||||
free_option_parameters(create_options);
|
free_option_parameters(create_options);
|
||||||
free_option_parameters(param);
|
free_option_parameters(param);
|
||||||
|
|
||||||
if (bs) {
|
|
||||||
bdrv_unref(bs);
|
|
||||||
}
|
|
||||||
if (error_is_set(&local_err)) {
|
if (error_is_set(&local_err)) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* QEMU Block driver for iSCSI images
|
* QEMU Block driver for iSCSI images
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||||
|
* Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -54,6 +55,7 @@ typedef struct IscsiLun {
|
|||||||
QEMUTimer *nop_timer;
|
QEMUTimer *nop_timer;
|
||||||
uint8_t lbpme;
|
uint8_t lbpme;
|
||||||
uint8_t lbprz;
|
uint8_t lbprz;
|
||||||
|
uint8_t has_write_same;
|
||||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||||
struct scsi_inquiry_block_limits bl;
|
struct scsi_inquiry_block_limits bl;
|
||||||
unsigned char *zeroblock;
|
unsigned char *zeroblock;
|
||||||
@ -975,8 +977,13 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iscsilun->lbp.lbpws) {
|
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||||
/* WRITE SAME is not supported by the target */
|
/* WRITE SAME without UNMAP is not supported by the target */
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||||
|
/* WRITE SAME with UNMAP is not supported by the target */
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,6 +1018,14 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||||
|
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
|
||||||
|
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
|
||||||
|
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
|
||||||
|
/* WRITE SAME is not supported by the target */
|
||||||
|
iscsilun->has_write_same = false;
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1374,6 +1389,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
iscsilun->type = inq->periperal_device_type;
|
iscsilun->type = inq->periperal_device_type;
|
||||||
|
iscsilun->has_write_same = true;
|
||||||
|
|
||||||
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) {
|
||||||
goto out;
|
goto out;
|
||||||
@ -1441,6 +1457,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||||
iscsilun);
|
iscsilun);
|
||||||
|
|
||||||
|
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
||||||
|
iscsilun);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||||
@ -1505,11 +1524,6 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iscsi_has_zero_init(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
static int iscsi_create(const char *filename, QEMUOptionParameter *options,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -1569,6 +1583,13 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||||
|
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||||
|
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||||
|
* reasonable size for bdi->cluster_size */
|
||||||
|
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
||||||
|
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||||
|
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1608,8 +1629,6 @@ static BlockDriver bdrv_iscsi = {
|
|||||||
.bdrv_aio_writev = iscsi_aio_writev,
|
.bdrv_aio_writev = iscsi_aio_writev,
|
||||||
.bdrv_aio_flush = iscsi_aio_flush,
|
.bdrv_aio_flush = iscsi_aio_flush,
|
||||||
|
|
||||||
.bdrv_has_zero_init = iscsi_has_zero_init,
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
.bdrv_ioctl = iscsi_ioctl,
|
.bdrv_ioctl = iscsi_ioctl,
|
||||||
.bdrv_aio_ioctl = iscsi_aio_ioctl,
|
.bdrv_aio_ioctl = iscsi_aio_ioctl,
|
||||||
|
@ -1401,7 +1401,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
|||||||
|
|
||||||
/* Round start up and end down */
|
/* Round start up and end down */
|
||||||
offset = align_offset(offset, s->cluster_size);
|
offset = align_offset(offset, s->cluster_size);
|
||||||
end_offset &= ~(s->cluster_size - 1);
|
end_offset = start_of_cluster(s, end_offset);
|
||||||
|
|
||||||
if (offset > end_offset) {
|
if (offset > end_offset) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -515,8 +515,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
|||||||
s->l2_table_cache);
|
s->l2_table_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
start = offset & ~(s->cluster_size - 1);
|
start = start_of_cluster(s, offset);
|
||||||
last = (offset + length - 1) & ~(s->cluster_size - 1);
|
last = start_of_cluster(s, offset + length - 1);
|
||||||
for(cluster_offset = start; cluster_offset <= last;
|
for(cluster_offset = start; cluster_offset <= last;
|
||||||
cluster_offset += s->cluster_size)
|
cluster_offset += s->cluster_size)
|
||||||
{
|
{
|
||||||
@ -724,7 +724,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
}
|
}
|
||||||
redo:
|
redo:
|
||||||
free_in_cluster = s->cluster_size -
|
free_in_cluster = s->cluster_size -
|
||||||
(s->free_byte_offset & (s->cluster_size - 1));
|
offset_into_cluster(s, s->free_byte_offset);
|
||||||
if (size <= free_in_cluster) {
|
if (size <= free_in_cluster) {
|
||||||
/* enough space in current cluster */
|
/* enough space in current cluster */
|
||||||
offset = s->free_byte_offset;
|
offset = s->free_byte_offset;
|
||||||
@ -732,7 +732,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
free_in_cluster -= size;
|
free_in_cluster -= size;
|
||||||
if (free_in_cluster == 0)
|
if (free_in_cluster == 0)
|
||||||
s->free_byte_offset = 0;
|
s->free_byte_offset = 0;
|
||||||
if ((offset & (s->cluster_size - 1)) != 0)
|
if (offset_into_cluster(s, offset) != 0)
|
||||||
qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
|
qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, 1,
|
||||||
QCOW2_DISCARD_NEVER);
|
QCOW2_DISCARD_NEVER);
|
||||||
} else {
|
} else {
|
||||||
@ -740,7 +740,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
|||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
|
cluster_offset = start_of_cluster(s, s->free_byte_offset);
|
||||||
if ((cluster_offset + s->cluster_size) == offset) {
|
if ((cluster_offset + s->cluster_size) == offset) {
|
||||||
/* we are lucky: contiguous data */
|
/* we are lucky: contiguous data */
|
||||||
offset = s->free_byte_offset;
|
offset = s->free_byte_offset;
|
||||||
@ -1010,8 +1010,8 @@ static void inc_refcounts(BlockDriverState *bs,
|
|||||||
if (size <= 0)
|
if (size <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
start = offset & ~(s->cluster_size - 1);
|
start = start_of_cluster(s, offset);
|
||||||
last = (offset + size - 1) & ~(s->cluster_size - 1);
|
last = start_of_cluster(s, offset + size - 1);
|
||||||
for(cluster_offset = start; cluster_offset <= last;
|
for(cluster_offset = start; cluster_offset <= last;
|
||||||
cluster_offset += s->cluster_size) {
|
cluster_offset += s->cluster_size) {
|
||||||
k = cluster_offset >> s->cluster_bits;
|
k = cluster_offset >> s->cluster_bits;
|
||||||
@ -1122,7 +1122,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
offset, s->cluster_size);
|
offset, s->cluster_size);
|
||||||
|
|
||||||
/* Correct offsets are cluster aligned */
|
/* Correct offsets are cluster aligned */
|
||||||
if (offset & (s->cluster_size - 1)) {
|
if (offset_into_cluster(s, offset)) {
|
||||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
||||||
"properly aligned; L2 entry corrupted.\n", offset);
|
"properly aligned; L2 entry corrupted.\n", offset);
|
||||||
res->corruptions++;
|
res->corruptions++;
|
||||||
@ -1194,7 +1194,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
l2_offset, s->cluster_size);
|
l2_offset, s->cluster_size);
|
||||||
|
|
||||||
/* L2 tables are cluster aligned */
|
/* L2 tables are cluster aligned */
|
||||||
if (l2_offset & (s->cluster_size - 1)) {
|
if (offset_into_cluster(s, l2_offset)) {
|
||||||
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
|
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
|
||||||
"cluster aligned; L1 entry corrupted\n", l2_offset);
|
"cluster aligned; L1 entry corrupted\n", l2_offset);
|
||||||
res->corruptions++;
|
res->corruptions++;
|
||||||
@ -1423,7 +1423,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* update refcount table */
|
/* update refcount table */
|
||||||
assert(!(new_offset & (s->cluster_size - 1)));
|
assert(!offset_into_cluster(s, new_offset));
|
||||||
s->refcount_table[reftable_index] = new_offset;
|
s->refcount_table[reftable_index] = new_offset;
|
||||||
ret = write_reftable_entry(bs, reftable_index);
|
ret = write_reftable_entry(bs, reftable_index);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -1507,7 +1507,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
cluster = offset >> s->cluster_bits;
|
cluster = offset >> s->cluster_bits;
|
||||||
|
|
||||||
/* Refcount blocks are cluster aligned */
|
/* Refcount blocks are cluster aligned */
|
||||||
if (offset & (s->cluster_size - 1)) {
|
if (offset_into_cluster(s, offset)) {
|
||||||
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
|
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
|
||||||
"cluster aligned; refcount table entry corrupted\n", i);
|
"cluster aligned; refcount table entry corrupted\n", i);
|
||||||
res->corruptions++;
|
res->corruptions++;
|
||||||
|
@ -675,7 +675,10 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
|||||||
return s->nb_snapshots;
|
return s->nb_snapshots;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||||
|
const char *snapshot_id,
|
||||||
|
const char *name,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
int i, snapshot_index;
|
int i, snapshot_index;
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
@ -687,8 +690,10 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
|||||||
assert(bs->read_only);
|
assert(bs->read_only);
|
||||||
|
|
||||||
/* Search the snapshot */
|
/* Search the snapshot */
|
||||||
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name);
|
snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name);
|
||||||
if (snapshot_index < 0) {
|
if (snapshot_index < 0) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Can't find snapshot");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
sn = &s->snapshots[snapshot_index];
|
sn = &s->snapshots[snapshot_index];
|
||||||
@ -699,6 +704,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
|||||||
|
|
||||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Failed to read l1 table for snapshot");
|
||||||
g_free(new_l1_table);
|
g_free(new_l1_table);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -718,6 +718,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
|
bs->bl.write_zeroes_alignment = s->cluster_sectors;
|
||||||
|
|
||||||
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
if (s->use_lazy_refcounts && s->qcow_version < 3) {
|
||||||
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
|
||||||
@ -1471,7 +1472,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
* size for any qcow2 image.
|
* size for any qcow2 image.
|
||||||
*/
|
*/
|
||||||
BlockDriverState* bs;
|
BlockDriverState* bs;
|
||||||
QCowHeader header;
|
QCowHeader *header;
|
||||||
uint8_t* refcount_table;
|
uint8_t* refcount_table;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1489,30 +1490,34 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the header */
|
/* Write the header */
|
||||||
memset(&header, 0, sizeof(header));
|
QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
|
||||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
header = g_malloc0(cluster_size);
|
||||||
header.version = cpu_to_be32(version);
|
*header = (QCowHeader) {
|
||||||
header.cluster_bits = cpu_to_be32(cluster_bits);
|
.magic = cpu_to_be32(QCOW_MAGIC),
|
||||||
header.size = cpu_to_be64(0);
|
.version = cpu_to_be32(version),
|
||||||
header.l1_table_offset = cpu_to_be64(0);
|
.cluster_bits = cpu_to_be32(cluster_bits),
|
||||||
header.l1_size = cpu_to_be32(0);
|
.size = cpu_to_be64(0),
|
||||||
header.refcount_table_offset = cpu_to_be64(cluster_size);
|
.l1_table_offset = cpu_to_be64(0),
|
||||||
header.refcount_table_clusters = cpu_to_be32(1);
|
.l1_size = cpu_to_be32(0),
|
||||||
header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
|
.refcount_table_offset = cpu_to_be64(cluster_size),
|
||||||
header.header_length = cpu_to_be32(sizeof(header));
|
.refcount_table_clusters = cpu_to_be32(1),
|
||||||
|
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
|
||||||
|
.header_length = cpu_to_be32(sizeof(*header)),
|
||||||
|
};
|
||||||
|
|
||||||
if (flags & BLOCK_FLAG_ENCRYPT) {
|
if (flags & BLOCK_FLAG_ENCRYPT) {
|
||||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
||||||
} else {
|
} else {
|
||||||
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
|
if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
|
||||||
header.compatible_features |=
|
header->compatible_features |=
|
||||||
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
|
cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
|
ret = bdrv_pwrite(bs, 0, header, cluster_size);
|
||||||
|
g_free(header);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(errp, -ret, "Could not write qcow2 header");
|
error_setg_errno(errp, -ret, "Could not write qcow2 header");
|
||||||
goto out;
|
goto out;
|
||||||
@ -1893,6 +1898,8 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
|||||||
static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
bdi->unallocated_blocks_are_zero = true;
|
||||||
|
bdi->can_write_zeroes_with_unmap = (s->qcow_version >= 3);
|
||||||
bdi->cluster_size = s->cluster_size;
|
bdi->cluster_size = s->cluster_size;
|
||||||
bdi->vm_state_offset = qcow2_vm_state_offset(s);
|
bdi->vm_state_offset = qcow2_vm_state_offset(s);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -488,7 +488,10 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
|
|||||||
const char *name,
|
const char *name,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
|
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
|
||||||
int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name);
|
int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
||||||
|
const char *snapshot_id,
|
||||||
|
const char *name,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
void qcow2_free_snapshots(BlockDriverState *bs);
|
void qcow2_free_snapshots(BlockDriverState *bs);
|
||||||
int qcow2_read_snapshots(BlockDriverState *bs);
|
int qcow2_read_snapshots(BlockDriverState *bs);
|
||||||
|
@ -495,6 +495,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS;
|
||||||
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
s->need_check_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
qed_need_check_timer_cb, s);
|
qed_need_check_timer_cb, s);
|
||||||
|
|
||||||
@ -1475,6 +1476,8 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
memset(bdi, 0, sizeof(*bdi));
|
memset(bdi, 0, sizeof(*bdi));
|
||||||
bdi->cluster_size = s->header.cluster_size;
|
bdi->cluster_size = s->header.cluster_size;
|
||||||
bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
|
bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
|
||||||
|
bdi->unallocated_blocks_are_zero = true;
|
||||||
|
bdi->can_write_zeroes_with_unmap = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
#define QEMU_AIO_IOCTL 0x0004
|
#define QEMU_AIO_IOCTL 0x0004
|
||||||
#define QEMU_AIO_FLUSH 0x0008
|
#define QEMU_AIO_FLUSH 0x0008
|
||||||
#define QEMU_AIO_DISCARD 0x0010
|
#define QEMU_AIO_DISCARD 0x0010
|
||||||
|
#define QEMU_AIO_WRITE_ZEROES 0x0020
|
||||||
#define QEMU_AIO_TYPE_MASK \
|
#define QEMU_AIO_TYPE_MASK \
|
||||||
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
|
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \
|
||||||
QEMU_AIO_DISCARD)
|
QEMU_AIO_DISCARD|QEMU_AIO_WRITE_ZEROES)
|
||||||
|
|
||||||
/* AIO flags */
|
/* AIO flags */
|
||||||
#define QEMU_AIO_MISALIGNED 0x1000
|
#define QEMU_AIO_MISALIGNED 0x1000
|
||||||
|
@ -139,9 +139,11 @@ typedef struct BDRVRawState {
|
|||||||
void *aio_ctx;
|
void *aio_ctx;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
bool is_xfs : 1;
|
bool is_xfs:1;
|
||||||
#endif
|
#endif
|
||||||
bool has_discard : 1;
|
bool has_discard:1;
|
||||||
|
bool has_write_zeroes:1;
|
||||||
|
bool discard_zeroes:1;
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
|
|
||||||
typedef struct BDRVRawReopenState {
|
typedef struct BDRVRawReopenState {
|
||||||
@ -283,6 +285,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
opts = qemu_opts_create_nofail(&raw_runtime_opts);
|
opts = qemu_opts_create_nofail(&raw_runtime_opts);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
@ -323,10 +326,38 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s->has_discard = 1;
|
s->has_discard = true;
|
||||||
|
s->has_write_zeroes = true;
|
||||||
|
|
||||||
|
if (fstat(s->fd, &st) < 0) {
|
||||||
|
error_setg_errno(errp, errno, "Could not stat file");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (S_ISREG(st.st_mode)) {
|
||||||
|
s->discard_zeroes = true;
|
||||||
|
}
|
||||||
|
if (S_ISBLK(st.st_mode)) {
|
||||||
|
#ifdef BLKDISCARDZEROES
|
||||||
|
unsigned int arg;
|
||||||
|
if (ioctl(s->fd, BLKDISCARDZEROES, &arg) == 0 && arg) {
|
||||||
|
s->discard_zeroes = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef __linux__
|
||||||
|
/* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do
|
||||||
|
* not rely on the contents of discarded blocks unless using O_DIRECT.
|
||||||
|
* Same for BLKZEROOUT.
|
||||||
|
*/
|
||||||
|
if (!(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||||
|
s->discard_zeroes = false;
|
||||||
|
s->has_write_zeroes = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
if (platform_test_xfs_fd(s->fd)) {
|
if (platform_test_xfs_fd(s->fd)) {
|
||||||
s->is_xfs = 1;
|
s->is_xfs = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -675,6 +706,23 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
|
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||||
|
{
|
||||||
|
struct xfs_flock64 fl;
|
||||||
|
|
||||||
|
memset(&fl, 0, sizeof(fl));
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = offset;
|
||||||
|
fl.l_len = bytes;
|
||||||
|
|
||||||
|
if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
|
||||||
|
DEBUG_BLOCK_PRINT("cannot write zero range (%s)\n", strerror(errno));
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||||
{
|
{
|
||||||
struct xfs_flock64 fl;
|
struct xfs_flock64 fl;
|
||||||
@ -693,13 +741,49 @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
|
||||||
|
{
|
||||||
|
int ret = -EOPNOTSUPP;
|
||||||
|
BDRVRawState *s = aiocb->bs->opaque;
|
||||||
|
|
||||||
|
if (s->has_write_zeroes == 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
|
||||||
|
#ifdef BLKZEROOUT
|
||||||
|
do {
|
||||||
|
uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
|
||||||
|
if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} while (errno == EINTR);
|
||||||
|
|
||||||
|
ret = -errno;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef CONFIG_XFS
|
||||||
|
if (s->is_xfs) {
|
||||||
|
return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
|
||||||
|
ret == -ENOTTY) {
|
||||||
|
s->has_write_zeroes = false;
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
|
static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
|
||||||
{
|
{
|
||||||
int ret = -EOPNOTSUPP;
|
int ret = -EOPNOTSUPP;
|
||||||
BDRVRawState *s = aiocb->bs->opaque;
|
BDRVRawState *s = aiocb->bs->opaque;
|
||||||
|
|
||||||
if (s->has_discard == 0) {
|
if (!s->has_discard) {
|
||||||
return 0;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
|
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
|
||||||
@ -734,8 +818,8 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
|
|||||||
|
|
||||||
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
|
if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP ||
|
||||||
ret == -ENOTTY) {
|
ret == -ENOTTY) {
|
||||||
s->has_discard = 0;
|
s->has_discard = false;
|
||||||
ret = 0;
|
ret = -ENOTSUP;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -777,6 +861,9 @@ static int aio_worker(void *arg)
|
|||||||
case QEMU_AIO_DISCARD:
|
case QEMU_AIO_DISCARD:
|
||||||
ret = handle_aiocb_discard(aiocb);
|
ret = handle_aiocb_discard(aiocb);
|
||||||
break;
|
break;
|
||||||
|
case QEMU_AIO_WRITE_ZEROES:
|
||||||
|
ret = handle_aiocb_write_zeroes(aiocb);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@ -787,6 +874,29 @@ static int aio_worker(void *arg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int paio_submit_co(BlockDriverState *bs, int fd,
|
||||||
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
|
int type)
|
||||||
|
{
|
||||||
|
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
|
||||||
|
ThreadPool *pool;
|
||||||
|
|
||||||
|
acb->bs = bs;
|
||||||
|
acb->aio_type = type;
|
||||||
|
acb->aio_fildes = fd;
|
||||||
|
|
||||||
|
if (qiov) {
|
||||||
|
acb->aio_iov = qiov->iov;
|
||||||
|
acb->aio_niov = qiov->niov;
|
||||||
|
}
|
||||||
|
acb->aio_nbytes = nb_sectors * 512;
|
||||||
|
acb->aio_offset = sector_num * 512;
|
||||||
|
|
||||||
|
trace_paio_submit_co(sector_num, nb_sectors, type);
|
||||||
|
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
|
||||||
|
return thread_pool_submit_co(pool, aio_worker, acb);
|
||||||
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||||
@ -1199,6 +1309,31 @@ static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
|
|||||||
cb, opaque, QEMU_AIO_DISCARD);
|
cb, opaque, QEMU_AIO_DISCARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int coroutine_fn raw_co_write_zeroes(
|
||||||
|
BlockDriverState *bs, int64_t sector_num,
|
||||||
|
int nb_sectors, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
|
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||||
|
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||||
|
QEMU_AIO_WRITE_ZEROES);
|
||||||
|
} else if (s->discard_zeroes) {
|
||||||
|
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||||
|
QEMU_AIO_DISCARD);
|
||||||
|
}
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
|
bdi->unallocated_blocks_are_zero = s->discard_zeroes;
|
||||||
|
bdi->can_write_zeroes_with_unmap = s->discard_zeroes;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static QEMUOptionParameter raw_create_options[] = {
|
static QEMUOptionParameter raw_create_options[] = {
|
||||||
{
|
{
|
||||||
.name = BLOCK_OPT_SIZE,
|
.name = BLOCK_OPT_SIZE,
|
||||||
@ -1222,6 +1357,7 @@ static BlockDriver bdrv_file = {
|
|||||||
.bdrv_create = raw_create,
|
.bdrv_create = raw_create,
|
||||||
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
||||||
.bdrv_co_get_block_status = raw_co_get_block_status,
|
.bdrv_co_get_block_status = raw_co_get_block_status,
|
||||||
|
.bdrv_co_write_zeroes = raw_co_write_zeroes,
|
||||||
|
|
||||||
.bdrv_aio_readv = raw_aio_readv,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
@ -1230,6 +1366,7 @@ static BlockDriver bdrv_file = {
|
|||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
|
.bdrv_get_info = raw_get_info,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_get_allocated_file_size,
|
= raw_get_allocated_file_size,
|
||||||
|
|
||||||
@ -1525,6 +1662,26 @@ static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
|
|||||||
cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static coroutine_fn int hdev_co_write_zeroes(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = fd_open(bs);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
|
||||||
|
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||||
|
QEMU_AIO_WRITE_ZEROES|QEMU_AIO_BLKDEV);
|
||||||
|
} else if (s->discard_zeroes) {
|
||||||
|
return paio_submit_co(bs, s->fd, sector_num, NULL, nb_sectors,
|
||||||
|
QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
|
||||||
|
}
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
static int hdev_create(const char *filename, QEMUOptionParameter *options,
|
static int hdev_create(const char *filename, QEMUOptionParameter *options,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -1577,6 +1734,7 @@ static BlockDriver bdrv_host_device = {
|
|||||||
.bdrv_reopen_abort = raw_reopen_abort,
|
.bdrv_reopen_abort = raw_reopen_abort,
|
||||||
.bdrv_create = hdev_create,
|
.bdrv_create = hdev_create,
|
||||||
.create_options = raw_create_options,
|
.create_options = raw_create_options,
|
||||||
|
.bdrv_co_write_zeroes = hdev_co_write_zeroes,
|
||||||
|
|
||||||
.bdrv_aio_readv = raw_aio_readv,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
@ -1585,6 +1743,7 @@ static BlockDriver bdrv_host_device = {
|
|||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
|
.bdrv_get_info = raw_get_info,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_get_allocated_file_size,
|
= raw_get_allocated_file_size,
|
||||||
|
|
||||||
|
@ -25,6 +25,24 @@
|
|||||||
#include "block/snapshot.h"
|
#include "block/snapshot.h"
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
|
|
||||||
|
QemuOptsList internal_snapshot_opts = {
|
||||||
|
.name = "snapshot",
|
||||||
|
.head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
|
||||||
|
.desc = {
|
||||||
|
{
|
||||||
|
.name = SNAPSHOT_OPT_ID,
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "snapshot id"
|
||||||
|
},{
|
||||||
|
.name = SNAPSHOT_OPT_NAME,
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
|
.help = "snapshot name"
|
||||||
|
},{
|
||||||
|
/* end of list */
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
|
int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
@ -194,7 +212,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
|||||||
* If only @snapshot_id is specified, delete the first one with id
|
* If only @snapshot_id is specified, delete the first one with id
|
||||||
* @snapshot_id.
|
* @snapshot_id.
|
||||||
* If only @name is specified, delete the first one with name @name.
|
* If only @name is specified, delete the first one with name @name.
|
||||||
* if none is specified, return -ENINVAL.
|
* if none is specified, return -EINVAL.
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -errno on failure. If @bs is not inserted, return
|
* Returns: 0 on success, -errno on failure. If @bs is not inserted, return
|
||||||
* -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
|
* -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
|
||||||
@ -265,18 +283,71 @@ int bdrv_snapshot_list(BlockDriverState *bs,
|
|||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily load an internal snapshot by @snapshot_id and @name.
|
||||||
|
* @bs: block device used in the operation
|
||||||
|
* @snapshot_id: unique snapshot ID, or NULL
|
||||||
|
* @name: snapshot name, or NULL
|
||||||
|
* @errp: location to store error
|
||||||
|
*
|
||||||
|
* If both @snapshot_id and @name are specified, load the first one with
|
||||||
|
* id @snapshot_id and name @name.
|
||||||
|
* If only @snapshot_id is specified, load the first one with id
|
||||||
|
* @snapshot_id.
|
||||||
|
* If only @name is specified, load the first one with name @name.
|
||||||
|
* if none is specified, return -EINVAL.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -errno on fail. If @bs is not inserted, return
|
||||||
|
* -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support
|
||||||
|
* internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and
|
||||||
|
* @name, return -ENOENT. If @errp != NULL, it will always be filled on
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
||||||
const char *snapshot_name)
|
const char *snapshot_id,
|
||||||
|
const char *name,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
}
|
}
|
||||||
|
if (!snapshot_id && !name) {
|
||||||
|
error_setg(errp, "snapshot_id and name are both NULL");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
if (!bs->read_only) {
|
if (!bs->read_only) {
|
||||||
|
error_setg(errp, "Device is not readonly");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (drv->bdrv_snapshot_load_tmp) {
|
if (drv->bdrv_snapshot_load_tmp) {
|
||||||
return drv->bdrv_snapshot_load_tmp(bs, snapshot_name);
|
return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
|
||||||
}
|
}
|
||||||
|
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||||
|
drv->format_name, bdrv_get_device_name(bs),
|
||||||
|
"temporarily load internal snapshot");
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
|
||||||
|
const char *id_or_name,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
|
||||||
|
if (ret == -ENOENT || ret == -EINVAL) {
|
||||||
|
error_free(local_err);
|
||||||
|
local_err = NULL;
|
||||||
|
ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_is_set(&local_err)) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -331,6 +331,7 @@ static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
logout("\n");
|
logout("\n");
|
||||||
bdi->cluster_size = s->block_size;
|
bdi->cluster_size = s->block_size;
|
||||||
bdi->vm_state_offset = 0;
|
bdi->vm_state_offset = 0;
|
||||||
|
bdi->unallocated_blocks_are_zero = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
block/vhdx.c
13
block/vhdx.c
@ -1043,6 +1043,18 @@ static void vhdx_block_translate(BDRVVHDXState *s, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
{
|
||||||
|
BDRVVHDXState *s = bs->opaque;
|
||||||
|
|
||||||
|
bdi->cluster_size = s->block_size;
|
||||||
|
|
||||||
|
bdi->unallocated_blocks_are_zero =
|
||||||
|
(s->params.data_bits & VHDX_PARAMS_HAS_PARENT) == 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, QEMUIOVector *qiov)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
@ -1885,6 +1897,7 @@ static BlockDriver bdrv_vhdx = {
|
|||||||
.bdrv_co_readv = vhdx_co_readv,
|
.bdrv_co_readv = vhdx_co_readv,
|
||||||
.bdrv_co_writev = vhdx_co_writev,
|
.bdrv_co_writev = vhdx_co_writev,
|
||||||
.bdrv_create = vhdx_create,
|
.bdrv_create = vhdx_create,
|
||||||
|
.bdrv_get_info = vhdx_get_info,
|
||||||
|
|
||||||
.create_options = vhdx_create_options,
|
.create_options = vhdx_create_options,
|
||||||
};
|
};
|
||||||
|
66
block/vmdk.c
66
block/vmdk.c
@ -428,6 +428,10 @@ static int vmdk_add_extent(BlockDriverState *bs,
|
|||||||
extent->l2_size = l2_size;
|
extent->l2_size = l2_size;
|
||||||
extent->cluster_sectors = flat ? sectors : cluster_sectors;
|
extent->cluster_sectors = flat ? sectors : cluster_sectors;
|
||||||
|
|
||||||
|
if (!flat) {
|
||||||
|
bs->bl.write_zeroes_alignment =
|
||||||
|
MAX(bs->bl.write_zeroes_alignment, cluster_sectors);
|
||||||
|
}
|
||||||
if (s->num_extents > 1) {
|
if (s->num_extents > 1) {
|
||||||
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
|
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
|
||||||
} else {
|
} else {
|
||||||
@ -1596,7 +1600,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
int fd, idx = 0;
|
int fd, idx = 0;
|
||||||
char desc[BUF_SIZE];
|
char *desc = NULL;
|
||||||
int64_t total_size = 0, filesize;
|
int64_t total_size = 0, filesize;
|
||||||
const char *adapter_type = NULL;
|
const char *adapter_type = NULL;
|
||||||
const char *backing_file = NULL;
|
const char *backing_file = NULL;
|
||||||
@ -1604,7 +1608,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
int flags = 0;
|
int flags = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool flat, split, compress;
|
bool flat, split, compress;
|
||||||
char ext_desc_lines[BUF_SIZE] = "";
|
GString *ext_desc_lines;
|
||||||
char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
|
char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
|
||||||
const int64_t split_size = 0x80000000; /* VMDK has constant split size */
|
const int64_t split_size = 0x80000000; /* VMDK has constant split size */
|
||||||
const char *desc_extent_line;
|
const char *desc_extent_line;
|
||||||
@ -1632,8 +1636,11 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
"ddb.geometry.sectors = \"63\"\n"
|
"ddb.geometry.sectors = \"63\"\n"
|
||||||
"ddb.adapterType = \"%s\"\n";
|
"ddb.adapterType = \"%s\"\n";
|
||||||
|
|
||||||
|
ext_desc_lines = g_string_new(NULL);
|
||||||
|
|
||||||
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) {
|
if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
@ -1659,7 +1666,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
strcmp(adapter_type, "lsilogic") &&
|
strcmp(adapter_type, "lsilogic") &&
|
||||||
strcmp(adapter_type, "legacyESX")) {
|
strcmp(adapter_type, "legacyESX")) {
|
||||||
error_setg(errp, "Unknown adapter type: '%s'", adapter_type);
|
error_setg(errp, "Unknown adapter type: '%s'", adapter_type);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
if (strcmp(adapter_type, "ide") != 0) {
|
if (strcmp(adapter_type, "ide") != 0) {
|
||||||
/* that's the number of heads with which vmware operates when
|
/* that's the number of heads with which vmware operates when
|
||||||
@ -1675,7 +1683,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
strcmp(fmt, "twoGbMaxExtentFlat") &&
|
strcmp(fmt, "twoGbMaxExtentFlat") &&
|
||||||
strcmp(fmt, "streamOptimized")) {
|
strcmp(fmt, "streamOptimized")) {
|
||||||
error_setg(errp, "Unknown subformat: '%s'", fmt);
|
error_setg(errp, "Unknown subformat: '%s'", fmt);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
|
split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
|
||||||
strcmp(fmt, "twoGbMaxExtentSparse"));
|
strcmp(fmt, "twoGbMaxExtentSparse"));
|
||||||
@ -1689,22 +1698,25 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
}
|
}
|
||||||
if (flat && backing_file) {
|
if (flat && backing_file) {
|
||||||
error_setg(errp, "Flat image can't have backing file");
|
error_setg(errp, "Flat image can't have backing file");
|
||||||
return -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
if (flat && zeroed_grain) {
|
if (flat && zeroed_grain) {
|
||||||
error_setg(errp, "Flat image can't enable zeroed grain");
|
error_setg(errp, "Flat image can't enable zeroed grain");
|
||||||
return -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
if (backing_file) {
|
if (backing_file) {
|
||||||
BlockDriverState *bs = bdrv_new("");
|
BlockDriverState *bs = bdrv_new("");
|
||||||
ret = bdrv_open(bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp);
|
ret = bdrv_open(bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
return ret;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (strcmp(bs->drv->format_name, "vmdk")) {
|
if (strcmp(bs->drv->format_name, "vmdk")) {
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
parent_cid = vmdk_read_cid(bs, 0);
|
parent_cid = vmdk_read_cid(bs, 0);
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
@ -1738,25 +1750,27 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
|
|
||||||
if (vmdk_create_extent(ext_filename, size,
|
if (vmdk_create_extent(ext_filename, size,
|
||||||
flat, compress, zeroed_grain)) {
|
flat, compress, zeroed_grain)) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
filesize -= size;
|
filesize -= size;
|
||||||
|
|
||||||
/* Format description line */
|
/* Format description line */
|
||||||
snprintf(desc_line, sizeof(desc_line),
|
snprintf(desc_line, sizeof(desc_line),
|
||||||
desc_extent_line, size / 512, desc_filename);
|
desc_extent_line, size / 512, desc_filename);
|
||||||
pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
|
g_string_append(ext_desc_lines, desc_line);
|
||||||
}
|
}
|
||||||
/* generate descriptor file */
|
/* generate descriptor file */
|
||||||
snprintf(desc, sizeof(desc), desc_template,
|
desc = g_strdup_printf(desc_template,
|
||||||
(unsigned int)time(NULL),
|
(unsigned int)time(NULL),
|
||||||
parent_cid,
|
parent_cid,
|
||||||
fmt,
|
fmt,
|
||||||
parent_desc_line,
|
parent_desc_line,
|
||||||
ext_desc_lines,
|
ext_desc_lines->str,
|
||||||
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
|
||||||
total_size / (int64_t)(63 * number_heads * 512), number_heads,
|
total_size / (int64_t)(63 * number_heads * 512),
|
||||||
adapter_type);
|
number_heads,
|
||||||
|
adapter_type);
|
||||||
if (split || flat) {
|
if (split || flat) {
|
||||||
fd = qemu_open(filename,
|
fd = qemu_open(filename,
|
||||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||||
@ -1767,21 +1781,25 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
|
|||||||
0644);
|
0644);
|
||||||
}
|
}
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return -errno;
|
ret = -errno;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
/* the descriptor offset = 0x200 */
|
/* the descriptor offset = 0x200 */
|
||||||
if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
|
if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto exit;
|
goto close_exit;
|
||||||
}
|
}
|
||||||
ret = qemu_write_full(fd, desc, strlen(desc));
|
ret = qemu_write_full(fd, desc, strlen(desc));
|
||||||
if (ret != strlen(desc)) {
|
if (ret != strlen(desc)) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto exit;
|
goto close_exit;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
exit:
|
close_exit:
|
||||||
qemu_close(fd);
|
qemu_close(fd);
|
||||||
|
exit:
|
||||||
|
g_free(desc);
|
||||||
|
g_string_free(ext_desc_lines, true);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
block/vpc.c
15
block/vpc.c
@ -455,6 +455,19 @@ fail:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||||
|
{
|
||||||
|
BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
|
||||||
|
VHDFooter *footer = (VHDFooter *) s->footer_buf;
|
||||||
|
|
||||||
|
if (cpu_to_be32(footer->type) != VHD_FIXED) {
|
||||||
|
bdi->cluster_size = s->block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdi->unallocated_blocks_are_zero = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
@ -857,6 +870,8 @@ static BlockDriver bdrv_vpc = {
|
|||||||
.bdrv_read = vpc_co_read,
|
.bdrv_read = vpc_co_read,
|
||||||
.bdrv_write = vpc_co_write,
|
.bdrv_write = vpc_co_write,
|
||||||
|
|
||||||
|
.bdrv_get_info = vpc_get_info,
|
||||||
|
|
||||||
.create_options = vpc_create_options,
|
.create_options = vpc_create_options,
|
||||||
.bdrv_has_zero_init = vpc_has_zero_init,
|
.bdrv_has_zero_init = vpc_has_zero_init,
|
||||||
};
|
};
|
||||||
|
@ -41,6 +41,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
|
|||||||
#include <scsi/sg.h>
|
#include <scsi/sg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SCSI_WRITE_SAME_MAX 524288
|
||||||
#define SCSI_DMA_BUF_SIZE 131072
|
#define SCSI_DMA_BUF_SIZE 131072
|
||||||
#define SCSI_MAX_INQUIRY_LEN 256
|
#define SCSI_MAX_INQUIRY_LEN 256
|
||||||
#define SCSI_MAX_MODE_LEN 256
|
#define SCSI_MAX_MODE_LEN 256
|
||||||
@ -634,6 +635,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||||||
buflen = 0x40;
|
buflen = 0x40;
|
||||||
memset(outbuf + 4, 0, buflen - 4);
|
memset(outbuf + 4, 0, buflen - 4);
|
||||||
|
|
||||||
|
outbuf[4] = 0x1; /* wsnz */
|
||||||
|
|
||||||
/* optimal transfer length granularity */
|
/* optimal transfer length granularity */
|
||||||
outbuf[6] = (min_io_size >> 8) & 0xff;
|
outbuf[6] = (min_io_size >> 8) & 0xff;
|
||||||
outbuf[7] = min_io_size & 0xff;
|
outbuf[7] = min_io_size & 0xff;
|
||||||
@ -1543,10 +1546,16 @@ done:
|
|||||||
|
|
||||||
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
||||||
{
|
{
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
uint8_t *p = inbuf;
|
uint8_t *p = inbuf;
|
||||||
int len = r->req.cmd.xfer;
|
int len = r->req.cmd.xfer;
|
||||||
UnmapCBData *data;
|
UnmapCBData *data;
|
||||||
|
|
||||||
|
/* Reject ANCHOR=1. */
|
||||||
|
if (r->req.cmd.buf[1] & 0x1) {
|
||||||
|
goto invalid_field;
|
||||||
|
}
|
||||||
|
|
||||||
if (len < 8) {
|
if (len < 8) {
|
||||||
goto invalid_param_len;
|
goto invalid_param_len;
|
||||||
}
|
}
|
||||||
@ -1560,6 +1569,11 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
|||||||
goto invalid_param_len;
|
goto invalid_param_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
||||||
|
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = g_new0(UnmapCBData, 1);
|
data = g_new0(UnmapCBData, 1);
|
||||||
data->r = r;
|
data->r = r;
|
||||||
data->inbuf = &p[8];
|
data->inbuf = &p[8];
|
||||||
@ -1572,6 +1586,115 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
|
|||||||
|
|
||||||
invalid_param_len:
|
invalid_param_len:
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
|
scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
|
||||||
|
return;
|
||||||
|
|
||||||
|
invalid_field:
|
||||||
|
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct WriteSameCBData {
|
||||||
|
SCSIDiskReq *r;
|
||||||
|
int64_t sector;
|
||||||
|
int nb_sectors;
|
||||||
|
QEMUIOVector qiov;
|
||||||
|
struct iovec iov;
|
||||||
|
} WriteSameCBData;
|
||||||
|
|
||||||
|
static void scsi_write_same_complete(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
WriteSameCBData *data = opaque;
|
||||||
|
SCSIDiskReq *r = data->r;
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
|
|
||||||
|
assert(r->req.aiocb != NULL);
|
||||||
|
r->req.aiocb = NULL;
|
||||||
|
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
|
||||||
|
if (r->req.io_canceled) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (scsi_handle_rw_error(r, -ret)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->nb_sectors -= data->iov.iov_len / 512;
|
||||||
|
data->sector += data->iov.iov_len / 512;
|
||||||
|
data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len);
|
||||||
|
if (data->iov.iov_len) {
|
||||||
|
bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE);
|
||||||
|
r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector,
|
||||||
|
&data->qiov, data->iov.iov_len / 512,
|
||||||
|
scsi_write_same_complete, r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi_req_complete(&r->req, GOOD);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (!r->req.io_canceled) {
|
||||||
|
scsi_req_unref(&r->req);
|
||||||
|
}
|
||||||
|
qemu_vfree(data->iov.iov_base);
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
|
||||||
|
{
|
||||||
|
SCSIRequest *req = &r->req;
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
|
uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
|
||||||
|
WriteSameCBData *data;
|
||||||
|
uint8_t *buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */
|
||||||
|
if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
|
||||||
|
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
||||||
|
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
||||||
|
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_is_zero(inbuf, s->qdev.blocksize)) {
|
||||||
|
int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0;
|
||||||
|
|
||||||
|
/* The request is used as the AIO opaque value, so add a ref. */
|
||||||
|
scsi_req_ref(&r->req);
|
||||||
|
bdrv_acct_start(s->qdev.conf.bs, &r->acct, nb_sectors * s->qdev.blocksize,
|
||||||
|
BDRV_ACCT_WRITE);
|
||||||
|
r->req.aiocb = bdrv_aio_write_zeroes(s->qdev.conf.bs,
|
||||||
|
r->req.cmd.lba * (s->qdev.blocksize / 512),
|
||||||
|
nb_sectors * (s->qdev.blocksize / 512),
|
||||||
|
flags, scsi_aio_complete, r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = g_new0(WriteSameCBData, 1);
|
||||||
|
data->r = r;
|
||||||
|
data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
|
||||||
|
data->nb_sectors = nb_sectors * (s->qdev.blocksize / 512);
|
||||||
|
data->iov.iov_len = MIN(data->nb_sectors * 512, SCSI_WRITE_SAME_MAX);
|
||||||
|
data->iov.iov_base = buf = qemu_blockalign(s->qdev.conf.bs, data->iov.iov_len);
|
||||||
|
qemu_iovec_init_external(&data->qiov, &data->iov, 1);
|
||||||
|
|
||||||
|
for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) {
|
||||||
|
memcpy(&buf[i], inbuf, s->qdev.blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi_req_ref(&r->req);
|
||||||
|
bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE);
|
||||||
|
r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector,
|
||||||
|
&data->qiov, data->iov.iov_len / 512,
|
||||||
|
scsi_write_same_complete, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
||||||
@ -1597,6 +1720,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
|||||||
scsi_disk_emulate_unmap(r, r->iov.iov_base);
|
scsi_disk_emulate_unmap(r, r->iov.iov_base);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WRITE_SAME_10:
|
||||||
|
case WRITE_SAME_16:
|
||||||
|
scsi_disk_emulate_write_same(r, r->iov.iov_base);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -1839,29 +1966,10 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
break;
|
break;
|
||||||
case WRITE_SAME_10:
|
case WRITE_SAME_10:
|
||||||
case WRITE_SAME_16:
|
case WRITE_SAME_16:
|
||||||
nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
|
DPRINTF("WRITE SAME %d (len %lu)\n",
|
||||||
if (bdrv_is_read_only(s->qdev.conf.bs)) {
|
req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16,
|
||||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
(long)r->req.cmd.xfer);
|
||||||
return 0;
|
break;
|
||||||
}
|
|
||||||
if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
|
|
||||||
goto illegal_lba;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We only support WRITE SAME with the unmap bit set for now.
|
|
||||||
*/
|
|
||||||
if (!(req->cmd.buf[1] & 0x8)) {
|
|
||||||
goto illegal_request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The request is used as the AIO opaque value, so add a ref. */
|
|
||||||
scsi_req_ref(&r->req);
|
|
||||||
r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
|
|
||||||
r->req.cmd.lba * (s->qdev.blocksize / 512),
|
|
||||||
nb_sectors * (s->qdev.blocksize / 512),
|
|
||||||
scsi_aio_complete, r);
|
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||||
|
@ -216,6 +216,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
|||||||
const uint8_t *buf, int nb_sectors);
|
const uint8_t *buf, int nb_sectors);
|
||||||
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||||
int nb_sectors, BdrvRequestFlags flags);
|
int nb_sectors, BdrvRequestFlags flags);
|
||||||
|
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
int nb_sectors, BdrvRequestFlags flags,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque);
|
||||||
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags);
|
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags);
|
||||||
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov);
|
int bdrv_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov);
|
||||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||||
@ -311,6 +314,7 @@ typedef struct BlockRequest {
|
|||||||
/* Fields to be filled by multiwrite caller */
|
/* Fields to be filled by multiwrite caller */
|
||||||
int64_t sector;
|
int64_t sector;
|
||||||
int nb_sectors;
|
int nb_sectors;
|
||||||
|
int flags;
|
||||||
QEMUIOVector *qiov;
|
QEMUIOVector *qiov;
|
||||||
BlockDriverCompletionFunc *cb;
|
BlockDriverCompletionFunc *cb;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
@ -176,7 +176,9 @@ struct BlockDriver {
|
|||||||
int (*bdrv_snapshot_list)(BlockDriverState *bs,
|
int (*bdrv_snapshot_list)(BlockDriverState *bs,
|
||||||
QEMUSnapshotInfo **psn_info);
|
QEMUSnapshotInfo **psn_info);
|
||||||
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
|
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
|
||||||
const char *snapshot_name);
|
const char *snapshot_id,
|
||||||
|
const char *name,
|
||||||
|
Error **errp);
|
||||||
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||||
ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
|
ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
|
||||||
|
|
||||||
@ -245,6 +247,9 @@ typedef struct BlockLimits {
|
|||||||
|
|
||||||
/* optimal alignment for write zeroes requests in sectors */
|
/* optimal alignment for write zeroes requests in sectors */
|
||||||
int64_t write_zeroes_alignment;
|
int64_t write_zeroes_alignment;
|
||||||
|
|
||||||
|
/* optimal transfer length in sectors */
|
||||||
|
int opt_transfer_length;
|
||||||
} BlockLimits;
|
} BlockLimits;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -105,7 +105,6 @@ bool qemu_in_coroutine(void);
|
|||||||
*/
|
*/
|
||||||
typedef struct CoQueue {
|
typedef struct CoQueue {
|
||||||
QTAILQ_HEAD(, Coroutine) entries;
|
QTAILQ_HEAD(, Coroutine) entries;
|
||||||
AioContext *ctx;
|
|
||||||
} CoQueue;
|
} CoQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,12 +119,6 @@ void qemu_co_queue_init(CoQueue *queue);
|
|||||||
*/
|
*/
|
||||||
void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
|
void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the current coroutine to the head of the CoQueue and transfers control to the
|
|
||||||
* caller of the coroutine.
|
|
||||||
*/
|
|
||||||
void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts the next coroutine in the CoQueue and removes it from the queue.
|
* Restarts the next coroutine in the CoQueue and removes it from the queue.
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,14 @@
|
|||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/option.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SNAPSHOT_OPT_BASE "snapshot."
|
||||||
|
#define SNAPSHOT_OPT_ID "snapshot.id"
|
||||||
|
#define SNAPSHOT_OPT_NAME "snapshot.name"
|
||||||
|
|
||||||
|
extern QemuOptsList internal_snapshot_opts;
|
||||||
|
|
||||||
typedef struct QEMUSnapshotInfo {
|
typedef struct QEMUSnapshotInfo {
|
||||||
char id_str[128]; /* unique snapshot id */
|
char id_str[128]; /* unique snapshot id */
|
||||||
@ -61,5 +69,10 @@ void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
|
|||||||
int bdrv_snapshot_list(BlockDriverState *bs,
|
int bdrv_snapshot_list(BlockDriverState *bs,
|
||||||
QEMUSnapshotInfo **psn_info);
|
QEMUSnapshotInfo **psn_info);
|
||||||
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
int bdrv_snapshot_load_tmp(BlockDriverState *bs,
|
||||||
const char *snapshot_name);
|
const char *snapshot_id,
|
||||||
|
const char *name,
|
||||||
|
Error **errp);
|
||||||
|
int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
|
||||||
|
const char *id_or_name,
|
||||||
|
Error **errp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,14 +41,6 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
|
|||||||
assert(qemu_in_coroutine());
|
assert(qemu_in_coroutine());
|
||||||
}
|
}
|
||||||
|
|
||||||
void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue)
|
|
||||||
{
|
|
||||||
Coroutine *self = qemu_coroutine_self();
|
|
||||||
QTAILQ_INSERT_HEAD(&queue->entries, self, co_queue_next);
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
assert(qemu_in_coroutine());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemu_co_queue_run_restart:
|
* qemu_co_queue_run_restart:
|
||||||
*
|
*
|
||||||
|
@ -34,9 +34,9 @@ STEXI
|
|||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
DEF("convert", img_convert,
|
DEF("convert", img_convert,
|
||||||
"convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename")
|
"convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename")
|
||||||
STEXI
|
STEXI
|
||||||
@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
DEF("info", img_info,
|
DEF("info", img_info,
|
||||||
|
169
qemu-img.c
169
qemu-img.c
@ -93,6 +93,11 @@ static void help(void)
|
|||||||
" 'options' is a comma separated list of format specific options in a\n"
|
" 'options' is a comma separated list of format specific options in a\n"
|
||||||
" name=value format. Use -o ? for an overview of the options supported by the\n"
|
" name=value format. Use -o ? for an overview of the options supported by the\n"
|
||||||
" used format\n"
|
" used format\n"
|
||||||
|
" 'snapshot_param' is param used for internal snapshot, format\n"
|
||||||
|
" is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
|
||||||
|
" '[ID_OR_NAME]'\n"
|
||||||
|
" 'snapshot_id_or_name' is deprecated, use 'snapshot_param'\n"
|
||||||
|
" instead\n"
|
||||||
" '-c' indicates that target image must be compressed (qcow format only)\n"
|
" '-c' indicates that target image must be compressed (qcow format only)\n"
|
||||||
" '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
|
" '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
|
||||||
" match exactly. The image doesn't need a working backing file before\n"
|
" match exactly. The image doesn't need a working backing file before\n"
|
||||||
@ -105,7 +110,6 @@ static void help(void)
|
|||||||
" conversion. If the number of bytes is 0, the source will not be scanned for\n"
|
" conversion. If the number of bytes is 0, the source will not be scanned for\n"
|
||||||
" unallocated or zero sectors, and the destination image will always be\n"
|
" unallocated or zero sectors, and the destination image will always be\n"
|
||||||
" fully allocated\n"
|
" fully allocated\n"
|
||||||
" images will always be fully allocated\n"
|
|
||||||
" '--output' takes the format in which the output must be done (human or json)\n"
|
" '--output' takes the format in which the output must be done (human or json)\n"
|
||||||
" '-n' skips the target volume creation (useful if the volume is created\n"
|
" '-n' skips the target volume creation (useful if the volume is created\n"
|
||||||
" prior to running qemu-img)\n"
|
" prior to running qemu-img)\n"
|
||||||
@ -1125,25 +1129,27 @@ out3:
|
|||||||
|
|
||||||
static int img_convert(int argc, char **argv)
|
static int img_convert(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size,
|
int c, n, n1, bs_n, bs_i, compress, cluster_sectors, skip_create;
|
||||||
cluster_sectors, skip_create;
|
int64_t ret = 0;
|
||||||
int progress = 0, flags;
|
int progress = 0, flags;
|
||||||
const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
|
const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
|
||||||
BlockDriver *drv, *proto_drv;
|
BlockDriver *drv, *proto_drv;
|
||||||
BlockDriverState **bs = NULL, *out_bs = NULL;
|
BlockDriverState **bs = NULL, *out_bs = NULL;
|
||||||
int64_t total_sectors, nb_sectors, sector_num, bs_offset;
|
int64_t total_sectors, nb_sectors, sector_num, bs_offset,
|
||||||
|
sector_num_next_status = 0;
|
||||||
uint64_t bs_sectors;
|
uint64_t bs_sectors;
|
||||||
uint8_t * buf = NULL;
|
uint8_t * buf = NULL;
|
||||||
|
size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;
|
||||||
const uint8_t *buf1;
|
const uint8_t *buf1;
|
||||||
BlockDriverInfo bdi;
|
BlockDriverInfo bdi;
|
||||||
QEMUOptionParameter *param = NULL, *create_options = NULL;
|
QEMUOptionParameter *param = NULL, *create_options = NULL;
|
||||||
QEMUOptionParameter *out_baseimg_param;
|
QEMUOptionParameter *out_baseimg_param;
|
||||||
char *options = NULL;
|
char *options = NULL;
|
||||||
const char *snapshot_name = NULL;
|
const char *snapshot_name = NULL;
|
||||||
float local_progress = 0;
|
|
||||||
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
|
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
QemuOpts *sn_opts = NULL;
|
||||||
|
|
||||||
fmt = NULL;
|
fmt = NULL;
|
||||||
out_fmt = "raw";
|
out_fmt = "raw";
|
||||||
@ -1152,7 +1158,7 @@ static int img_convert(int argc, char **argv)
|
|||||||
compress = 0;
|
compress = 0;
|
||||||
skip_create = 0;
|
skip_create = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qn");
|
c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qnl:");
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1187,6 +1193,18 @@ static int img_convert(int argc, char **argv)
|
|||||||
case 's':
|
case 's':
|
||||||
snapshot_name = optarg;
|
snapshot_name = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
|
||||||
|
sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);
|
||||||
|
if (!sn_opts) {
|
||||||
|
error_report("Failed in parsing snapshot param '%s'",
|
||||||
|
optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snapshot_name = optarg;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
{
|
{
|
||||||
int64_t sval;
|
int64_t sval;
|
||||||
@ -1227,7 +1245,7 @@ static int img_convert(int argc, char **argv)
|
|||||||
out_filename = argv[argc - 1];
|
out_filename = argv[argc - 1];
|
||||||
|
|
||||||
/* Initialize before goto out */
|
/* Initialize before goto out */
|
||||||
qemu_progress_init(progress, 2.0);
|
qemu_progress_init(progress, 1.0);
|
||||||
|
|
||||||
if (options && is_help_option(options)) {
|
if (options && is_help_option(options)) {
|
||||||
ret = print_block_option_help(out_filename, out_fmt);
|
ret = print_block_option_help(out_filename, out_fmt);
|
||||||
@ -1258,17 +1276,26 @@ static int img_convert(int argc, char **argv)
|
|||||||
total_sectors += bs_sectors;
|
total_sectors += bs_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapshot_name != NULL) {
|
if (sn_opts) {
|
||||||
|
ret = bdrv_snapshot_load_tmp(bs[0],
|
||||||
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
||||||
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
|
||||||
|
&local_err);
|
||||||
|
} else if (snapshot_name != NULL) {
|
||||||
if (bs_n > 1) {
|
if (bs_n > 1) {
|
||||||
error_report("No support for concatenating multiple snapshot");
|
error_report("No support for concatenating multiple snapshot");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
|
|
||||||
error_report("Failed to load snapshot");
|
bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);
|
||||||
ret = -1;
|
}
|
||||||
goto out;
|
if (error_is_set(&local_err)) {
|
||||||
}
|
error_report("Failed to load snapshot: %s",
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
error_free(local_err);
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find driver and parse its options */
|
/* Find driver and parse its options */
|
||||||
@ -1371,7 +1398,16 @@ static int img_convert(int argc, char **argv)
|
|||||||
bs_i = 0;
|
bs_i = 0;
|
||||||
bs_offset = 0;
|
bs_offset = 0;
|
||||||
bdrv_get_geometry(bs[0], &bs_sectors);
|
bdrv_get_geometry(bs[0], &bs_sectors);
|
||||||
buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
|
|
||||||
|
/* increase bufsectors from the default 4096 (2M) if opt_transfer_length
|
||||||
|
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
|
||||||
|
* as maximum. */
|
||||||
|
bufsectors = MIN(32768,
|
||||||
|
MAX(bufsectors, MAX(out_bs->bl.opt_transfer_length,
|
||||||
|
out_bs->bl.discard_alignment))
|
||||||
|
);
|
||||||
|
|
||||||
|
buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
if (skip_create) {
|
if (skip_create) {
|
||||||
int64_t output_length = bdrv_getlength(out_bs);
|
int64_t output_length = bdrv_getlength(out_bs);
|
||||||
@ -1387,26 +1423,26 @@ static int img_convert(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compress) {
|
cluster_sectors = 0;
|
||||||
ret = bdrv_get_info(out_bs, &bdi);
|
ret = bdrv_get_info(out_bs, &bdi);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
if (compress) {
|
||||||
error_report("could not get block driver info");
|
error_report("could not get block driver info");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
cluster_size = bdi.cluster_size;
|
} else {
|
||||||
if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
|
cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compress) {
|
||||||
|
if (cluster_sectors <= 0 || cluster_sectors > bufsectors) {
|
||||||
error_report("invalid cluster size");
|
error_report("invalid cluster size");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
cluster_sectors = cluster_size >> 9;
|
|
||||||
sector_num = 0;
|
sector_num = 0;
|
||||||
|
|
||||||
nb_sectors = total_sectors;
|
nb_sectors = total_sectors;
|
||||||
if (nb_sectors != 0) {
|
|
||||||
local_progress = (float)100 /
|
|
||||||
(nb_sectors / MIN(nb_sectors, cluster_sectors));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
int64_t bs_num;
|
int64_t bs_num;
|
||||||
@ -1464,7 +1500,7 @@ static int img_convert(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sector_num += n;
|
sector_num += n;
|
||||||
qemu_progress_print(local_progress, 100);
|
qemu_progress_print(100.0 * sector_num / total_sectors, 0);
|
||||||
}
|
}
|
||||||
/* signal EOF to align */
|
/* signal EOF to align */
|
||||||
bdrv_write_compressed(out_bs, 0, NULL, 0);
|
bdrv_write_compressed(out_bs, 0, NULL, 0);
|
||||||
@ -1481,21 +1517,13 @@ static int img_convert(int argc, char **argv)
|
|||||||
|
|
||||||
sector_num = 0; // total number of sectors converted so far
|
sector_num = 0; // total number of sectors converted so far
|
||||||
nb_sectors = total_sectors - sector_num;
|
nb_sectors = total_sectors - sector_num;
|
||||||
if (nb_sectors != 0) {
|
|
||||||
local_progress = (float)100 /
|
|
||||||
(nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
nb_sectors = total_sectors - sector_num;
|
nb_sectors = total_sectors - sector_num;
|
||||||
if (nb_sectors <= 0) {
|
if (nb_sectors <= 0) {
|
||||||
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nb_sectors >= (IO_BUF_SIZE / 512)) {
|
|
||||||
n = (IO_BUF_SIZE / 512);
|
|
||||||
} else {
|
|
||||||
n = nb_sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (sector_num - bs_offset >= bs_sectors) {
|
while (sector_num - bs_offset >= bs_sectors) {
|
||||||
bs_i ++;
|
bs_i ++;
|
||||||
@ -1507,34 +1535,59 @@ static int img_convert(int argc, char **argv)
|
|||||||
sector_num, bs_i, bs_offset, bs_sectors); */
|
sector_num, bs_i, bs_offset, bs_sectors); */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n > bs_offset + bs_sectors - sector_num) {
|
if ((out_baseimg || has_zero_init) &&
|
||||||
n = bs_offset + bs_sectors - sector_num;
|
sector_num >= sector_num_next_status) {
|
||||||
}
|
n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors;
|
||||||
|
ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset,
|
||||||
/* If the output image is being created as a copy on write image,
|
n, &n1);
|
||||||
assume that sectors which are unallocated in the input image
|
|
||||||
are present in both the output's and input's base images (no
|
|
||||||
need to copy them). */
|
|
||||||
if (out_baseimg) {
|
|
||||||
ret = bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
|
|
||||||
n, &n1);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("error while reading metadata for sector "
|
error_report("error while reading block status of sector %"
|
||||||
"%" PRId64 ": %s",
|
PRId64 ": %s", sector_num - bs_offset,
|
||||||
sector_num - bs_offset, strerror(-ret));
|
strerror(-ret));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!ret) {
|
/* If the output image is zero initialized, we are not working
|
||||||
|
* on a shared base and the input is zero we can skip the next
|
||||||
|
* n1 sectors */
|
||||||
|
if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) {
|
||||||
sector_num += n1;
|
sector_num += n1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* The next 'n1' sectors are allocated in the input image. Copy
|
/* If the output image is being created as a copy on write
|
||||||
only those as they may be followed by unallocated sectors. */
|
* image, assume that sectors which are unallocated in the
|
||||||
n = n1;
|
* input image are present in both the output's and input's
|
||||||
} else {
|
* base images (no need to copy them). */
|
||||||
n1 = n;
|
if (out_baseimg) {
|
||||||
|
if (!(ret & BDRV_BLOCK_DATA)) {
|
||||||
|
sector_num += n1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* The next 'n1' sectors are allocated in the input image.
|
||||||
|
* Copy only those as they may be followed by unallocated
|
||||||
|
* sectors. */
|
||||||
|
nb_sectors = n1;
|
||||||
|
}
|
||||||
|
/* avoid redundant callouts to get_block_status */
|
||||||
|
sector_num_next_status = sector_num + n1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n = MIN(nb_sectors, bufsectors);
|
||||||
|
|
||||||
|
/* round down request length to an aligned sector, but
|
||||||
|
* do not bother doing this on short requests. They happen
|
||||||
|
* when we found an all-zero area, and the next sector to
|
||||||
|
* write will not be sector_num + n. */
|
||||||
|
if (cluster_sectors > 0 && n >= cluster_sectors) {
|
||||||
|
int64_t next_aligned_sector = (sector_num + n);
|
||||||
|
next_aligned_sector -= next_aligned_sector % cluster_sectors;
|
||||||
|
if (sector_num + n > next_aligned_sector) {
|
||||||
|
n = next_aligned_sector - sector_num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = MIN(n, bs_sectors - (sector_num - bs_offset));
|
||||||
|
n1 = n;
|
||||||
|
|
||||||
ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
|
ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("error while reading sector %" PRId64 ": %s",
|
error_report("error while reading sector %" PRId64 ": %s",
|
||||||
@ -1559,14 +1612,20 @@ static int img_convert(int argc, char **argv)
|
|||||||
n -= n1;
|
n -= n1;
|
||||||
buf1 += n1 * 512;
|
buf1 += n1 * 512;
|
||||||
}
|
}
|
||||||
qemu_progress_print(local_progress, 100);
|
qemu_progress_print(100.0 * sector_num / total_sectors, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
if (!ret) {
|
||||||
|
qemu_progress_print(100, 0);
|
||||||
|
}
|
||||||
qemu_progress_end();
|
qemu_progress_end();
|
||||||
free_option_parameters(create_options);
|
free_option_parameters(create_options);
|
||||||
free_option_parameters(param);
|
free_option_parameters(param);
|
||||||
qemu_vfree(buf);
|
qemu_vfree(buf);
|
||||||
|
if (sn_opts) {
|
||||||
|
qemu_opts_del(sn_opts);
|
||||||
|
}
|
||||||
if (out_bs) {
|
if (out_bs) {
|
||||||
bdrv_unref(out_bs);
|
bdrv_unref(out_bs);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,11 @@ is the destination disk image filename
|
|||||||
is a comma separated list of format specific options in a
|
is a comma separated list of format specific options in a
|
||||||
name=value format. Use @code{-o ?} for an overview of the options supported
|
name=value format. Use @code{-o ?} for an overview of the options supported
|
||||||
by the used format or see the format descriptions below for details.
|
by the used format or see the format descriptions below for details.
|
||||||
|
@item snapshot_param
|
||||||
|
is param used for internal snapshot, format is
|
||||||
|
'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]'
|
||||||
|
@item snapshot_id_or_name
|
||||||
|
is deprecated, use snapshot_param instead
|
||||||
|
|
||||||
@item -c
|
@item -c
|
||||||
indicates that target image must be compressed (qcow format only)
|
indicates that target image must be compressed (qcow format only)
|
||||||
@ -179,10 +183,10 @@ Error on reading data
|
|||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
|
||||||
|
|
||||||
Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename}
|
Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated)
|
||||||
using format @var{output_fmt}. It can be optionally compressed (@code{-c}
|
to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
|
||||||
option) or use any format specific options like encryption (@code{-o} option).
|
option) or use any format specific options like encryption (@code{-o} option).
|
||||||
|
|
||||||
Only the formats @code{qcow} and @code{qcow2} support compression. The
|
Only the formats @code{qcow} and @code{qcow2} support compression. The
|
||||||
|
47
qemu-nbd.c
47
qemu-nbd.c
@ -20,6 +20,7 @@
|
|||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
#include "block/nbd.h"
|
#include "block/nbd.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
|
#include "block/snapshot.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -78,8 +79,16 @@ static void usage(const char *name)
|
|||||||
#endif
|
#endif
|
||||||
"\n"
|
"\n"
|
||||||
"Block device options:\n"
|
"Block device options:\n"
|
||||||
|
" -f, --format=FORMAT set image format (raw, qcow2, ...)\n"
|
||||||
" -r, --read-only export read-only\n"
|
" -r, --read-only export read-only\n"
|
||||||
" -s, --snapshot use snapshot file\n"
|
" -s, --snapshot use FILE as an external snapshot, create a temporary\n"
|
||||||
|
" file with backing_file=FILE, redirect the write to\n"
|
||||||
|
" the temporary one\n"
|
||||||
|
" -l, --load-snapshot=SNAPSHOT_PARAM\n"
|
||||||
|
" load an internal snapshot inside FILE and export it\n"
|
||||||
|
" as an read-only device, SNAPSHOT_PARAM format is\n"
|
||||||
|
" 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
|
||||||
|
" '[ID_OR_NAME]'\n"
|
||||||
" -n, --nocache disable host cache\n"
|
" -n, --nocache disable host cache\n"
|
||||||
" --cache=MODE set cache mode (none, writeback, ...)\n"
|
" --cache=MODE set cache mode (none, writeback, ...)\n"
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
@ -315,7 +324,9 @@ int main(int argc, char **argv)
|
|||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
int port = NBD_DEFAULT_PORT;
|
int port = NBD_DEFAULT_PORT;
|
||||||
off_t fd_size;
|
off_t fd_size;
|
||||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t";
|
QemuOpts *sn_opts = NULL;
|
||||||
|
const char *sn_id_or_name = NULL;
|
||||||
|
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:";
|
||||||
struct option lopt[] = {
|
struct option lopt[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "version", 0, NULL, 'V' },
|
{ "version", 0, NULL, 'V' },
|
||||||
@ -328,6 +339,7 @@ int main(int argc, char **argv)
|
|||||||
{ "connect", 1, NULL, 'c' },
|
{ "connect", 1, NULL, 'c' },
|
||||||
{ "disconnect", 0, NULL, 'd' },
|
{ "disconnect", 0, NULL, 'd' },
|
||||||
{ "snapshot", 0, NULL, 's' },
|
{ "snapshot", 0, NULL, 's' },
|
||||||
|
{ "load-snapshot", 1, NULL, 'l' },
|
||||||
{ "nocache", 0, NULL, 'n' },
|
{ "nocache", 0, NULL, 'n' },
|
||||||
{ "cache", 1, NULL, QEMU_NBD_OPT_CACHE },
|
{ "cache", 1, NULL, QEMU_NBD_OPT_CACHE },
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
@ -428,6 +440,17 @@ int main(int argc, char **argv)
|
|||||||
errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg);
|
errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
|
||||||
|
sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);
|
||||||
|
if (!sn_opts) {
|
||||||
|
errx(EXIT_FAILURE, "Failed in parsing snapshot param `%s'",
|
||||||
|
optarg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sn_id_or_name = optarg;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
case 'r':
|
case 'r':
|
||||||
nbdflags |= NBD_FLAG_READ_ONLY;
|
nbdflags |= NBD_FLAG_READ_ONLY;
|
||||||
flags &= ~BDRV_O_RDWR;
|
flags &= ~BDRV_O_RDWR;
|
||||||
@ -581,6 +604,22 @@ int main(int argc, char **argv)
|
|||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sn_opts) {
|
||||||
|
ret = bdrv_snapshot_load_tmp(bs,
|
||||||
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
||||||
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
|
||||||
|
&local_err);
|
||||||
|
} else if (sn_id_or_name) {
|
||||||
|
ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name,
|
||||||
|
&local_err);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
errno = -ret;
|
||||||
|
err(EXIT_FAILURE,
|
||||||
|
"Failed to load snapshot: %s",
|
||||||
|
error_get_pretty(local_err));
|
||||||
|
}
|
||||||
|
|
||||||
fd_size = bdrv_getlength(bs);
|
fd_size = bdrv_getlength(bs);
|
||||||
|
|
||||||
if (partition != -1) {
|
if (partition != -1) {
|
||||||
@ -641,6 +680,10 @@ int main(int argc, char **argv)
|
|||||||
unlink(sockpath);
|
unlink(sockpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sn_opts) {
|
||||||
|
qemu_opts_del(sn_opts);
|
||||||
|
}
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
void *ret;
|
void *ret;
|
||||||
pthread_join(client_thread, &ret);
|
pthread_join(client_thread, &ret);
|
||||||
|
@ -22,12 +22,20 @@ Export QEMU disk image using NBD protocol.
|
|||||||
interface to bind to (default @samp{0.0.0.0})
|
interface to bind to (default @samp{0.0.0.0})
|
||||||
@item -k, --socket=@var{path}
|
@item -k, --socket=@var{path}
|
||||||
Use a unix socket with path @var{path}
|
Use a unix socket with path @var{path}
|
||||||
|
@item -f, --format=@var{format}
|
||||||
|
Set image format as @var{format}
|
||||||
@item -r, --read-only
|
@item -r, --read-only
|
||||||
export read-only
|
export read-only
|
||||||
@item -P, --partition=@var{num}
|
@item -P, --partition=@var{num}
|
||||||
only expose partition @var{num}
|
only expose partition @var{num}
|
||||||
@item -s, --snapshot
|
@item -s, --snapshot
|
||||||
use snapshot file
|
use @var{filename} as an external snapshot, create a temporary
|
||||||
|
file with backing_file=@var{filename}, redirect the write to
|
||||||
|
the temporary one
|
||||||
|
@item -l, --load-snapshot=@var{snapshot_param}
|
||||||
|
load an internal snapshot inside @var{filename} and export it
|
||||||
|
as an read-only device, @var{snapshot_param} format is
|
||||||
|
'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]'
|
||||||
@item -n, --nocache
|
@item -n, --nocache
|
||||||
@itemx --cache=@var{cache}
|
@itemx --cache=@var{cache}
|
||||||
set cache mode to be used with the file. See the documentation of
|
set cache mode to be used with the file. See the documentation of
|
||||||
|
@ -44,7 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
|||||||
_supported_fmt qcow2
|
_supported_fmt qcow2
|
||||||
_supported_proto generic
|
_supported_proto generic
|
||||||
_supported_os Linux
|
_supported_os Linux
|
||||||
|
_default_cache_mode "writethrough"
|
||||||
|
_supported_cache_modes "writethrough" "none"
|
||||||
|
|
||||||
echo "Errors while writing 128 kB"
|
echo "Errors while writing 128 kB"
|
||||||
echo
|
echo
|
||||||
|
@ -44,7 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
|||||||
_supported_fmt qcow2
|
_supported_fmt qcow2
|
||||||
_supported_proto generic
|
_supported_proto generic
|
||||||
_supported_os Linux
|
_supported_os Linux
|
||||||
_unsupported_qemu_io_options --nocache
|
_default_cache_mode "writethrough"
|
||||||
|
_supported_cache_modes "writethrough"
|
||||||
|
|
||||||
size=128M
|
size=128M
|
||||||
|
|
||||||
|
@ -81,32 +81,5 @@ cp "$TEST_IMG" "$TEST_IMG2"
|
|||||||
io_pattern write 512 512 0 1 101
|
io_pattern write 512 512 0 1 101
|
||||||
_compare
|
_compare
|
||||||
|
|
||||||
# Test cluster allocated in one, with IO error
|
|
||||||
cat > "$TEST_DIR/blkdebug.conf"<<EOF
|
|
||||||
[inject-error]
|
|
||||||
event = "read_aio"
|
|
||||||
errno = "5"
|
|
||||||
once ="off"
|
|
||||||
EOF
|
|
||||||
_make_test_img $size
|
|
||||||
cp "$TEST_IMG" "$TEST_IMG2"
|
|
||||||
io_pattern write 512 512 0 1 102
|
|
||||||
TEST_IMG="blkdebug:$TEST_DIR/blkdebug.conf:$TEST_IMG" _compare 2>&1 |\
|
|
||||||
_filter_testdir | _filter_imgfmt
|
|
||||||
|
|
||||||
# Test cluster allocated in one, with different sizes and IO error in the part
|
|
||||||
# that exists only in one image
|
|
||||||
cat > "$TEST_DIR/blkdebug.conf"<<EOF
|
|
||||||
[inject-error]
|
|
||||||
event = "read_aio"
|
|
||||||
errno = "5"
|
|
||||||
once ="off"
|
|
||||||
EOF
|
|
||||||
_make_test_img $size
|
|
||||||
TEST_IMG="$TEST_IMG2" _make_test_img 0
|
|
||||||
io_pattern write 512 512 0 1 102
|
|
||||||
TEST_IMG="blkdebug:$TEST_DIR/blkdebug.conf:$TEST_IMG" _compare 2>&1 |\
|
|
||||||
_filter_testdir | _filter_imgfmt
|
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
status=0
|
status=0
|
||||||
|
@ -37,20 +37,4 @@ wrote 512/512 bytes at offset 512
|
|||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
Content mismatch at offset 512!
|
Content mismatch at offset 512!
|
||||||
1
|
1
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
|
||||||
=== IO: pattern 102
|
|
||||||
wrote 512/512 bytes at offset 512
|
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
|
||||||
qemu-img: Error while reading offset 0: Input/output error
|
|
||||||
4
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
|
|
||||||
=== IO: pattern 102
|
|
||||||
wrote 512/512 bytes at offset 512
|
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
|
||||||
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
|
||||||
Warning: Image size mismatch!
|
|
||||||
4
|
|
||||||
Cleanup
|
Cleanup
|
||||||
|
@ -39,12 +39,12 @@ ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
|
|||||||
=== Enable and disable lazy refcounting on the command line, plus some invalid values ===
|
=== Enable and disable lazy refcounting on the command line, plus some invalid values ===
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
|
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
|
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
|
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
|
||||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off'
|
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off'
|
||||||
@ -63,71 +63,71 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
|
|||||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
|
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
|
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
|
|
||||||
=== No medium ===
|
=== No medium ===
|
||||||
|
|
||||||
Testing: -drive if=floppy
|
Testing: -drive if=floppy
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive if=ide,media=cdrom
|
Testing: -drive if=ide,media=cdrom
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive if=scsi,media=cdrom
|
Testing: -drive if=scsi,media=cdrom
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive if=ide
|
Testing: -drive if=ide
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: Device needs media, but drive is empty
|
||||||
QEMU_PROG: Device initialization failed.
|
QEMU_PROG: Device initialization failed.
|
||||||
QEMU_PROG: Initialization of device ide-hd failed
|
QEMU_PROG: Initialization of device ide-hd failed
|
||||||
|
|
||||||
Testing: -drive if=virtio
|
Testing: -drive if=virtio
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
|
||||||
QEMU_PROG: -drive if=virtio: Device initialization failed.
|
QEMU_PROG: -drive if=virtio: Device initialization failed.
|
||||||
QEMU_PROG: -drive if=virtio: Device initialization failed.
|
QEMU_PROG: -drive if=virtio: Device initialization failed.
|
||||||
QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
|
QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
|
||||||
|
|
||||||
Testing: -drive if=scsi
|
Testing: -drive if=scsi
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty
|
||||||
QEMU_PROG: Device initialization failed.
|
QEMU_PROG: Device initialization failed.
|
||||||
QEMU_PROG: Initialization of device lsi53c895a failed
|
QEMU_PROG: Initialization of device lsi53c895a failed
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device ide-cd,drive=disk
|
Testing: -drive if=none,id=disk -device ide-cd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
|
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device ide-drive,drive=disk
|
Testing: -drive if=none,id=disk -device ide-drive,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
|
||||||
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device ide-hd,drive=disk
|
Testing: -drive if=none,id=disk -device ide-hd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
|
||||||
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
|
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
|
||||||
QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed.
|
QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized
|
QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized
|
||||||
|
|
||||||
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
|
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
|
(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
|
||||||
QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed.
|
QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized
|
QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized
|
||||||
@ -136,81 +136,81 @@ QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized
|
|||||||
=== Read-only ===
|
=== Read-only ===
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: Can't use a read-only drive
|
(qemu) QEMU_PROG: Can't use a read-only drive
|
||||||
QEMU_PROG: Device initialization failed.
|
QEMU_PROG: Device initialization failed.
|
||||||
QEMU_PROG: Initialization of device ide-hd failed
|
QEMU_PROG: Initialization of device ide-hd failed
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
|
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
|
(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
|
||||||
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
|
(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
|
||||||
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
|
||||||
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
|
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
|
|
||||||
=== Cache modes ===
|
=== Cache modes ===
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=none
|
Testing: -drive media=cdrom,cache=none
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=directsync
|
Testing: -drive media=cdrom,cache=directsync
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=writeback
|
Testing: -drive media=cdrom,cache=writeback
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=writethrough
|
Testing: -drive media=cdrom,cache=writethrough
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=unsafe
|
Testing: -drive media=cdrom,cache=unsafe
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive media=cdrom,cache=invalid_value
|
Testing: -drive media=cdrom,cache=invalid_value
|
||||||
QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
|
QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
|
||||||
@ -219,8 +219,8 @@ QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
|
|||||||
=== Specifying the protocol layer ===
|
=== Specifying the protocol layer ===
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
|
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
|
||||||
QEMU X.Y.Z monitor - type 'help' for more information
|
QEMU X.Y.Z monitor - type 'help' for more information
|
||||||
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K
|
||||||
|
|
||||||
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
|
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
|
||||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Can't use 'qcow2' as a block driver for the protocol level
|
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Can't use 'qcow2' as a block driver for the protocol level
|
||||||
|
@ -41,8 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
|||||||
_supported_fmt generic
|
_supported_fmt generic
|
||||||
_supported_proto generic
|
_supported_proto generic
|
||||||
_supported_os Linux
|
_supported_os Linux
|
||||||
_unsupported_qemu_io_options --nocache
|
_default_cache_mode "writethrough"
|
||||||
|
_supported_cache_modes "writethrough"
|
||||||
|
|
||||||
size=128M
|
size=128M
|
||||||
_make_test_img $size
|
_make_test_img $size
|
||||||
|
138
tests/qemu-iotests/058
Executable file
138
tests/qemu-iotests/058
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test export internal snapshot by qemu-nbd, convert it by qemu-img.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 IBM, Inc.
|
||||||
|
#
|
||||||
|
# Based on 029.
|
||||||
|
#
|
||||||
|
# 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=xiawenc@linux.vnet.ibm.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket
|
||||||
|
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
|
||||||
|
|
||||||
|
_cleanup_nbd()
|
||||||
|
{
|
||||||
|
if [ -n "$NBD_SNAPSHOT_PID" ]; then
|
||||||
|
kill "$NBD_SNAPSHOT_PID"
|
||||||
|
fi
|
||||||
|
rm -f "$nbd_unix_socket"
|
||||||
|
}
|
||||||
|
|
||||||
|
_wait_for_nbd()
|
||||||
|
{
|
||||||
|
for ((i = 0; i < 300; i++))
|
||||||
|
do
|
||||||
|
if [ -r "$nbd_unix_socket" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
echo "Failed in check of unix socket created by qemu-nbd"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
converted_image=$TEST_IMG.converted
|
||||||
|
|
||||||
|
_export_nbd_snapshot()
|
||||||
|
{
|
||||||
|
_cleanup_nbd
|
||||||
|
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l $1 &
|
||||||
|
NBD_SNAPSHOT_PID=$!
|
||||||
|
_wait_for_nbd
|
||||||
|
}
|
||||||
|
|
||||||
|
_export_nbd_snapshot1()
|
||||||
|
{
|
||||||
|
_cleanup_nbd
|
||||||
|
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l snapshot.name=$1 &
|
||||||
|
NBD_SNAPSHOT_PID=$!
|
||||||
|
_wait_for_nbd
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_nbd
|
||||||
|
_cleanup_test_img
|
||||||
|
rm -f "$converted_image"
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
. ./common.pattern
|
||||||
|
|
||||||
|
_supported_fmt qcow2
|
||||||
|
_supported_proto file
|
||||||
|
_require_command QEMU_NBD
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== preparing image =="
|
||||||
|
_make_test_img 64M
|
||||||
|
$QEMU_IO -c 'write -P 0xa 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'write -P 0xb 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IMG snapshot -c sn1 "$TEST_IMG"
|
||||||
|
$QEMU_IO -c 'write -P 0xc 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'write -P 0xd 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying the image file with patterns =="
|
||||||
|
$QEMU_IO -c 'read -P 0xc 0x1000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'read -P 0xd 0x2000 0x1000' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
_export_nbd_snapshot sn1
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying the exported snapshot with patterns, method 1 =="
|
||||||
|
$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io
|
||||||
|
|
||||||
|
_export_nbd_snapshot1 sn1
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying the exported snapshot with patterns, method 2 =="
|
||||||
|
$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$nbd_snapshot_img" | _filter_qemu_io
|
||||||
|
|
||||||
|
$QEMU_IMG convert "$TEST_IMG" -l sn1 -O qcow2 "$converted_image"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying the converted snapshot with patterns, method 1 =="
|
||||||
|
$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$converted_image" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$converted_image" | _filter_qemu_io
|
||||||
|
|
||||||
|
$QEMU_IMG convert "$TEST_IMG" -l snapshot.name=sn1 -O qcow2 "$converted_image"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying the converted snapshot with patterns, method 2 =="
|
||||||
|
$QEMU_IO -c 'read -P 0xa 0x1000 0x1000' "$converted_image" | _filter_qemu_io
|
||||||
|
$QEMU_IO -c 'read -P 0xb 0x2000 0x1000' "$converted_image" | _filter_qemu_io
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
44
tests/qemu-iotests/058.out
Normal file
44
tests/qemu-iotests/058.out
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
QA output created by 058
|
||||||
|
|
||||||
|
== preparing image ==
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
|
wrote 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
== verifying the image file with patterns ==
|
||||||
|
read 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying the exported snapshot with patterns, method 1 ==
|
||||||
|
read 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying the exported snapshot with patterns, method 2 ==
|
||||||
|
read 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying the converted snapshot with patterns, method 1 ==
|
||||||
|
read 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying the converted snapshot with patterns, method 2 ==
|
||||||
|
read 4096/4096 bytes at offset 4096
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 8192
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
*** done
|
@ -75,6 +75,11 @@ echo
|
|||||||
echo "=== Testing monolithicFlat with zeroed_grain ==="
|
echo "=== Testing monolithicFlat with zeroed_grain ==="
|
||||||
IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
|
IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== Testing big twoGbMaxExtentFlat ==="
|
||||||
|
IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G
|
||||||
|
$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/'
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== Testing version 3 ==="
|
echo "=== Testing version 3 ==="
|
||||||
_use_sample_img iotest-version3.vmdk.bz2
|
_use_sample_img iotest-version3.vmdk.bz2
|
||||||
|
File diff suppressed because it is too large
Load Diff
86
tests/qemu-iotests/074
Executable file
86
tests/qemu-iotests/074
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
##
|
||||||
|
## qemu-img compare test (qcow2 only ones)
|
||||||
|
##
|
||||||
|
##
|
||||||
|
## Copyright (C) 2013 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=famz@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
echo "Cleanup"
|
||||||
|
_cleanup_test_img
|
||||||
|
rm "${TEST_IMG2}"
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
_compare()
|
||||||
|
{
|
||||||
|
$QEMU_IMG compare "$@" "$TEST_IMG" "${TEST_IMG2}"
|
||||||
|
echo $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
. ./common.pattern
|
||||||
|
|
||||||
|
_supported_fmt qcow2
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
# Setup test basic parameters
|
||||||
|
TEST_IMG2=$TEST_IMG.2
|
||||||
|
CLUSTER_SIZE=4096
|
||||||
|
size=1024M
|
||||||
|
|
||||||
|
# Test cluster allocated in one, with IO error
|
||||||
|
cat > "$TEST_DIR/blkdebug.conf"<<EOF
|
||||||
|
[inject-error]
|
||||||
|
event = "read_aio"
|
||||||
|
errno = "5"
|
||||||
|
once ="off"
|
||||||
|
EOF
|
||||||
|
_make_test_img $size
|
||||||
|
cp "$TEST_IMG" "$TEST_IMG2"
|
||||||
|
io_pattern write 512 512 0 1 102
|
||||||
|
TEST_IMG="blkdebug:$TEST_DIR/blkdebug.conf:$TEST_IMG" _compare 2>&1 |\
|
||||||
|
_filter_testdir | _filter_imgfmt
|
||||||
|
|
||||||
|
# Test cluster allocated in one, with different sizes and IO error in the part
|
||||||
|
# that exists only in one image
|
||||||
|
cat > "$TEST_DIR/blkdebug.conf"<<EOF
|
||||||
|
[inject-error]
|
||||||
|
event = "read_aio"
|
||||||
|
errno = "5"
|
||||||
|
once ="off"
|
||||||
|
EOF
|
||||||
|
_make_test_img $size
|
||||||
|
TEST_IMG="$TEST_IMG2" _make_test_img 0
|
||||||
|
io_pattern write 512 512 0 1 102
|
||||||
|
TEST_IMG="blkdebug:$TEST_DIR/blkdebug.conf:$TEST_IMG" _compare 2>&1 |\
|
||||||
|
_filter_testdir | _filter_imgfmt
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
status=0
|
18
tests/qemu-iotests/074.out
Normal file
18
tests/qemu-iotests/074.out
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
QA output created by 074
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
=== IO: pattern 102
|
||||||
|
wrote 512/512 bytes at offset 512
|
||||||
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
||||||
|
qemu-img: Error while reading offset 0: Input/output error
|
||||||
|
4
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=0
|
||||||
|
=== IO: pattern 102
|
||||||
|
wrote 512/512 bytes at offset 512
|
||||||
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
||||||
|
qemu-img: Error while reading offset 0 of blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
|
||||||
|
Warning: Image size mismatch!
|
||||||
|
4
|
||||||
|
Cleanup
|
@ -161,6 +161,7 @@ cat <<EOF
|
|||||||
QEMU -- $QEMU
|
QEMU -- $QEMU
|
||||||
QEMU_IMG -- $QEMU_IMG
|
QEMU_IMG -- $QEMU_IMG
|
||||||
QEMU_IO -- $QEMU_IO
|
QEMU_IO -- $QEMU_IO
|
||||||
|
QEMU_NBD -- $QEMU_NBD
|
||||||
IMGFMT -- $FULL_IMGFMT_DETAILS
|
IMGFMT -- $FULL_IMGFMT_DETAILS
|
||||||
IMGPROTO -- $FULL_IMGPROTO_DETAILS
|
IMGPROTO -- $FULL_IMGPROTO_DETAILS
|
||||||
PLATFORM -- $FULL_HOST_DETAILS
|
PLATFORM -- $FULL_HOST_DETAILS
|
||||||
@ -242,7 +243,7 @@ do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
reference=$seq.out
|
reference=$seq.out
|
||||||
if (echo $QEMU_IO_OPTIONS | grep -s -- '--nocache' > /dev/null); then
|
if [ "$CACHEMODE" = "none" ]; then
|
||||||
[ -f $seq.out.nocache ] && reference=$seq.out.nocache
|
[ -f $seq.out.nocache ] && reference=$seq.out.nocache
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -42,13 +42,16 @@ expunge=true
|
|||||||
have_test_arg=false
|
have_test_arg=false
|
||||||
randomize=false
|
randomize=false
|
||||||
valgrind=false
|
valgrind=false
|
||||||
|
cachemode=false
|
||||||
rm -f $tmp.list $tmp.tmp $tmp.sed
|
rm -f $tmp.list $tmp.tmp $tmp.sed
|
||||||
|
|
||||||
export IMGFMT=raw
|
export IMGFMT=raw
|
||||||
export IMGFMT_GENERIC=true
|
export IMGFMT_GENERIC=true
|
||||||
export IMGPROTO=file
|
export IMGPROTO=file
|
||||||
export IMGOPTS=""
|
export IMGOPTS=""
|
||||||
|
export CACHEMODE="writeback"
|
||||||
export QEMU_IO_OPTIONS=""
|
export QEMU_IO_OPTIONS=""
|
||||||
|
export CACHEMODE_IS_DEFAULT=true
|
||||||
|
|
||||||
for r
|
for r
|
||||||
do
|
do
|
||||||
@ -113,7 +116,12 @@ s/ .*//p
|
|||||||
IMGOPTS="$r"
|
IMGOPTS="$r"
|
||||||
imgopts=false
|
imgopts=false
|
||||||
continue
|
continue
|
||||||
|
elif $cachemode
|
||||||
|
then
|
||||||
|
CACHEMODE="$r"
|
||||||
|
CACHEMODE_IS_DEFAULT=false
|
||||||
|
cachemode=false
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
xpand=true
|
xpand=true
|
||||||
@ -124,7 +132,7 @@ s/ .*//p
|
|||||||
echo "Usage: $0 [options] [testlist]"'
|
echo "Usage: $0 [options] [testlist]"'
|
||||||
|
|
||||||
common options
|
common options
|
||||||
-v verbose
|
-v verbose
|
||||||
|
|
||||||
check options
|
check options
|
||||||
-raw test raw (default)
|
-raw test raw (default)
|
||||||
@ -140,19 +148,20 @@ check options
|
|||||||
-sheepdog test sheepdog
|
-sheepdog test sheepdog
|
||||||
-nbd test nbd
|
-nbd test nbd
|
||||||
-ssh test ssh
|
-ssh test ssh
|
||||||
-xdiff graphical mode diff
|
-xdiff graphical mode diff
|
||||||
-nocache use O_DIRECT on backing file
|
-nocache use O_DIRECT on backing file
|
||||||
-misalign misalign memory allocations
|
-misalign misalign memory allocations
|
||||||
-n show me, do not run tests
|
-n show me, do not run tests
|
||||||
-o options -o options to pass to qemu-img create/convert
|
-o options -o options to pass to qemu-img create/convert
|
||||||
-T output timestamps
|
-T output timestamps
|
||||||
-r randomize test order
|
-r randomize test order
|
||||||
|
-c mode cache mode
|
||||||
|
|
||||||
testlist options
|
testlist options
|
||||||
-g group[,group...] include tests from these groups
|
-g group[,group...] include tests from these groups
|
||||||
-x group[,group...] exclude tests from these groups
|
-x group[,group...] exclude tests from these groups
|
||||||
NNN include test NNN
|
NNN include test NNN
|
||||||
NNN-NNN include test range (eg. 012-021)
|
NNN-NNN include test range (eg. 012-021)
|
||||||
'
|
'
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
@ -219,7 +228,8 @@ testlist options
|
|||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
-nocache)
|
-nocache)
|
||||||
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --nocache"
|
CACHEMODE="none"
|
||||||
|
CACHEMODE_IS_DEFAULT=false
|
||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@ -258,6 +268,10 @@ testlist options
|
|||||||
imgopts=true
|
imgopts=true
|
||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
|
-c)
|
||||||
|
cachemode=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
-r) # randomize test order
|
-r) # randomize test order
|
||||||
randomize=true
|
randomize=true
|
||||||
xpand=false
|
xpand=false
|
||||||
@ -334,6 +348,9 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
|
|||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Set qemu-io cache mode with $CACHEMODE we have
|
||||||
|
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
|
||||||
|
|
||||||
# Set default options for qemu-img create -o if they were not specified
|
# Set default options for qemu-img create -o if they were not specified
|
||||||
_set_default_imgopts
|
_set_default_imgopts
|
||||||
|
|
||||||
|
@ -157,7 +157,8 @@ _filter_qemu_io()
|
|||||||
_filter_qemu()
|
_filter_qemu()
|
||||||
{
|
{
|
||||||
sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
|
sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
|
||||||
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#'
|
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \
|
||||||
|
-e $'s#\r##' # QEMU monitor uses \r\n line endings
|
||||||
}
|
}
|
||||||
|
|
||||||
# replace problematic QMP output like timestamps
|
# replace problematic QMP output like timestamps
|
||||||
|
@ -387,25 +387,31 @@ _supported_os()
|
|||||||
_notrun "not suitable for this OS: $HOSTOS"
|
_notrun "not suitable for this OS: $HOSTOS"
|
||||||
}
|
}
|
||||||
|
|
||||||
_unsupported_qemu_io_options()
|
_supported_cache_modes()
|
||||||
{
|
{
|
||||||
for bad_opt
|
for mode; do
|
||||||
do
|
if [ "$mode" = "$CACHEMODE" ]; then
|
||||||
for opt in $QEMU_IO_OPTIONS
|
return
|
||||||
do
|
fi
|
||||||
if [ "$bad_opt" = "$opt" ]
|
|
||||||
then
|
|
||||||
_notrun "not suitable for qemu-io option: $bad_opt"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
done
|
||||||
|
_notrun "not suitable for cache mode: $CACHEMODE"
|
||||||
|
}
|
||||||
|
|
||||||
|
_default_cache_mode()
|
||||||
|
{
|
||||||
|
if $CACHEMODE_IS_DEFAULT; then
|
||||||
|
CACHEMODE="$1"
|
||||||
|
QEMU_IO="$QEMU_IO --cache $1"
|
||||||
|
return
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# this test requires that a specified command (executable) exists
|
# this test requires that a specified command (executable) exists
|
||||||
#
|
#
|
||||||
_require_command()
|
_require_command()
|
||||||
{
|
{
|
||||||
[ -x "$1" ] || _notrun "$1 utility required, skipped this test"
|
eval c=\$$1
|
||||||
|
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
|
||||||
}
|
}
|
||||||
|
|
||||||
_full_imgfmt_details()
|
_full_imgfmt_details()
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
030 rw auto backing
|
030 rw auto backing
|
||||||
031 rw auto quick
|
031 rw auto quick
|
||||||
032 rw auto
|
032 rw auto
|
||||||
033 rw auto
|
033 rw auto quick
|
||||||
034 rw auto backing
|
034 rw auto backing
|
||||||
035 rw auto quick
|
035 rw auto quick
|
||||||
036 rw auto quick
|
036 rw auto quick
|
||||||
@ -64,6 +64,7 @@
|
|||||||
055 rw auto
|
055 rw auto
|
||||||
056 rw auto backing
|
056 rw auto backing
|
||||||
057 rw auto
|
057 rw auto
|
||||||
|
058 rw auto
|
||||||
059 rw auto
|
059 rw auto
|
||||||
060 rw auto
|
060 rw auto
|
||||||
061 rw auto
|
061 rw auto
|
||||||
@ -77,3 +78,4 @@
|
|||||||
069 rw auto
|
069 rw auto
|
||||||
070 rw auto
|
070 rw auto
|
||||||
073 rw auto
|
073 rw auto
|
||||||
|
074 rw auto
|
||||||
|
@ -37,6 +37,7 @@ qemu_args = os.environ.get('QEMU', 'qemu').strip().split(' ')
|
|||||||
imgfmt = os.environ.get('IMGFMT', 'raw')
|
imgfmt = os.environ.get('IMGFMT', 'raw')
|
||||||
imgproto = os.environ.get('IMGPROTO', 'file')
|
imgproto = os.environ.get('IMGPROTO', 'file')
|
||||||
test_dir = os.environ.get('TEST_DIR', '/var/tmp')
|
test_dir = os.environ.get('TEST_DIR', '/var/tmp')
|
||||||
|
cachemode = os.environ.get('CACHEMODE')
|
||||||
|
|
||||||
socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper')
|
socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper')
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ class VM(object):
|
|||||||
'''Add a virtio-blk drive to the VM'''
|
'''Add a virtio-blk drive to the VM'''
|
||||||
options = ['if=virtio',
|
options = ['if=virtio',
|
||||||
'format=%s' % imgfmt,
|
'format=%s' % imgfmt,
|
||||||
'cache=none',
|
'cache=%s' % cachemode,
|
||||||
'file=%s' % path,
|
'file=%s' % path,
|
||||||
'id=drive%d' % self._num_drives]
|
'id=drive%d' % self._num_drives]
|
||||||
if opts:
|
if opts:
|
||||||
|
@ -195,7 +195,6 @@ static void test_bh_delete_from_cb(void)
|
|||||||
g_assert(data1.bh == NULL);
|
g_assert(data1.bh == NULL);
|
||||||
|
|
||||||
g_assert(!aio_poll(ctx, false));
|
g_assert(!aio_poll(ctx, false));
|
||||||
g_assert(!aio_poll(ctx, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_bh_delete_from_cb_many(void)
|
static void test_bh_delete_from_cb_many(void)
|
||||||
|
@ -60,11 +60,12 @@ bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs
|
|||||||
bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
|
bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
|
||||||
bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
||||||
bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
||||||
|
bdrv_aio_write_zeroes(void *bs, int64_t sector_num, int nb_sectors, int flags, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x opaque %p"
|
||||||
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
|
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
|
||||||
bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
||||||
bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
||||||
bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
||||||
bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
|
bdrv_co_write_zeroes(void *bs, int64_t sector_num, int nb_sector, int flags) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x"
|
||||||
bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
|
bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
|
||||||
bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
|
bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
|
||||||
|
|
||||||
@ -127,6 +128,7 @@ thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
|
|||||||
|
|
||||||
# block/raw-win32.c
|
# block/raw-win32.c
|
||||||
# block/raw-posix.c
|
# block/raw-posix.c
|
||||||
|
paio_submit_co(int64_t sector_num, int nb_sectors, int type) "sector_num %"PRId64" nb_sectors %d type %d"
|
||||||
paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
|
paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
|
||||||
|
|
||||||
# ioport.c
|
# ioport.c
|
||||||
|
Loading…
x
Reference in New Issue
Block a user