Merge remote-tracking branch 'kwolf/for-anthony' into staging
* kwolf/for-anthony: (38 commits) qemu-iotests: Fix test 031 for qcow2 v3 support qemu-iotests: Add -o and make v3 the default for qcow2 qcow2: Zero write support qemu-iotests: Test backing file COW with zero clusters qemu-iotests: add a simple test for write_zeroes qcow2: Support for feature table header extension qcow2: Support reading zero clusters qcow2: Version 3 images qcow2: Ignore reserved bits in check_refcounts qcow2: Ignore reserved bits in refcount table entries qcow2: Simplify count_cow_clusters qcow2: Refactor qcow2_free_any_clusters qcow2: Ignore reserved bits in L1/L2 entries qcow2: Fail write_compressed when overwriting data qcow2: Ignore reserved bits in count_contiguous_clusters() qcow2: Ignore reserved bits in get_cluster_offset qcow2: Save disk size in snapshot header Specification for qcow2 version 3 qcow2: Fix refcount block allocation during qcow2_alloc_cluster_at() iotests: Resolve test failures caused by hostname ...
This commit is contained in:
commit
1f8bcac09a
172
aio.c
172
aio.c
|
@ -35,7 +35,6 @@ struct AioHandler
|
||||||
IOHandler *io_read;
|
IOHandler *io_read;
|
||||||
IOHandler *io_write;
|
IOHandler *io_write;
|
||||||
AioFlushHandler *io_flush;
|
AioFlushHandler *io_flush;
|
||||||
AioProcessQueue *io_process_queue;
|
|
||||||
int deleted;
|
int deleted;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
QLIST_ENTRY(AioHandler) node;
|
QLIST_ENTRY(AioHandler) node;
|
||||||
|
@ -58,7 +57,6 @@ int qemu_aio_set_fd_handler(int fd,
|
||||||
IOHandler *io_read,
|
IOHandler *io_read,
|
||||||
IOHandler *io_write,
|
IOHandler *io_write,
|
||||||
AioFlushHandler *io_flush,
|
AioFlushHandler *io_flush,
|
||||||
AioProcessQueue *io_process_queue,
|
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
AioHandler *node;
|
AioHandler *node;
|
||||||
|
@ -91,7 +89,6 @@ int qemu_aio_set_fd_handler(int fd,
|
||||||
node->io_read = io_read;
|
node->io_read = io_read;
|
||||||
node->io_write = io_write;
|
node->io_write = io_write;
|
||||||
node->io_flush = io_flush;
|
node->io_flush = io_flush;
|
||||||
node->io_process_queue = io_process_queue;
|
|
||||||
node->opaque = opaque;
|
node->opaque = opaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,131 +99,96 @@ int qemu_aio_set_fd_handler(int fd,
|
||||||
|
|
||||||
void qemu_aio_flush(void)
|
void qemu_aio_flush(void)
|
||||||
{
|
{
|
||||||
AioHandler *node;
|
while (qemu_aio_wait());
|
||||||
int ret;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there are pending emulated aio start them now so flush
|
|
||||||
* will be able to return 1.
|
|
||||||
*/
|
|
||||||
qemu_aio_wait();
|
|
||||||
|
|
||||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
|
||||||
if (node->io_flush) {
|
|
||||||
ret |= node->io_flush(node->opaque);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (qemu_bh_poll() || ret > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int qemu_aio_process_queue(void)
|
bool qemu_aio_wait(void)
|
||||||
{
|
{
|
||||||
AioHandler *node;
|
AioHandler *node;
|
||||||
int ret = 0;
|
fd_set rdfds, wrfds;
|
||||||
|
int max_fd = -1;
|
||||||
|
int ret;
|
||||||
|
bool busy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are callbacks left that have been queued, we need to call then.
|
||||||
|
* Do not call select in this case, because it is possible that the caller
|
||||||
|
* does not need a complete flush (as is the case for qemu_aio_wait loops).
|
||||||
|
*/
|
||||||
|
if (qemu_bh_poll()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
walking_handlers = 1;
|
walking_handlers = 1;
|
||||||
|
|
||||||
|
FD_ZERO(&rdfds);
|
||||||
|
FD_ZERO(&wrfds);
|
||||||
|
|
||||||
|
/* fill fd sets */
|
||||||
|
busy = false;
|
||||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||||
if (node->io_process_queue) {
|
/* If there aren't pending AIO operations, don't invoke callbacks.
|
||||||
if (node->io_process_queue(node->opaque)) {
|
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
||||||
ret = 1;
|
* wait indefinitely.
|
||||||
|
*/
|
||||||
|
if (node->io_flush) {
|
||||||
|
if (node->io_flush(node->opaque) == 0) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
busy = true;
|
||||||
|
}
|
||||||
|
if (!node->deleted && node->io_read) {
|
||||||
|
FD_SET(node->fd, &rdfds);
|
||||||
|
max_fd = MAX(max_fd, node->fd + 1);
|
||||||
|
}
|
||||||
|
if (!node->deleted && node->io_write) {
|
||||||
|
FD_SET(node->fd, &wrfds);
|
||||||
|
max_fd = MAX(max_fd, node->fd + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
walking_handlers = 0;
|
walking_handlers = 0;
|
||||||
|
|
||||||
return ret;
|
/* No AIO operations? Get us out of here */
|
||||||
}
|
if (!busy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void qemu_aio_wait(void)
|
/* wait until next event */
|
||||||
{
|
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (qemu_bh_poll())
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there are callbacks left that have been queued, we need to call then.
|
|
||||||
* Return afterwards to avoid waiting needlessly in select().
|
|
||||||
*/
|
|
||||||
if (qemu_aio_process_queue())
|
|
||||||
return;
|
|
||||||
|
|
||||||
do {
|
|
||||||
AioHandler *node;
|
|
||||||
fd_set rdfds, wrfds;
|
|
||||||
int max_fd = -1;
|
|
||||||
|
|
||||||
|
/* if we have any readable fds, dispatch event */
|
||||||
|
if (ret > 0) {
|
||||||
walking_handlers = 1;
|
walking_handlers = 1;
|
||||||
|
|
||||||
FD_ZERO(&rdfds);
|
/* we have to walk very carefully in case
|
||||||
FD_ZERO(&wrfds);
|
* qemu_aio_set_fd_handler is called while we're walking */
|
||||||
|
node = QLIST_FIRST(&aio_handlers);
|
||||||
|
while (node) {
|
||||||
|
AioHandler *tmp;
|
||||||
|
|
||||||
/* fill fd sets */
|
if (!node->deleted &&
|
||||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
FD_ISSET(node->fd, &rdfds) &&
|
||||||
/* If there aren't pending AIO operations, don't invoke callbacks.
|
node->io_read) {
|
||||||
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
|
node->io_read(node->opaque);
|
||||||
* wait indefinitely.
|
|
||||||
*/
|
|
||||||
if (node->io_flush && node->io_flush(node->opaque) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!node->deleted && node->io_read) {
|
|
||||||
FD_SET(node->fd, &rdfds);
|
|
||||||
max_fd = MAX(max_fd, node->fd + 1);
|
|
||||||
}
|
}
|
||||||
if (!node->deleted && node->io_write) {
|
if (!node->deleted &&
|
||||||
FD_SET(node->fd, &wrfds);
|
FD_ISSET(node->fd, &wrfds) &&
|
||||||
max_fd = MAX(max_fd, node->fd + 1);
|
node->io_write) {
|
||||||
|
node->io_write(node->opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = node;
|
||||||
|
node = QLIST_NEXT(node, node);
|
||||||
|
|
||||||
|
if (tmp->deleted) {
|
||||||
|
QLIST_REMOVE(tmp, node);
|
||||||
|
g_free(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
walking_handlers = 0;
|
walking_handlers = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* No AIO operations? Get us out of here */
|
return true;
|
||||||
if (max_fd == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* wait until next event */
|
|
||||||
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
|
|
||||||
if (ret == -1 && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* if we have any readable fds, dispatch event */
|
|
||||||
if (ret > 0) {
|
|
||||||
walking_handlers = 1;
|
|
||||||
|
|
||||||
/* we have to walk very carefully in case
|
|
||||||
* qemu_aio_set_fd_handler is called while we're walking */
|
|
||||||
node = QLIST_FIRST(&aio_handlers);
|
|
||||||
while (node) {
|
|
||||||
AioHandler *tmp;
|
|
||||||
|
|
||||||
if (!node->deleted &&
|
|
||||||
FD_ISSET(node->fd, &rdfds) &&
|
|
||||||
node->io_read) {
|
|
||||||
node->io_read(node->opaque);
|
|
||||||
}
|
|
||||||
if (!node->deleted &&
|
|
||||||
FD_ISSET(node->fd, &wrfds) &&
|
|
||||||
node->io_write) {
|
|
||||||
node->io_write(node->opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = node;
|
|
||||||
node = QLIST_NEXT(node, node);
|
|
||||||
|
|
||||||
if (tmp->deleted) {
|
|
||||||
QLIST_REMOVE(tmp, node);
|
|
||||||
g_free(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walking_handlers = 0;
|
|
||||||
}
|
|
||||||
} while (ret == 0);
|
|
||||||
}
|
}
|
||||||
|
|
17
block.c
17
block.c
|
@ -80,6 +80,8 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||||
void *opaque,
|
void *opaque,
|
||||||
bool is_write);
|
bool is_write);
|
||||||
static void coroutine_fn bdrv_co_do_rw(void *opaque);
|
static void coroutine_fn bdrv_co_do_rw(void *opaque);
|
||||||
|
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors);
|
||||||
|
|
||||||
static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
|
static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
|
||||||
bool is_write, double elapsed_time, uint64_t *wait);
|
bool is_write, double elapsed_time, uint64_t *wait);
|
||||||
|
@ -812,10 +814,13 @@ unlink_and_fail:
|
||||||
|
|
||||||
void bdrv_close(BlockDriverState *bs)
|
void bdrv_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
|
bdrv_flush(bs);
|
||||||
if (bs->drv) {
|
if (bs->drv) {
|
||||||
if (bs->job) {
|
if (bs->job) {
|
||||||
block_job_cancel_sync(bs->job);
|
block_job_cancel_sync(bs->job);
|
||||||
}
|
}
|
||||||
|
bdrv_drain_all();
|
||||||
|
|
||||||
if (bs == bs_snapshots) {
|
if (bs == bs_snapshots) {
|
||||||
bs_snapshots = NULL;
|
bs_snapshots = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1705,8 +1710,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
|
||||||
|
|
||||||
if (drv->bdrv_co_write_zeroes &&
|
if (drv->bdrv_co_write_zeroes &&
|
||||||
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
||||||
ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
|
ret = bdrv_co_do_write_zeroes(bs, cluster_sector_num,
|
||||||
cluster_nb_sectors);
|
cluster_nb_sectors);
|
||||||
} else {
|
} else {
|
||||||
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
|
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
|
||||||
&bounce_qiov);
|
&bounce_qiov);
|
||||||
|
@ -1816,9 +1821,15 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* TODO Emulate only part of misaligned requests instead of letting block
|
||||||
|
* drivers return -ENOTSUP and emulate everything */
|
||||||
|
|
||||||
/* First try the efficient write zeroes operation */
|
/* First try the efficient write zeroes operation */
|
||||||
if (drv->bdrv_co_write_zeroes) {
|
if (drv->bdrv_co_write_zeroes) {
|
||||||
return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
|
ret = drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
|
||||||
|
if (ret != -ENOTSUP) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||||
|
|
|
@ -103,7 +103,7 @@ static int cow_open(BlockDriverState *bs, int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX(hch): right now these functions are extremely ineffcient.
|
* XXX(hch): right now these functions are extremely inefficient.
|
||||||
* We should just read the whole bitmap we'll need in one go instead.
|
* We should just read the whole bitmap we'll need in one go instead.
|
||||||
*/
|
*/
|
||||||
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
|
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
|
||||||
|
|
10
block/curl.c
10
block/curl.c
|
@ -89,19 +89,17 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CURL_POLL_IN:
|
case CURL_POLL_IN:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
|
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s);
|
||||||
NULL, s);
|
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_OUT:
|
case CURL_POLL_OUT:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
|
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s);
|
||||||
NULL, s);
|
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_INOUT:
|
case CURL_POLL_INOUT:
|
||||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
|
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
|
||||||
curl_aio_flush, NULL, s);
|
curl_aio_flush, s);
|
||||||
break;
|
break;
|
||||||
case CURL_POLL_REMOVE:
|
case CURL_POLL_REMOVE:
|
||||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ iscsi_set_events(IscsiLun *iscsilun)
|
||||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
|
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
|
||||||
(iscsi_which_events(iscsi) & POLLOUT)
|
(iscsi_which_events(iscsi) & POLLOUT)
|
||||||
? iscsi_process_write : NULL,
|
? iscsi_process_write : NULL,
|
||||||
iscsi_process_flush, NULL, iscsilun);
|
iscsi_process_flush, iscsilun);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -682,7 +682,7 @@ static void iscsi_close(BlockDriverState *bs)
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
|
||||||
iscsi_destroy_context(iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
|
||||||
qemu_co_mutex_lock(&s->send_mutex);
|
qemu_co_mutex_lock(&s->send_mutex);
|
||||||
s->send_coroutine = qemu_coroutine_self();
|
s->send_coroutine = qemu_coroutine_self();
|
||||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
|
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
|
||||||
nbd_have_request, NULL, s);
|
nbd_have_request, s);
|
||||||
rc = nbd_send_request(s->sock, request);
|
rc = nbd_send_request(s->sock, request);
|
||||||
if (rc >= 0 && iov) {
|
if (rc >= 0 && iov) {
|
||||||
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
|
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
|
||||||
|
@ -212,7 +212,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
||||||
nbd_have_request, NULL, s);
|
nbd_have_request, s);
|
||||||
s->send_coroutine = NULL;
|
s->send_coroutine = NULL;
|
||||||
qemu_co_mutex_unlock(&s->send_mutex);
|
qemu_co_mutex_unlock(&s->send_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -285,7 +285,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
|
||||||
* kick the reply mechanism. */
|
* kick the reply mechanism. */
|
||||||
socket_set_nonblock(sock);
|
socket_set_nonblock(sock);
|
||||||
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
|
||||||
nbd_have_request, NULL, s);
|
nbd_have_request, s);
|
||||||
|
|
||||||
s->sock = sock;
|
s->sock = sock;
|
||||||
s->size = size;
|
s->size = size;
|
||||||
|
@ -305,7 +305,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
|
||||||
request.len = 0;
|
request.len = 0;
|
||||||
nbd_send_request(s->sock, &request);
|
nbd_send_request(s->sock, &request);
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL);
|
||||||
closesocket(s->sock);
|
closesocket(s->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||||
|
|
||||||
l2_table = *table;
|
l2_table = *table;
|
||||||
|
|
||||||
if (old_l2_offset == 0) {
|
if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
|
||||||
/* if there was no old l2 table, clear the new table */
|
/* if there was no old l2 table, clear the new table */
|
||||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,7 +203,8 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
||||||
|
|
||||||
/* if there was an old l2 table, read it from the disk */
|
/* if there was an old l2 table, read it from the disk */
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
|
||||||
ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
|
ret = qcow2_cache_get(bs, s->l2_table_cache,
|
||||||
|
old_l2_offset & L1E_OFFSET_MASK,
|
||||||
(void**) &old_table);
|
(void**) &old_table);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -246,28 +247,44 @@ fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks how many clusters in a given L2 table are contiguous in the image
|
||||||
|
* file. As soon as one of the flags in the bitmask stop_flags changes compared
|
||||||
|
* to the first cluster, the search is stopped and the cluster is not counted
|
||||||
|
* as contiguous. (This allows it, for example, to stop at the first compressed
|
||||||
|
* cluster which may require a different handling)
|
||||||
|
*/
|
||||||
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||||
uint64_t *l2_table, uint64_t start, uint64_t mask)
|
uint64_t *l2_table, uint64_t start, uint64_t stop_flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
|
uint64_t mask = stop_flags | L2E_OFFSET_MASK;
|
||||||
|
uint64_t offset = be64_to_cpu(l2_table[0]) & mask;
|
||||||
|
|
||||||
if (!offset)
|
if (!offset)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = start; i < start + nb_clusters; i++)
|
for (i = start; i < start + nb_clusters; i++) {
|
||||||
if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
|
uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
|
||||||
|
if (offset + (uint64_t) i * cluster_size != l2_entry) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (i - start);
|
return (i - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
|
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i;
|
||||||
|
|
||||||
while(nb_clusters-- && l2_table[i] == 0)
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
i++;
|
int type = qcow2_get_cluster_type(be64_to_cpu(l2_table[i]));
|
||||||
|
|
||||||
|
if (type != QCOW2_CLUSTER_UNALLOCATED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -367,11 +384,9 @@ out:
|
||||||
*
|
*
|
||||||
* on exit, *num is the number of contiguous sectors we can read.
|
* on exit, *num is the number of contiguous sectors we can read.
|
||||||
*
|
*
|
||||||
* Return 0, if the offset is found
|
* Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
|
||||||
* Return -errno, otherwise.
|
* cases.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num, uint64_t *cluster_offset)
|
int *num, uint64_t *cluster_offset)
|
||||||
{
|
{
|
||||||
|
@ -407,19 +422,19 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
/* seek the the l2 offset in the l1 table */
|
/* seek the the l2 offset in the l1 table */
|
||||||
|
|
||||||
l1_index = offset >> l1_bits;
|
l1_index = offset >> l1_bits;
|
||||||
if (l1_index >= s->l1_size)
|
if (l1_index >= s->l1_size) {
|
||||||
|
ret = QCOW2_CLUSTER_UNALLOCATED;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
l2_offset = s->l1_table[l1_index];
|
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
|
||||||
|
if (!l2_offset) {
|
||||||
/* seek the l2 table of the given l2 offset */
|
ret = QCOW2_CLUSTER_UNALLOCATED;
|
||||||
|
|
||||||
if (!l2_offset)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* load the l2 table in memory */
|
/* load the l2 table in memory */
|
||||||
|
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
|
||||||
ret = l2_load(bs, l2_offset, &l2_table);
|
ret = l2_load(bs, l2_offset, &l2_table);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -431,26 +446,44 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||||
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
||||||
|
|
||||||
if (!*cluster_offset) {
|
ret = qcow2_get_cluster_type(*cluster_offset);
|
||||||
|
switch (ret) {
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
|
/* Compressed clusters can only be processed one by one */
|
||||||
|
c = 1;
|
||||||
|
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
|
||||||
|
break;
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
|
&l2_table[l2_index], 0,
|
||||||
|
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
||||||
|
*cluster_offset = 0;
|
||||||
|
break;
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
/* how many empty clusters ? */
|
/* how many empty clusters ? */
|
||||||
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
||||||
} else {
|
*cluster_offset = 0;
|
||||||
|
break;
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
/* how many allocated clusters ? */
|
/* how many allocated clusters ? */
|
||||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
&l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
|
&l2_table[l2_index], 0,
|
||||||
|
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
||||||
|
*cluster_offset &= L2E_OFFSET_MASK;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
|
||||||
nb_available = (c * s->cluster_sectors);
|
nb_available = (c * s->cluster_sectors);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (nb_available > nb_needed)
|
if (nb_available > nb_needed)
|
||||||
nb_available = nb_needed;
|
nb_available = nb_needed;
|
||||||
|
|
||||||
*num = nb_available - index_in_cluster;
|
*num = nb_available - index_in_cluster;
|
||||||
|
|
||||||
*cluster_offset &=~QCOW_OFLAG_COPIED;
|
return ret;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -483,13 +516,13 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l2_offset = s->l1_table[l1_index];
|
|
||||||
|
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
|
||||||
|
|
||||||
/* seek the l2 table of the given l2 offset */
|
/* seek the l2 table of the given l2 offset */
|
||||||
|
|
||||||
if (l2_offset & QCOW_OFLAG_COPIED) {
|
if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
|
||||||
/* load the l2 table in memory */
|
/* load the l2 table in memory */
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
|
||||||
ret = l2_load(bs, l2_offset, &l2_table);
|
ret = l2_load(bs, l2_offset, &l2_table);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -505,7 +538,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||||
if (l2_offset) {
|
if (l2_offset) {
|
||||||
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
||||||
}
|
}
|
||||||
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
|
l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the cluster offset for the given disk offset */
|
/* find the cluster offset for the given disk offset */
|
||||||
|
@ -546,15 +579,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compression can't overwrite anything. Fail if the cluster was already
|
||||||
|
* allocated. */
|
||||||
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||||
if (cluster_offset & QCOW_OFLAG_COPIED) {
|
if (cluster_offset & L2E_OFFSET_MASK) {
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cluster_offset)
|
|
||||||
qcow2_free_any_clusters(bs, cluster_offset, 1);
|
|
||||||
|
|
||||||
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
|
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
|
||||||
if (cluster_offset < 0) {
|
if (cluster_offset < 0) {
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
@ -663,8 +695,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
*/
|
*/
|
||||||
if (j != 0) {
|
if (j != 0) {
|
||||||
for (i = 0; i < j; i++) {
|
for (i = 0; i < j; i++) {
|
||||||
qcow2_free_any_clusters(bs,
|
qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
|
||||||
be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,29 +713,28 @@ err:
|
||||||
static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
|
static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
|
||||||
uint64_t *l2_table, int l2_index)
|
uint64_t *l2_table, int l2_index)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i;
|
||||||
uint64_t cluster_offset;
|
|
||||||
|
|
||||||
while (i < nb_clusters) {
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
|
uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
&l2_table[l2_index], i, 0);
|
int cluster_type = qcow2_get_cluster_type(l2_entry);
|
||||||
if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
|
|
||||||
|
switch(cluster_type) {
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
if (l2_entry & QCOW_OFLAG_COPIED) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
i += count_contiguous_free_clusters(nb_clusters - i,
|
|
||||||
&l2_table[l2_index + i]);
|
|
||||||
if (i >= nb_clusters) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
|
|
||||||
|
|
||||||
if ((cluster_offset & QCOW_OFLAG_COPIED) ||
|
|
||||||
(cluster_offset & QCOW_OFLAG_COMPRESSED))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
assert(i <= nb_clusters);
|
assert(i <= nb_clusters);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -842,10 +872,14 @@ again:
|
||||||
* Check how many clusters are already allocated and don't need COW, and how
|
* Check how many clusters are already allocated and don't need COW, and how
|
||||||
* many need a new allocation.
|
* many need a new allocation.
|
||||||
*/
|
*/
|
||||||
if (cluster_offset & QCOW_OFLAG_COPIED) {
|
if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
|
||||||
|
&& (cluster_offset & QCOW_OFLAG_COPIED))
|
||||||
|
{
|
||||||
/* We keep all QCOW_OFLAG_COPIED clusters */
|
/* We keep all QCOW_OFLAG_COPIED clusters */
|
||||||
keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
keep_clusters =
|
||||||
&l2_table[l2_index], 0, 0);
|
count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||||
|
&l2_table[l2_index], 0,
|
||||||
|
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
|
||||||
assert(keep_clusters <= nb_clusters);
|
assert(keep_clusters <= nb_clusters);
|
||||||
nb_clusters -= keep_clusters;
|
nb_clusters -= keep_clusters;
|
||||||
} else {
|
} else {
|
||||||
|
@ -860,7 +894,7 @@ again:
|
||||||
cluster_offset = 0;
|
cluster_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster_offset &= ~QCOW_OFLAG_COPIED;
|
cluster_offset &= L2E_OFFSET_MASK;
|
||||||
|
|
||||||
/* If there is something left to allocate, do that now */
|
/* If there is something left to allocate, do that now */
|
||||||
*m = (QCowL2Meta) {
|
*m = (QCowL2Meta) {
|
||||||
|
@ -931,7 +965,7 @@ again:
|
||||||
fail:
|
fail:
|
||||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
fail_put:
|
fail_put:
|
||||||
if (nb_clusters > 0) {
|
if (m->nb_clusters > 0) {
|
||||||
QLIST_REMOVE(m, next_in_flight);
|
QLIST_REMOVE(m, next_in_flight);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1015,9 +1049,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
uint64_t old_offset;
|
uint64_t old_offset;
|
||||||
|
|
||||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
old_offset &= ~QCOW_OFLAG_COPIED;
|
if ((old_offset & L2E_OFFSET_MASK) == 0) {
|
||||||
|
|
||||||
if (old_offset == 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,3 +1102,75 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This zeroes as many clusters of nb_clusters as possible at once (i.e.
|
||||||
|
* all clusters in the same L2 table) and returns the number of zeroed
|
||||||
|
* clusters.
|
||||||
|
*/
|
||||||
|
static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||||
|
unsigned int nb_clusters)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
uint64_t *l2_table;
|
||||||
|
int l2_index;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limit nb_clusters to one L2 table */
|
||||||
|
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||||
|
|
||||||
|
for (i = 0; i < nb_clusters; i++) {
|
||||||
|
uint64_t old_offset;
|
||||||
|
|
||||||
|
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||||
|
|
||||||
|
/* Update L2 entries */
|
||||||
|
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
|
||||||
|
if (old_offset & QCOW_OFLAG_COMPRESSED) {
|
||||||
|
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
|
||||||
|
qcow2_free_any_clusters(bs, old_offset, 1);
|
||||||
|
} else {
|
||||||
|
l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nb_clusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
|
||||||
|
{
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
unsigned int nb_clusters;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* The zero flag is only supported by version 3 and newer */
|
||||||
|
if (s->qcow_version < 3) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each L2 table is handled by its own loop iteration */
|
||||||
|
nb_clusters = size_to_clusters(s, nb_sectors << BDRV_SECTOR_BITS);
|
||||||
|
|
||||||
|
while (nb_clusters > 0) {
|
||||||
|
ret = zero_single_l2(bs, offset, nb_clusters);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_clusters -= ret;
|
||||||
|
offset += (ret * s->cluster_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||||
if (refcount_table_index < s->refcount_table_size) {
|
if (refcount_table_index < s->refcount_table_size) {
|
||||||
|
|
||||||
uint64_t refcount_block_offset =
|
uint64_t refcount_block_offset =
|
||||||
s->refcount_table[refcount_table_index];
|
s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
|
||||||
|
|
||||||
/* If it's already there, we're done */
|
/* If it's already there, we're done */
|
||||||
if (refcount_block_offset) {
|
if (refcount_block_offset) {
|
||||||
|
@ -400,7 +400,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_block;
|
return 0;
|
||||||
|
|
||||||
fail_table:
|
fail_table:
|
||||||
g_free(new_table);
|
g_free(new_table);
|
||||||
|
@ -587,6 +587,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t cluster_index;
|
uint64_t cluster_index;
|
||||||
|
uint64_t old_free_cluster_index;
|
||||||
int i, refcount, ret;
|
int i, refcount, ret;
|
||||||
|
|
||||||
/* Check how many clusters there are free */
|
/* Check how many clusters there are free */
|
||||||
|
@ -602,11 +603,16 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And then allocate them */
|
/* And then allocate them */
|
||||||
|
old_free_cluster_index = s->free_cluster_index;
|
||||||
|
s->free_cluster_index = cluster_index + i;
|
||||||
|
|
||||||
ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
|
ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->free_cluster_index = old_free_cluster_index;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,32 +679,35 @@ void qcow2_free_clusters(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free_any_clusters
|
* Free a cluster using its L2 entry (handles clusters of all types, e.g.
|
||||||
*
|
* normal cluster, compressed cluster, etc.)
|
||||||
* free clusters according to its type: compressed or not
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void qcow2_free_any_clusters(BlockDriverState *bs,
|
void qcow2_free_any_clusters(BlockDriverState *bs,
|
||||||
uint64_t cluster_offset, int nb_clusters)
|
uint64_t l2_entry, int nb_clusters)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
/* free the cluster */
|
switch (qcow2_get_cluster_type(l2_entry)) {
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
{
|
||||||
int nb_csectors;
|
int nb_csectors;
|
||||||
nb_csectors = ((cluster_offset >> s->csize_shift) &
|
nb_csectors = ((l2_entry >> s->csize_shift) &
|
||||||
s->csize_mask) + 1;
|
s->csize_mask) + 1;
|
||||||
qcow2_free_clusters(bs,
|
qcow2_free_clusters(bs,
|
||||||
(cluster_offset & s->cluster_offset_mask) & ~511,
|
(l2_entry & s->cluster_offset_mask) & ~511,
|
||||||
nb_csectors * 512);
|
nb_csectors * 512);
|
||||||
return;
|
}
|
||||||
|
break;
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
|
||||||
|
nb_clusters << s->cluster_bits);
|
||||||
|
break;
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -758,7 +767,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||||
l2_offset = l1_table[i];
|
l2_offset = l1_table[i];
|
||||||
if (l2_offset) {
|
if (l2_offset) {
|
||||||
old_l2_offset = l2_offset;
|
old_l2_offset = l2_offset;
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= L1E_OFFSET_MASK;
|
||||||
|
|
||||||
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
|
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
|
||||||
(void**) &l2_table);
|
(void**) &l2_table);
|
||||||
|
@ -790,10 +799,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||||
/* compressed clusters are never modified */
|
/* compressed clusters are never modified */
|
||||||
refcount = 2;
|
refcount = 2;
|
||||||
} else {
|
} else {
|
||||||
|
uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
|
||||||
if (addend != 0) {
|
if (addend != 0) {
|
||||||
refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
|
refcount = update_cluster_refcount(bs, cluster_index, addend);
|
||||||
} else {
|
} else {
|
||||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
refcount = get_refcount(bs, cluster_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refcount < 0) {
|
if (refcount < 0) {
|
||||||
|
@ -931,7 +941,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
int check_copied)
|
int check_copied)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t *l2_table, offset;
|
uint64_t *l2_table, l2_entry;
|
||||||
int i, l2_size, nb_csectors, refcount;
|
int i, l2_size, nb_csectors, refcount;
|
||||||
|
|
||||||
/* Read L2 table from disk */
|
/* Read L2 table from disk */
|
||||||
|
@ -943,54 +953,70 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
|
||||||
/* Do the actual checks */
|
/* Do the actual checks */
|
||||||
for(i = 0; i < s->l2_size; i++) {
|
for(i = 0; i < s->l2_size; i++) {
|
||||||
offset = be64_to_cpu(l2_table[i]);
|
l2_entry = be64_to_cpu(l2_table[i]);
|
||||||
if (offset != 0) {
|
|
||||||
if (offset & QCOW_OFLAG_COMPRESSED) {
|
switch (qcow2_get_cluster_type(l2_entry)) {
|
||||||
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
if (offset & QCOW_OFLAG_COPIED) {
|
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
||||||
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
|
if (l2_entry & QCOW_OFLAG_COPIED) {
|
||||||
"copied flag must never be set for compressed "
|
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
|
||||||
"clusters\n", offset >> s->cluster_bits);
|
"copied flag must never be set for compressed "
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
"clusters\n", l2_entry >> s->cluster_bits);
|
||||||
res->corruptions++;
|
l2_entry &= ~QCOW_OFLAG_COPIED;
|
||||||
|
res->corruptions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark cluster as used */
|
||||||
|
nb_csectors = ((l2_entry >> s->csize_shift) &
|
||||||
|
s->csize_mask) + 1;
|
||||||
|
l2_entry &= s->cluster_offset_mask;
|
||||||
|
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||||
|
l2_entry & ~511, nb_csectors * 512);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
if ((l2_entry & L2E_OFFSET_MASK) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
{
|
||||||
|
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
|
||||||
|
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
|
||||||
|
|
||||||
|
if (check_copied) {
|
||||||
|
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
||||||
|
if (refcount < 0) {
|
||||||
|
fprintf(stderr, "Can't get refcount for offset %"
|
||||||
|
PRIx64 ": %s\n", l2_entry, strerror(-refcount));
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
|
||||||
/* Mark cluster as used */
|
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
||||||
nb_csectors = ((offset >> s->csize_shift) &
|
PRIx64 " refcount=%d\n", l2_entry, refcount);
|
||||||
s->csize_mask) + 1;
|
|
||||||
offset &= s->cluster_offset_mask;
|
|
||||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
|
||||||
offset & ~511, nb_csectors * 512);
|
|
||||||
} else {
|
|
||||||
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
|
|
||||||
if (check_copied) {
|
|
||||||
uint64_t entry = offset;
|
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
|
||||||
refcount = get_refcount(bs, offset >> s->cluster_bits);
|
|
||||||
if (refcount < 0) {
|
|
||||||
fprintf(stderr, "Can't get refcount for offset %"
|
|
||||||
PRIx64 ": %s\n", entry, strerror(-refcount));
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
|
|
||||||
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
|
||||||
PRIx64 " refcount=%d\n", entry, refcount);
|
|
||||||
res->corruptions++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark cluster as used */
|
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
|
||||||
inc_refcounts(bs, res, refcount_table,refcount_table_size,
|
|
||||||
offset, s->cluster_size);
|
|
||||||
|
|
||||||
/* Correct offsets are cluster aligned */
|
|
||||||
if (offset & (s->cluster_size - 1)) {
|
|
||||||
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
|
||||||
"properly aligned; L2 entry corrupted.\n", offset);
|
|
||||||
res->corruptions++;
|
res->corruptions++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark cluster as used */
|
||||||
|
inc_refcounts(bs, res, refcount_table,refcount_table_size,
|
||||||
|
offset, s->cluster_size);
|
||||||
|
|
||||||
|
/* Correct offsets are cluster aligned */
|
||||||
|
if (offset & (s->cluster_size - 1)) {
|
||||||
|
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
|
||||||
|
"properly aligned; L2 entry corrupted.\n", offset);
|
||||||
|
res->corruptions++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,7 +1087,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark L2 table as used */
|
/* Mark L2 table as used */
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= L1E_OFFSET_MASK;
|
||||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||||
l2_offset, s->cluster_size);
|
l2_offset, s->cluster_size);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||||
|
|
||||||
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||||
uint64_t vm_state_size_large;
|
uint64_t vm_state_size_large;
|
||||||
|
uint64_t disk_size;
|
||||||
} QCowSnapshotExtraData;
|
} QCowSnapshotExtraData;
|
||||||
|
|
||||||
void qcow2_free_snapshots(BlockDriverState *bs)
|
void qcow2_free_snapshots(BlockDriverState *bs)
|
||||||
|
@ -117,6 +118,12 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
||||||
sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
|
sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extra_data_size >= 16) {
|
||||||
|
sn->disk_size = be64_to_cpu(extra.disk_size);
|
||||||
|
} else {
|
||||||
|
sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read snapshot ID */
|
/* Read snapshot ID */
|
||||||
sn->id_str = g_malloc(id_str_size + 1);
|
sn->id_str = g_malloc(id_str_size + 1);
|
||||||
ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
|
ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
|
||||||
|
@ -197,6 +204,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||||
|
|
||||||
memset(&extra, 0, sizeof(extra));
|
memset(&extra, 0, sizeof(extra));
|
||||||
extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
|
extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
|
||||||
|
extra.disk_size = cpu_to_be64(sn->disk_size);
|
||||||
|
|
||||||
id_str_size = strlen(sn->id_str);
|
id_str_size = strlen(sn->id_str);
|
||||||
name_size = strlen(sn->name);
|
name_size = strlen(sn->name);
|
||||||
|
@ -330,6 +338,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||||
sn->id_str = g_strdup(sn_info->id_str);
|
sn->id_str = g_strdup(sn_info->id_str);
|
||||||
sn->name = g_strdup(sn_info->name);
|
sn->name = g_strdup(sn_info->name);
|
||||||
|
|
||||||
|
sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||||
sn->vm_state_size = sn_info->vm_state_size;
|
sn->vm_state_size = sn_info->vm_state_size;
|
||||||
sn->date_sec = sn_info->date_sec;
|
sn->date_sec = sn_info->date_sec;
|
||||||
sn->date_nsec = sn_info->date_nsec;
|
sn->date_nsec = sn_info->date_nsec;
|
||||||
|
@ -426,6 +435,13 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||||
}
|
}
|
||||||
sn = &s->snapshots[snapshot_index];
|
sn = &s->snapshots[snapshot_index];
|
||||||
|
|
||||||
|
if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
|
||||||
|
error_report("qcow2: Loading snapshots with different disk "
|
||||||
|
"size is not implemented");
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that the current L1 table is big enough to contain the whole
|
* Make sure that the current L1 table is big enough to contain the whole
|
||||||
* L1 table of the snapshot. If the snapshot L1 table is smaller, the
|
* L1 table of the snapshot. If the snapshot L1 table is smaller, the
|
||||||
|
|
252
block/qcow2.c
252
block/qcow2.c
|
@ -54,6 +54,7 @@ typedef struct {
|
||||||
} QCowExtension;
|
} QCowExtension;
|
||||||
#define QCOW2_EXT_MAGIC_END 0
|
#define QCOW2_EXT_MAGIC_END 0
|
||||||
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
|
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
|
||||||
|
#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
|
||||||
|
|
||||||
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
|
|
||||||
if (buf_size >= sizeof(QCowHeader) &&
|
if (buf_size >= sizeof(QCowHeader) &&
|
||||||
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
||||||
be32_to_cpu(cow_header->version) >= QCOW_VERSION)
|
be32_to_cpu(cow_header->version) >= 2)
|
||||||
return 100;
|
return 100;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -76,7 +77,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
* return 0 upon success, non-0 otherwise
|
* return 0 upon success, non-0 otherwise
|
||||||
*/
|
*/
|
||||||
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||||
uint64_t end_offset)
|
uint64_t end_offset, void **p_feature_table)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
QCowExtension ext;
|
QCowExtension ext;
|
||||||
|
@ -134,6 +135,18 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
|
||||||
|
if (p_feature_table != NULL) {
|
||||||
|
void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
|
||||||
|
ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_feature_table = feature_table;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* unknown magic - save it in case we need to rewrite the header */
|
/* unknown magic - save it in case we need to rewrite the header */
|
||||||
{
|
{
|
||||||
|
@ -169,6 +182,37 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char msg[64];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
|
bs->device_name, "qcow2", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report_unsupported_feature(BlockDriverState *bs,
|
||||||
|
Qcow2Feature *table, uint64_t mask)
|
||||||
|
{
|
||||||
|
while (table && table->name[0] != '\0') {
|
||||||
|
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
||||||
|
if (mask & (1 << table->bit)) {
|
||||||
|
report_unsupported(bs, "%.46s",table->name);
|
||||||
|
mask &= ~(1 << table->bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask) {
|
||||||
|
report_unsupported(bs, "Unknown incompatible feature: %" PRIx64, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int qcow2_open(BlockDriverState *bs, int flags)
|
static int qcow2_open(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
@ -199,14 +243,73 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (header.version != QCOW_VERSION) {
|
if (header.version < 2 || header.version > 3) {
|
||||||
char version[64];
|
report_unsupported(bs, "QCOW version %d", header.version);
|
||||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
|
||||||
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
|
||||||
bs->device_name, "qcow2", version);
|
|
||||||
ret = -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->qcow_version = header.version;
|
||||||
|
|
||||||
|
/* Initialise version 3 header fields */
|
||||||
|
if (header.version == 2) {
|
||||||
|
header.incompatible_features = 0;
|
||||||
|
header.compatible_features = 0;
|
||||||
|
header.autoclear_features = 0;
|
||||||
|
header.refcount_order = 4;
|
||||||
|
header.header_length = 72;
|
||||||
|
} else {
|
||||||
|
be64_to_cpus(&header.incompatible_features);
|
||||||
|
be64_to_cpus(&header.compatible_features);
|
||||||
|
be64_to_cpus(&header.autoclear_features);
|
||||||
|
be32_to_cpus(&header.refcount_order);
|
||||||
|
be32_to_cpus(&header.header_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.header_length > sizeof(header)) {
|
||||||
|
s->unknown_header_fields_size = header.header_length - sizeof(header);
|
||||||
|
s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
|
||||||
|
ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
|
||||||
|
s->unknown_header_fields_size);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.backing_file_offset) {
|
||||||
|
ext_end = header.backing_file_offset;
|
||||||
|
} else {
|
||||||
|
ext_end = 1 << header.cluster_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle feature bits */
|
||||||
|
s->incompatible_features = header.incompatible_features;
|
||||||
|
s->compatible_features = header.compatible_features;
|
||||||
|
s->autoclear_features = header.autoclear_features;
|
||||||
|
|
||||||
|
if (s->incompatible_features != 0) {
|
||||||
|
void *feature_table = NULL;
|
||||||
|
qcow2_read_extensions(bs, header.header_length, ext_end,
|
||||||
|
&feature_table);
|
||||||
|
report_unsupported_feature(bs, feature_table,
|
||||||
|
s->incompatible_features);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bs->read_only && s->autoclear_features != 0) {
|
||||||
|
s->autoclear_features = 0;
|
||||||
|
qcow2_update_header(bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check support for various header values */
|
||||||
|
if (header.refcount_order != 4) {
|
||||||
|
report_unsupported(bs, "%d bit reference counts",
|
||||||
|
1 << header.refcount_order);
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -280,12 +383,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||||
QLIST_INIT(&s->cluster_allocs);
|
QLIST_INIT(&s->cluster_allocs);
|
||||||
|
|
||||||
/* read qcow2 extensions */
|
/* read qcow2 extensions */
|
||||||
if (header.backing_file_offset) {
|
if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) {
|
||||||
ext_end = header.backing_file_offset;
|
|
||||||
} else {
|
|
||||||
ext_end = s->cluster_size;
|
|
||||||
}
|
|
||||||
if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -321,6 +419,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
g_free(s->unknown_header_fields);
|
||||||
cleanup_unknown_header_ext(bs);
|
cleanup_unknown_header_ext(bs);
|
||||||
qcow2_free_snapshots(bs);
|
qcow2_free_snapshots(bs);
|
||||||
qcow2_refcount_close(bs);
|
qcow2_refcount_close(bs);
|
||||||
|
@ -449,7 +548,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
|
qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
|
||||||
cur_nr_sectors * 512);
|
cur_nr_sectors * 512);
|
||||||
|
|
||||||
if (!cluster_offset) {
|
switch (ret) {
|
||||||
|
case QCOW2_CLUSTER_UNALLOCATED:
|
||||||
|
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
/* read from the base image */
|
/* read from the base image */
|
||||||
|
@ -469,7 +569,17 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
/* Note: in this case, no need to wait */
|
/* Note: in this case, no need to wait */
|
||||||
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
|
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
|
||||||
}
|
}
|
||||||
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
break;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_ZERO:
|
||||||
|
if (s->qcow_version < 3) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
/* add AIO support for compressed blocks ? */
|
/* add AIO support for compressed blocks ? */
|
||||||
ret = qcow2_decompress_cluster(bs, cluster_offset);
|
ret = qcow2_decompress_cluster(bs, cluster_offset);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -479,7 +589,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
qemu_iovec_from_buffer(&hd_qiov,
|
qemu_iovec_from_buffer(&hd_qiov,
|
||||||
s->cluster_cache + index_in_cluster * 512,
|
s->cluster_cache + index_in_cluster * 512,
|
||||||
512 * cur_nr_sectors);
|
512 * cur_nr_sectors);
|
||||||
} else {
|
break;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
if ((cluster_offset & 511) != 0) {
|
if ((cluster_offset & 511) != 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -520,6 +632,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
qemu_iovec_from_buffer(&hd_qiov, cluster_data,
|
qemu_iovec_from_buffer(&hd_qiov, cluster_data,
|
||||||
512 * cur_nr_sectors);
|
512 * cur_nr_sectors);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
ret = -EIO;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining_sectors -= cur_nr_sectors;
|
remaining_sectors -= cur_nr_sectors;
|
||||||
|
@ -671,7 +789,9 @@ static void qcow2_close(BlockDriverState *bs)
|
||||||
qcow2_cache_destroy(bs, s->l2_table_cache);
|
qcow2_cache_destroy(bs, s->l2_table_cache);
|
||||||
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
qcow2_cache_destroy(bs, s->refcount_block_cache);
|
||||||
|
|
||||||
|
g_free(s->unknown_header_fields);
|
||||||
cleanup_unknown_header_ext(bs);
|
cleanup_unknown_header_ext(bs);
|
||||||
|
|
||||||
g_free(s->cluster_cache);
|
g_free(s->cluster_cache);
|
||||||
qemu_vfree(s->cluster_data);
|
qemu_vfree(s->cluster_data);
|
||||||
qcow2_refcount_close(bs);
|
qcow2_refcount_close(bs);
|
||||||
|
@ -745,10 +865,10 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t total_size;
|
uint64_t total_size;
|
||||||
uint32_t refcount_table_clusters;
|
uint32_t refcount_table_clusters;
|
||||||
|
size_t header_length;
|
||||||
Qcow2UnknownHeaderExtension *uext;
|
Qcow2UnknownHeaderExtension *uext;
|
||||||
|
|
||||||
buf = qemu_blockalign(bs, buflen);
|
buf = qemu_blockalign(bs, buflen);
|
||||||
memset(buf, 0, s->cluster_size);
|
|
||||||
|
|
||||||
/* Header structure */
|
/* Header structure */
|
||||||
header = (QCowHeader*) buf;
|
header = (QCowHeader*) buf;
|
||||||
|
@ -758,12 +878,14 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header_length = sizeof(*header) + s->unknown_header_fields_size;
|
||||||
total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||||
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
|
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
|
||||||
|
|
||||||
*header = (QCowHeader) {
|
*header = (QCowHeader) {
|
||||||
|
/* Version 2 fields */
|
||||||
.magic = cpu_to_be32(QCOW_MAGIC),
|
.magic = cpu_to_be32(QCOW_MAGIC),
|
||||||
.version = cpu_to_be32(QCOW_VERSION),
|
.version = cpu_to_be32(s->qcow_version),
|
||||||
.backing_file_offset = 0,
|
.backing_file_offset = 0,
|
||||||
.backing_file_size = 0,
|
.backing_file_size = 0,
|
||||||
.cluster_bits = cpu_to_be32(s->cluster_bits),
|
.cluster_bits = cpu_to_be32(s->cluster_bits),
|
||||||
|
@ -775,10 +897,42 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||||
.refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
|
.refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
|
||||||
.nb_snapshots = cpu_to_be32(s->nb_snapshots),
|
.nb_snapshots = cpu_to_be32(s->nb_snapshots),
|
||||||
.snapshots_offset = cpu_to_be64(s->snapshots_offset),
|
.snapshots_offset = cpu_to_be64(s->snapshots_offset),
|
||||||
|
|
||||||
|
/* Version 3 fields */
|
||||||
|
.incompatible_features = cpu_to_be64(s->incompatible_features),
|
||||||
|
.compatible_features = cpu_to_be64(s->compatible_features),
|
||||||
|
.autoclear_features = cpu_to_be64(s->autoclear_features),
|
||||||
|
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
|
||||||
|
.header_length = cpu_to_be32(header_length),
|
||||||
};
|
};
|
||||||
|
|
||||||
buf += sizeof(*header);
|
/* For older versions, write a shorter header */
|
||||||
buflen -= sizeof(*header);
|
switch (s->qcow_version) {
|
||||||
|
case 2:
|
||||||
|
ret = offsetof(QCowHeader, incompatible_features);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ret = sizeof(*header);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += ret;
|
||||||
|
buflen -= ret;
|
||||||
|
memset(buf, 0, buflen);
|
||||||
|
|
||||||
|
/* Preserve any unknown field in the header */
|
||||||
|
if (s->unknown_header_fields_size) {
|
||||||
|
if (buflen < s->unknown_header_fields_size) {
|
||||||
|
ret = -ENOSPC;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf, s->unknown_header_fields, s->unknown_header_fields_size);
|
||||||
|
buf += s->unknown_header_fields_size;
|
||||||
|
buflen -= s->unknown_header_fields_size;
|
||||||
|
}
|
||||||
|
|
||||||
/* Backing file format header extension */
|
/* Backing file format header extension */
|
||||||
if (*bs->backing_format) {
|
if (*bs->backing_format) {
|
||||||
|
@ -793,6 +947,19 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||||
buflen -= ret;
|
buflen -= ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Feature table */
|
||||||
|
Qcow2Feature features[] = {
|
||||||
|
/* no feature defined yet */
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
|
||||||
|
features, sizeof(features), buflen);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
buf += ret;
|
||||||
|
buflen -= ret;
|
||||||
|
|
||||||
/* Keep unknown header extensions */
|
/* Keep unknown header extensions */
|
||||||
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
|
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
|
||||||
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
|
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
|
||||||
|
@ -910,7 +1077,7 @@ static int preallocate(BlockDriverState *bs)
|
||||||
static int qcow2_create2(const char *filename, int64_t total_size,
|
static int qcow2_create2(const char *filename, int64_t total_size,
|
||||||
const char *backing_file, const char *backing_format,
|
const char *backing_file, const char *backing_format,
|
||||||
int flags, size_t cluster_size, int prealloc,
|
int flags, size_t cluster_size, int prealloc,
|
||||||
QEMUOptionParameter *options)
|
QEMUOptionParameter *options, int version)
|
||||||
{
|
{
|
||||||
/* Calculate cluster_bits */
|
/* Calculate cluster_bits */
|
||||||
int cluster_bits;
|
int cluster_bits;
|
||||||
|
@ -954,13 +1121,15 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||||
/* Write the header */
|
/* Write the header */
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
header.magic = cpu_to_be32(QCOW_MAGIC);
|
header.magic = cpu_to_be32(QCOW_MAGIC);
|
||||||
header.version = cpu_to_be32(QCOW_VERSION);
|
header.version = cpu_to_be32(version);
|
||||||
header.cluster_bits = cpu_to_be32(cluster_bits);
|
header.cluster_bits = cpu_to_be32(cluster_bits);
|
||||||
header.size = cpu_to_be64(0);
|
header.size = cpu_to_be64(0);
|
||||||
header.l1_table_offset = cpu_to_be64(0);
|
header.l1_table_offset = cpu_to_be64(0);
|
||||||
header.l1_size = cpu_to_be32(0);
|
header.l1_size = cpu_to_be32(0);
|
||||||
header.refcount_table_offset = cpu_to_be64(cluster_size);
|
header.refcount_table_offset = cpu_to_be64(cluster_size);
|
||||||
header.refcount_table_clusters = cpu_to_be32(1);
|
header.refcount_table_clusters = cpu_to_be32(1);
|
||||||
|
header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
|
||||||
|
header.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);
|
||||||
|
@ -1042,6 +1211,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
|
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
|
||||||
int prealloc = 0;
|
int prealloc = 0;
|
||||||
|
int version = 2;
|
||||||
|
|
||||||
/* Read out options */
|
/* Read out options */
|
||||||
while (options && options->name) {
|
while (options && options->name) {
|
||||||
|
@ -1067,6 +1237,16 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
|
||||||
options->value.s);
|
options->value.s);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
|
||||||
|
if (!options->value.s || !strcmp(options->value.s, "0.10")) {
|
||||||
|
version = 2;
|
||||||
|
} else if (!strcmp(options->value.s, "1.1")) {
|
||||||
|
version = 3;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid compatibility level: '%s'\n",
|
||||||
|
options->value.s);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
options++;
|
options++;
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1258,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
|
return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
|
||||||
cluster_size, prealloc, options);
|
cluster_size, prealloc, options, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcow2_make_empty(BlockDriverState *bs)
|
static int qcow2_make_empty(BlockDriverState *bs)
|
||||||
|
@ -1101,6 +1281,26 @@ static int qcow2_make_empty(BlockDriverState *bs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
|
||||||
|
int64_t sector_num, int nb_sectors)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
BDRVQcowState *s = bs->opaque;
|
||||||
|
|
||||||
|
/* Emulate misaligned zero writes */
|
||||||
|
if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whatever is left can use real zero clusters */
|
||||||
|
qemu_co_mutex_lock(&s->lock);
|
||||||
|
ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS,
|
||||||
|
nb_sectors);
|
||||||
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
|
static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors)
|
int64_t sector_num, int nb_sectors)
|
||||||
{
|
{
|
||||||
|
@ -1329,6 +1529,11 @@ static QEMUOptionParameter qcow2_create_options[] = {
|
||||||
.type = OPT_SIZE,
|
.type = OPT_SIZE,
|
||||||
.help = "Virtual disk size"
|
.help = "Virtual disk size"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_COMPAT_LEVEL,
|
||||||
|
.type = OPT_STRING,
|
||||||
|
.help = "Compatibility level (0.10 or 1.1)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = BLOCK_OPT_BACKING_FILE,
|
.name = BLOCK_OPT_BACKING_FILE,
|
||||||
.type = OPT_STRING,
|
.type = OPT_STRING,
|
||||||
|
@ -1373,6 +1578,7 @@ static BlockDriver bdrv_qcow2 = {
|
||||||
.bdrv_co_writev = qcow2_co_writev,
|
.bdrv_co_writev = qcow2_co_writev,
|
||||||
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
|
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
|
||||||
|
|
||||||
|
.bdrv_co_write_zeroes = qcow2_co_write_zeroes,
|
||||||
.bdrv_co_discard = qcow2_co_discard,
|
.bdrv_co_discard = qcow2_co_discard,
|
||||||
.bdrv_truncate = qcow2_truncate,
|
.bdrv_truncate = qcow2_truncate,
|
||||||
.bdrv_write_compressed = qcow2_write_compressed,
|
.bdrv_write_compressed = qcow2_write_compressed,
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
//#define DEBUG_EXT
|
//#define DEBUG_EXT
|
||||||
|
|
||||||
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
|
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
|
||||||
#define QCOW_VERSION 2
|
|
||||||
|
|
||||||
#define QCOW_CRYPT_NONE 0
|
#define QCOW_CRYPT_NONE 0
|
||||||
#define QCOW_CRYPT_AES 1
|
#define QCOW_CRYPT_AES 1
|
||||||
|
@ -44,6 +43,8 @@
|
||||||
#define QCOW_OFLAG_COPIED (1LL << 63)
|
#define QCOW_OFLAG_COPIED (1LL << 63)
|
||||||
/* indicate that the cluster is compressed (they never have the copied flag) */
|
/* indicate that the cluster is compressed (they never have the copied flag) */
|
||||||
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
|
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
|
||||||
|
/* The cluster reads as all zeros */
|
||||||
|
#define QCOW_OFLAG_ZERO (1LL << 0)
|
||||||
|
|
||||||
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
|
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
|
||||||
|
|
||||||
|
@ -71,6 +72,14 @@ typedef struct QCowHeader {
|
||||||
uint32_t refcount_table_clusters;
|
uint32_t refcount_table_clusters;
|
||||||
uint32_t nb_snapshots;
|
uint32_t nb_snapshots;
|
||||||
uint64_t snapshots_offset;
|
uint64_t snapshots_offset;
|
||||||
|
|
||||||
|
/* The following fields are only valid for version >= 3 */
|
||||||
|
uint64_t incompatible_features;
|
||||||
|
uint64_t compatible_features;
|
||||||
|
uint64_t autoclear_features;
|
||||||
|
|
||||||
|
uint32_t refcount_order;
|
||||||
|
uint32_t header_length;
|
||||||
} QCowHeader;
|
} QCowHeader;
|
||||||
|
|
||||||
typedef struct QCowSnapshot {
|
typedef struct QCowSnapshot {
|
||||||
|
@ -78,6 +87,7 @@ typedef struct QCowSnapshot {
|
||||||
uint32_t l1_size;
|
uint32_t l1_size;
|
||||||
char *id_str;
|
char *id_str;
|
||||||
char *name;
|
char *name;
|
||||||
|
uint64_t disk_size;
|
||||||
uint64_t vm_state_size;
|
uint64_t vm_state_size;
|
||||||
uint32_t date_sec;
|
uint32_t date_sec;
|
||||||
uint32_t date_nsec;
|
uint32_t date_nsec;
|
||||||
|
@ -94,6 +104,18 @@ typedef struct Qcow2UnknownHeaderExtension {
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
} Qcow2UnknownHeaderExtension;
|
} Qcow2UnknownHeaderExtension;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
QCOW2_FEAT_TYPE_INCOMPATIBLE = 0,
|
||||||
|
QCOW2_FEAT_TYPE_COMPATIBLE = 1,
|
||||||
|
QCOW2_FEAT_TYPE_AUTOCLEAR = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Qcow2Feature {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t bit;
|
||||||
|
char name[46];
|
||||||
|
} QEMU_PACKED Qcow2Feature;
|
||||||
|
|
||||||
typedef struct BDRVQcowState {
|
typedef struct BDRVQcowState {
|
||||||
int cluster_bits;
|
int cluster_bits;
|
||||||
int cluster_size;
|
int cluster_size;
|
||||||
|
@ -134,6 +156,14 @@ typedef struct BDRVQcowState {
|
||||||
QCowSnapshot *snapshots;
|
QCowSnapshot *snapshots;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
|
int qcow_version;
|
||||||
|
|
||||||
|
uint64_t incompatible_features;
|
||||||
|
uint64_t compatible_features;
|
||||||
|
uint64_t autoclear_features;
|
||||||
|
|
||||||
|
size_t unknown_header_fields_size;
|
||||||
|
void* unknown_header_fields;
|
||||||
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
|
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
|
||||||
} BDRVQcowState;
|
} BDRVQcowState;
|
||||||
|
|
||||||
|
@ -164,6 +194,19 @@ typedef struct QCowL2Meta
|
||||||
QLIST_ENTRY(QCowL2Meta) next_in_flight;
|
QLIST_ENTRY(QCowL2Meta) next_in_flight;
|
||||||
} QCowL2Meta;
|
} QCowL2Meta;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
QCOW2_CLUSTER_UNALLOCATED,
|
||||||
|
QCOW2_CLUSTER_NORMAL,
|
||||||
|
QCOW2_CLUSTER_COMPRESSED,
|
||||||
|
QCOW2_CLUSTER_ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
|
||||||
|
#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
|
||||||
|
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
|
||||||
|
|
||||||
|
#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
|
||||||
|
|
||||||
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
|
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
|
||||||
{
|
{
|
||||||
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
||||||
|
@ -181,6 +224,19 @@ static inline int64_t align_offset(int64_t offset, int n)
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
||||||
|
{
|
||||||
|
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
||||||
|
return QCOW2_CLUSTER_COMPRESSED;
|
||||||
|
} else if (l2_entry & QCOW_OFLAG_ZERO) {
|
||||||
|
return QCOW2_CLUSTER_ZERO;
|
||||||
|
} else if (!(l2_entry & L2E_OFFSET_MASK)) {
|
||||||
|
return QCOW2_CLUSTER_UNALLOCATED;
|
||||||
|
} else {
|
||||||
|
return QCOW2_CLUSTER_NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME Need qcow2_ prefix to global functions
|
// FIXME Need qcow2_ prefix to global functions
|
||||||
|
|
||||||
|
@ -227,6 +283,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
|
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
|
||||||
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||||
int nb_sectors);
|
int nb_sectors);
|
||||||
|
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
|
||||||
|
|
||||||
/* qcow2-snapshot.c functions */
|
/* qcow2-snapshot.c functions */
|
||||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
|
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
|
||||||
|
|
|
@ -504,7 +504,7 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
|
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
|
||||||
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
|
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
|
||||||
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
|
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
|
||||||
NULL, qemu_rbd_aio_flush_cb, NULL, s);
|
NULL, qemu_rbd_aio_flush_cb, s);
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -525,8 +525,7 @@ static void qemu_rbd_close(BlockDriverState *bs)
|
||||||
|
|
||||||
close(s->fds[0]);
|
close(s->fds[0]);
|
||||||
close(s->fds[1]);
|
close(s->fds[1]);
|
||||||
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
|
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);
|
||||||
NULL);
|
|
||||||
|
|
||||||
rbd_close(s->image);
|
rbd_close(s->image);
|
||||||
rados_ioctx_destroy(s->io_ctx);
|
rados_ioctx_destroy(s->io_ctx);
|
||||||
|
|
|
@ -799,8 +799,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request,
|
qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
|
||||||
NULL, s);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -973,7 +972,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||||
qemu_co_mutex_lock(&s->lock);
|
qemu_co_mutex_lock(&s->lock);
|
||||||
s->co_send = qemu_coroutine_self();
|
s->co_send = qemu_coroutine_self();
|
||||||
qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
|
qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
|
||||||
aio_flush_request, NULL, s);
|
aio_flush_request, s);
|
||||||
socket_set_cork(s->fd, 1);
|
socket_set_cork(s->fd, 1);
|
||||||
|
|
||||||
/* send a header */
|
/* send a header */
|
||||||
|
@ -995,7 +994,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||||
|
|
||||||
socket_set_cork(s->fd, 0);
|
socket_set_cork(s->fd, 0);
|
||||||
qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
|
qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
|
||||||
aio_flush_request, NULL, s);
|
aio_flush_request, s);
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1135,7 +1134,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
|
||||||
if (s->fd >= 0) {
|
if (s->fd >= 0) {
|
||||||
closesocket(s->fd);
|
closesocket(s->fd);
|
||||||
}
|
}
|
||||||
|
@ -1349,7 +1348,7 @@ static void sd_close(BlockDriverState *bs)
|
||||||
error_report("%s, %s", sd_strerror(rsp->result), s->name);
|
error_report("%s, %s", sd_strerror(rsp->result), s->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
|
||||||
closesocket(s->fd);
|
closesocket(s->fd);
|
||||||
if (s->cache_enabled) {
|
if (s->cache_enabled) {
|
||||||
closesocket(s->flush_fd);
|
closesocket(s->flush_fd);
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#define BLOCK_OPT_TABLE_SIZE "table_size"
|
#define BLOCK_OPT_TABLE_SIZE "table_size"
|
||||||
#define BLOCK_OPT_PREALLOC "preallocation"
|
#define BLOCK_OPT_PREALLOC "preallocation"
|
||||||
#define BLOCK_OPT_SUBFMT "subformat"
|
#define BLOCK_OPT_SUBFMT "subformat"
|
||||||
|
#define BLOCK_OPT_COMPAT_LEVEL "compat"
|
||||||
|
|
||||||
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
|
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
|
||||||
|
|
||||||
|
|
10
cmd.c
10
cmd.c
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "qemu-aio.h"
|
#include "qemu-aio.h"
|
||||||
|
#include "main-loop.h"
|
||||||
|
|
||||||
#define _(x) x /* not gettext support yet */
|
#define _(x) x /* not gettext support yet */
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ static void prep_fetchline(void *opaque)
|
||||||
{
|
{
|
||||||
int *fetchable = opaque;
|
int *fetchable = opaque;
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
|
qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
|
||||||
*fetchable= 1;
|
*fetchable= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,12 +194,11 @@ void command_loop(void)
|
||||||
if (!prompted) {
|
if (!prompted) {
|
||||||
printf("%s", get_prompt());
|
printf("%s", get_prompt());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
|
qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
|
||||||
NULL, &fetchable);
|
|
||||||
prompted = 1;
|
prompted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_aio_wait();
|
main_loop_wait(false);
|
||||||
|
|
||||||
if (!fetchable) {
|
if (!fetchable) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -221,7 +221,7 @@ void command_loop(void)
|
||||||
prompted = 0;
|
prompted = 0;
|
||||||
fetchable = 0;
|
fetchable = 0;
|
||||||
}
|
}
|
||||||
qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
|
qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from libxcmd/input.c */
|
/* from libxcmd/input.c */
|
||||||
|
|
|
@ -18,7 +18,7 @@ The first cluster of a qcow2 image contains the file header:
|
||||||
QCOW magic string ("QFI\xfb")
|
QCOW magic string ("QFI\xfb")
|
||||||
|
|
||||||
4 - 7: version
|
4 - 7: version
|
||||||
Version number (only valid value is 2)
|
Version number (valid values are 2 and 3)
|
||||||
|
|
||||||
8 - 15: backing_file_offset
|
8 - 15: backing_file_offset
|
||||||
Offset into the image file at which the backing file name
|
Offset into the image file at which the backing file name
|
||||||
|
@ -67,12 +67,45 @@ The first cluster of a qcow2 image contains the file header:
|
||||||
Offset into the image file at which the snapshot table
|
Offset into the image file at which the snapshot table
|
||||||
starts. Must be aligned to a cluster boundary.
|
starts. Must be aligned to a cluster boundary.
|
||||||
|
|
||||||
|
If the version is 3 or higher, the header has the following additional fields.
|
||||||
|
For version 2, the values are assumed to be zero, unless specified otherwise
|
||||||
|
in the description of a field.
|
||||||
|
|
||||||
|
72 - 79: incompatible_features
|
||||||
|
Bitmask of incompatible features. An implementation must
|
||||||
|
fail to open an image if an unknown bit is set.
|
||||||
|
|
||||||
|
Bits 0-63: Reserved (set to 0)
|
||||||
|
|
||||||
|
80 - 87: compatible_features
|
||||||
|
Bitmask of compatible features. An implementation can
|
||||||
|
safely ignore any unknown bits that are set.
|
||||||
|
|
||||||
|
Bits 0-63: Reserved (set to 0)
|
||||||
|
|
||||||
|
88 - 95: autoclear_features
|
||||||
|
Bitmask of auto-clear features. An implementation may only
|
||||||
|
write to an image with unknown auto-clear features if it
|
||||||
|
clears the respective bits from this field first.
|
||||||
|
|
||||||
|
Bits 0-63: Reserved (set to 0)
|
||||||
|
|
||||||
|
96 - 99: refcount_order
|
||||||
|
Describes the width of a reference count block entry (width
|
||||||
|
in bits = 1 << refcount_order). For version 2 images, the
|
||||||
|
order is always assumed to be 4 (i.e. the width is 16 bits).
|
||||||
|
|
||||||
|
100 - 103: header_length
|
||||||
|
Length of the header structure in bytes. For version 2
|
||||||
|
images, the length is always assumed to be 72 bytes.
|
||||||
|
|
||||||
Directly after the image header, optional sections called header extensions can
|
Directly after the image header, optional sections called header extensions can
|
||||||
be stored. Each extension has a structure like the following:
|
be stored. Each extension has a structure like the following:
|
||||||
|
|
||||||
Byte 0 - 3: Header extension type:
|
Byte 0 - 3: Header extension type:
|
||||||
0x00000000 - End of the header extension area
|
0x00000000 - End of the header extension area
|
||||||
0xE2792ACA - Backing file format name
|
0xE2792ACA - Backing file format name
|
||||||
|
0x6803f857 - Feature name table
|
||||||
other - Unknown header extension, can be safely
|
other - Unknown header extension, can be safely
|
||||||
ignored
|
ignored
|
||||||
|
|
||||||
|
@ -83,9 +116,37 @@ be stored. Each extension has a structure like the following:
|
||||||
n - m: Padding to round up the header extension size to the next
|
n - m: Padding to round up the header extension size to the next
|
||||||
multiple of 8.
|
multiple of 8.
|
||||||
|
|
||||||
|
Unless stated otherwise, each header extension type shall appear at most once
|
||||||
|
in the same image.
|
||||||
|
|
||||||
The remaining space between the end of the header extension area and the end of
|
The remaining space between the end of the header extension area and the end of
|
||||||
the first cluster can be used for other data. Usually, the backing file name is
|
the first cluster can be used for the backing file name. It is not allowed to
|
||||||
stored there.
|
store other data here, so that an implementation can safely modify the header
|
||||||
|
and add extensions without harming data of compatible features that it
|
||||||
|
doesn't support. Compatible features that need space for additional data can
|
||||||
|
use a header extension.
|
||||||
|
|
||||||
|
|
||||||
|
== Feature name table ==
|
||||||
|
|
||||||
|
The feature name table is an optional header extension that contains the name
|
||||||
|
for features used by the image. It can be used by applications that don't know
|
||||||
|
the respective feature (e.g. because the feature was introduced only later) to
|
||||||
|
display a useful error message.
|
||||||
|
|
||||||
|
The number of entries in the feature name table is determined by the length of
|
||||||
|
the header extension data. Each entry look like this:
|
||||||
|
|
||||||
|
Byte 0: Type of feature (select feature bitmap)
|
||||||
|
0: Incompatible feature
|
||||||
|
1: Compatible feature
|
||||||
|
2: Autoclear feature
|
||||||
|
|
||||||
|
1: Bit number within the selected feature bitmap (valid
|
||||||
|
values: 0-63)
|
||||||
|
|
||||||
|
2 - 47: Feature name (padded with zeros, but not necessarily null
|
||||||
|
terminated if it has full length)
|
||||||
|
|
||||||
|
|
||||||
== Host cluster management ==
|
== Host cluster management ==
|
||||||
|
@ -126,9 +187,11 @@ Refcount table entry:
|
||||||
been allocated. All refcounts managed by this refcount block
|
been allocated. All refcounts managed by this refcount block
|
||||||
are 0.
|
are 0.
|
||||||
|
|
||||||
Refcount block entry:
|
Refcount block entry (x = refcount_bits - 1):
|
||||||
|
|
||||||
Bit 0 - 15: Reference count of the cluster
|
Bit 0 - x: Reference count of the cluster. If refcount_bits implies a
|
||||||
|
sub-byte width, note that bit 0 means the least significant
|
||||||
|
bit in this context.
|
||||||
|
|
||||||
|
|
||||||
== Cluster mapping ==
|
== Cluster mapping ==
|
||||||
|
@ -168,9 +231,29 @@ L1 table entry:
|
||||||
refcount is exactly one. This information is only accurate
|
refcount is exactly one. This information is only accurate
|
||||||
in the active L1 table.
|
in the active L1 table.
|
||||||
|
|
||||||
L2 table entry (for normal clusters):
|
L2 table entry:
|
||||||
|
|
||||||
Bit 0 - 8: Reserved (set to 0)
|
Bit 0 - 61: Cluster descriptor
|
||||||
|
|
||||||
|
62: 0 for standard clusters
|
||||||
|
1 for compressed clusters
|
||||||
|
|
||||||
|
63: 0 for a cluster that is unused or requires COW, 1 if its
|
||||||
|
refcount is exactly one. This information is only accurate
|
||||||
|
in L2 tables that are reachable from the the active L1
|
||||||
|
table.
|
||||||
|
|
||||||
|
Standard Cluster Descriptor:
|
||||||
|
|
||||||
|
Bit 0: If set to 1, the cluster reads as all zeros. The host
|
||||||
|
cluster offset can be used to describe a preallocation,
|
||||||
|
but it won't be used for reading data from this cluster,
|
||||||
|
nor is data read from the backing file if the cluster is
|
||||||
|
unallocated.
|
||||||
|
|
||||||
|
With version 2, this is always 0.
|
||||||
|
|
||||||
|
1 - 8: Reserved (set to 0)
|
||||||
|
|
||||||
9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a
|
9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a
|
||||||
cluster boundary. If the offset is 0, the cluster is
|
cluster boundary. If the offset is 0, the cluster is
|
||||||
|
@ -178,30 +261,18 @@ L2 table entry (for normal clusters):
|
||||||
|
|
||||||
56 - 61: Reserved (set to 0)
|
56 - 61: Reserved (set to 0)
|
||||||
|
|
||||||
62: 0 (this cluster is not compressed)
|
|
||||||
|
|
||||||
63: 0 for a cluster that is unused or requires COW, 1 if its
|
Compressed Clusters Descriptor (x = 62 - (cluster_size - 8)):
|
||||||
refcount is exactly one. This information is only accurate
|
|
||||||
in L2 tables that are reachable from the the active L1
|
|
||||||
table.
|
|
||||||
|
|
||||||
L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
|
|
||||||
|
|
||||||
Bit 0 - x: Host cluster offset. This is usually _not_ aligned to a
|
Bit 0 - x: Host cluster offset. This is usually _not_ aligned to a
|
||||||
cluster boundary!
|
cluster boundary!
|
||||||
|
|
||||||
x+1 - 61: Compressed size of the images in sectors of 512 bytes
|
x+1 - 61: Compressed size of the images in sectors of 512 bytes
|
||||||
|
|
||||||
62: 1 (this cluster is compressed using zlib)
|
|
||||||
|
|
||||||
63: 0 for a cluster that is unused or requires COW, 1 if its
|
|
||||||
refcount is exactly one. This information is only accurate
|
|
||||||
in L2 tables that are reachable from the the active L1
|
|
||||||
table.
|
|
||||||
|
|
||||||
If a cluster is unallocated, read requests shall read the data from the backing
|
If a cluster is unallocated, read requests shall read the data from the backing
|
||||||
file. If there is no backing file or the backing file is smaller than the image,
|
file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
|
||||||
they shall read zeros for all parts that are not covered by the backing file.
|
no backing file or the backing file is smaller than the image, they shall read
|
||||||
|
zeros for all parts that are not covered by the backing file.
|
||||||
|
|
||||||
|
|
||||||
== Snapshots ==
|
== Snapshots ==
|
||||||
|
@ -261,6 +332,11 @@ Snapshot table entry:
|
||||||
state is saved. If this field is present,
|
state is saved. If this field is present,
|
||||||
the 32-bit value in bytes 32-35 is ignored.
|
the 32-bit value in bytes 32-35 is ignored.
|
||||||
|
|
||||||
|
Byte 48 - 55: Virtual disk size of the snapshot in bytes
|
||||||
|
|
||||||
|
Version 3 images must include extra data at least up to
|
||||||
|
byte 55.
|
||||||
|
|
||||||
variable: Unique ID string for the snapshot (not null terminated)
|
variable: Unique ID string for the snapshot (not null terminated)
|
||||||
|
|
||||||
variable: Name of the snapshot (not null terminated)
|
variable: Name of the snapshot (not null terminated)
|
||||||
|
|
143
hw/ide/core.c
143
hw/ide/core.c
|
@ -471,40 +471,68 @@ static void ide_rw_error(IDEState *s) {
|
||||||
ide_set_irq(s->bus);
|
ide_set_irq(s->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ide_sector_read_cb(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
IDEState *s = opaque;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
s->pio_aiocb = NULL;
|
||||||
|
s->status &= ~BUSY_STAT;
|
||||||
|
|
||||||
|
bdrv_acct_done(s->bs, &s->acct);
|
||||||
|
if (ret != 0) {
|
||||||
|
if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
|
||||||
|
BM_STATUS_RETRY_READ)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = s->nsector;
|
||||||
|
if (n > s->req_nb_sectors) {
|
||||||
|
n = s->req_nb_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow the guest to read the io_buffer */
|
||||||
|
ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
|
||||||
|
|
||||||
|
ide_set_irq(s->bus);
|
||||||
|
|
||||||
|
ide_set_sector(s, ide_get_sector(s) + n);
|
||||||
|
s->nsector -= n;
|
||||||
|
}
|
||||||
|
|
||||||
void ide_sector_read(IDEState *s)
|
void ide_sector_read(IDEState *s)
|
||||||
{
|
{
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
int ret, n;
|
int n;
|
||||||
|
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
s->error = 0; /* not needed by IDE spec, but needed by Windows */
|
s->error = 0; /* not needed by IDE spec, but needed by Windows */
|
||||||
sector_num = ide_get_sector(s);
|
sector_num = ide_get_sector(s);
|
||||||
n = s->nsector;
|
n = s->nsector;
|
||||||
if (n == 0) {
|
|
||||||
/* no more sector to read from disk */
|
|
||||||
ide_transfer_stop(s);
|
|
||||||
} else {
|
|
||||||
#if defined(DEBUG_IDE)
|
|
||||||
printf("read sector=%" PRId64 "\n", sector_num);
|
|
||||||
#endif
|
|
||||||
if (n > s->req_nb_sectors)
|
|
||||||
n = s->req_nb_sectors;
|
|
||||||
|
|
||||||
bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
if (n == 0) {
|
||||||
ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
|
ide_transfer_stop(s);
|
||||||
bdrv_acct_done(s->bs, &s->acct);
|
return;
|
||||||
if (ret != 0) {
|
|
||||||
if (ide_handle_rw_error(s, -ret,
|
|
||||||
BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
|
|
||||||
ide_set_irq(s->bus);
|
|
||||||
ide_set_sector(s, sector_num + n);
|
|
||||||
s->nsector -= n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->status |= BUSY_STAT;
|
||||||
|
|
||||||
|
if (n > s->req_nb_sectors) {
|
||||||
|
n = s->req_nb_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DEBUG_IDE)
|
||||||
|
printf("sector=%" PRId64 "\n", sector_num);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s->iov.iov_base = s->io_buffer;
|
||||||
|
s->iov.iov_len = n * BDRV_SECTOR_SIZE;
|
||||||
|
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
|
||||||
|
|
||||||
|
bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
||||||
|
s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
|
||||||
|
ide_sector_read_cb, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_buf_commit(IDEState *s)
|
static void dma_buf_commit(IDEState *s)
|
||||||
|
@ -660,40 +688,39 @@ static void ide_sector_write_timer_cb(void *opaque)
|
||||||
ide_set_irq(s->bus);
|
ide_set_irq(s->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ide_sector_write(IDEState *s)
|
static void ide_sector_write_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
int64_t sector_num;
|
IDEState *s = opaque;
|
||||||
int ret, n, n1;
|
int n;
|
||||||
|
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
|
||||||
sector_num = ide_get_sector(s);
|
|
||||||
#if defined(DEBUG_IDE)
|
|
||||||
printf("write sector=%" PRId64 "\n", sector_num);
|
|
||||||
#endif
|
|
||||||
n = s->nsector;
|
|
||||||
if (n > s->req_nb_sectors)
|
|
||||||
n = s->req_nb_sectors;
|
|
||||||
|
|
||||||
bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
|
||||||
ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
|
|
||||||
bdrv_acct_done(s->bs, &s->acct);
|
bdrv_acct_done(s->bs, &s->acct);
|
||||||
|
|
||||||
|
s->pio_aiocb = NULL;
|
||||||
|
s->status &= ~BUSY_STAT;
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
|
if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n = s->nsector;
|
||||||
|
if (n > s->req_nb_sectors) {
|
||||||
|
n = s->req_nb_sectors;
|
||||||
|
}
|
||||||
s->nsector -= n;
|
s->nsector -= n;
|
||||||
if (s->nsector == 0) {
|
if (s->nsector == 0) {
|
||||||
/* no more sectors to write */
|
/* no more sectors to write */
|
||||||
ide_transfer_stop(s);
|
ide_transfer_stop(s);
|
||||||
} else {
|
} else {
|
||||||
n1 = s->nsector;
|
int n1 = s->nsector;
|
||||||
if (n1 > s->req_nb_sectors)
|
if (n1 > s->req_nb_sectors) {
|
||||||
n1 = s->req_nb_sectors;
|
n1 = s->req_nb_sectors;
|
||||||
ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
|
}
|
||||||
|
ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
|
||||||
|
ide_sector_write);
|
||||||
}
|
}
|
||||||
ide_set_sector(s, sector_num + n);
|
ide_set_sector(s, ide_get_sector(s) + n);
|
||||||
|
|
||||||
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
|
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
|
||||||
/* It seems there is a bug in the Windows 2000 installer HDD
|
/* It seems there is a bug in the Windows 2000 installer HDD
|
||||||
|
@ -709,6 +736,30 @@ void ide_sector_write(IDEState *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ide_sector_write(IDEState *s)
|
||||||
|
{
|
||||||
|
int64_t sector_num;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
|
||||||
|
sector_num = ide_get_sector(s);
|
||||||
|
#if defined(DEBUG_IDE)
|
||||||
|
printf("sector=%" PRId64 "\n", sector_num);
|
||||||
|
#endif
|
||||||
|
n = s->nsector;
|
||||||
|
if (n > s->req_nb_sectors) {
|
||||||
|
n = s->req_nb_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->iov.iov_base = s->io_buffer;
|
||||||
|
s->iov.iov_len = n * BDRV_SECTOR_SIZE;
|
||||||
|
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
|
||||||
|
|
||||||
|
bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
|
||||||
|
s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
|
||||||
|
ide_sector_write_cb, s);
|
||||||
|
}
|
||||||
|
|
||||||
static void ide_flush_cb(void *opaque, int ret)
|
static void ide_flush_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
IDEState *s = opaque;
|
IDEState *s = opaque;
|
||||||
|
@ -1765,6 +1816,12 @@ static void ide_reset(IDEState *s)
|
||||||
#ifdef DEBUG_IDE
|
#ifdef DEBUG_IDE
|
||||||
printf("ide: reset\n");
|
printf("ide: reset\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (s->pio_aiocb) {
|
||||||
|
bdrv_aio_cancel(s->pio_aiocb);
|
||||||
|
s->pio_aiocb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->drive_kind == IDE_CFATA)
|
if (s->drive_kind == IDE_CFATA)
|
||||||
s->mult_sectors = 0;
|
s->mult_sectors = 0;
|
||||||
else
|
else
|
||||||
|
|
|
@ -385,6 +385,9 @@ struct IDEState {
|
||||||
int cd_sector_size;
|
int cd_sector_size;
|
||||||
int atapi_dma; /* true if dma is requested for the packet cmd */
|
int atapi_dma; /* true if dma is requested for the packet cmd */
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
|
BlockDriverAIOCB *pio_aiocb;
|
||||||
|
struct iovec iov;
|
||||||
|
QEMUIOVector qiov;
|
||||||
/* ATA DMA state */
|
/* ATA DMA state */
|
||||||
int io_buffer_size;
|
int io_buffer_size;
|
||||||
QEMUSGList sg;
|
QEMUSGList sg;
|
||||||
|
|
|
@ -214,7 +214,7 @@ void *laio_init(void)
|
||||||
goto out_close_efd;
|
goto out_close_efd;
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
|
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
|
||||||
qemu_laio_flush_cb, NULL, s);
|
qemu_laio_flush_cb, s);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
|
|
|
@ -468,26 +468,37 @@ static int qemu_paio_error(struct qemu_paiocb *aiocb)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int posix_aio_process_queue(void *opaque)
|
static void posix_aio_read(void *opaque)
|
||||||
{
|
{
|
||||||
PosixAioState *s = opaque;
|
PosixAioState *s = opaque;
|
||||||
struct qemu_paiocb *acb, **pacb;
|
struct qemu_paiocb *acb, **pacb;
|
||||||
int ret;
|
int ret;
|
||||||
int result = 0;
|
ssize_t len;
|
||||||
|
|
||||||
|
/* read all bytes from signal pipe */
|
||||||
|
for (;;) {
|
||||||
|
char bytes[16];
|
||||||
|
|
||||||
|
len = read(s->rfd, bytes, sizeof(bytes));
|
||||||
|
if (len == -1 && errno == EINTR)
|
||||||
|
continue; /* try again */
|
||||||
|
if (len == sizeof(bytes))
|
||||||
|
continue; /* more to read */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
pacb = &s->first_aio;
|
pacb = &s->first_aio;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
acb = *pacb;
|
acb = *pacb;
|
||||||
if (!acb)
|
if (!acb)
|
||||||
return result;
|
return;
|
||||||
|
|
||||||
ret = qemu_paio_error(acb);
|
ret = qemu_paio_error(acb);
|
||||||
if (ret == ECANCELED) {
|
if (ret == ECANCELED) {
|
||||||
/* remove the request */
|
/* remove the request */
|
||||||
*pacb = acb->next;
|
*pacb = acb->next;
|
||||||
qemu_aio_release(acb);
|
qemu_aio_release(acb);
|
||||||
result = 1;
|
|
||||||
} else if (ret != EINPROGRESS) {
|
} else if (ret != EINPROGRESS) {
|
||||||
/* end of aio */
|
/* end of aio */
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -507,35 +518,12 @@ static int posix_aio_process_queue(void *opaque)
|
||||||
/* call the callback */
|
/* call the callback */
|
||||||
acb->common.cb(acb->common.opaque, ret);
|
acb->common.cb(acb->common.opaque, ret);
|
||||||
qemu_aio_release(acb);
|
qemu_aio_release(acb);
|
||||||
result = 1;
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
pacb = &acb->next;
|
pacb = &acb->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void posix_aio_read(void *opaque)
|
|
||||||
{
|
|
||||||
PosixAioState *s = opaque;
|
|
||||||
ssize_t len;
|
|
||||||
|
|
||||||
/* read all bytes from signal pipe */
|
|
||||||
for (;;) {
|
|
||||||
char bytes[16];
|
|
||||||
|
|
||||||
len = read(s->rfd, bytes, sizeof(bytes));
|
|
||||||
if (len == -1 && errno == EINTR)
|
|
||||||
continue; /* try again */
|
|
||||||
if (len == sizeof(bytes))
|
|
||||||
continue; /* more to read */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
posix_aio_process_queue(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int posix_aio_flush(void *opaque)
|
static int posix_aio_flush(void *opaque)
|
||||||
|
@ -675,8 +663,7 @@ int paio_init(void)
|
||||||
fcntl(s->rfd, F_SETFL, O_NONBLOCK);
|
fcntl(s->rfd, F_SETFL, O_NONBLOCK);
|
||||||
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
|
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
|
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
|
||||||
posix_aio_process_queue, s);
|
|
||||||
|
|
||||||
ret = pthread_attr_init(&attr);
|
ret = pthread_attr_init(&attr);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
19
qemu-aio.h
19
qemu-aio.h
|
@ -41,11 +41,6 @@ void qemu_aio_release(void *p);
|
||||||
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
|
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
|
||||||
typedef int (AioFlushHandler)(void *opaque);
|
typedef int (AioFlushHandler)(void *opaque);
|
||||||
|
|
||||||
/* Runs all currently allowed AIO callbacks of completed requests in the
|
|
||||||
* respective AIO backend. Returns 0 if no requests was handled, non-zero
|
|
||||||
* if at least one queued request was handled. */
|
|
||||||
typedef int (AioProcessQueue)(void *opaque);
|
|
||||||
|
|
||||||
/* Flush any pending AIO operation. This function will block until all
|
/* Flush any pending AIO operation. This function will block until all
|
||||||
* outstanding AIO operations have been completed or cancelled. */
|
* outstanding AIO operations have been completed or cancelled. */
|
||||||
void qemu_aio_flush(void);
|
void qemu_aio_flush(void);
|
||||||
|
@ -53,15 +48,10 @@ void qemu_aio_flush(void);
|
||||||
/* Wait for a single AIO completion to occur. This function will wait
|
/* Wait for a single AIO completion to occur. This function will wait
|
||||||
* until a single AIO event has completed and it will ensure something
|
* until a single AIO event has completed and it will ensure something
|
||||||
* has moved before returning. This can issue new pending aio as
|
* has moved before returning. This can issue new pending aio as
|
||||||
* result of executing I/O completion or bh callbacks. */
|
* result of executing I/O completion or bh callbacks.
|
||||||
void qemu_aio_wait(void);
|
*
|
||||||
|
* Return whether there is still any pending AIO operation. */
|
||||||
/*
|
bool qemu_aio_wait(void);
|
||||||
* Runs all currently allowed AIO callbacks of completed requests. Returns 0
|
|
||||||
* if no requests were handled, non-zero if at least one request was
|
|
||||||
* processed.
|
|
||||||
*/
|
|
||||||
int qemu_aio_process_queue(void);
|
|
||||||
|
|
||||||
/* Register a file descriptor and associated callbacks. Behaves very similarly
|
/* Register a file descriptor and associated callbacks. Behaves very similarly
|
||||||
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
|
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
|
||||||
|
@ -74,7 +64,6 @@ int qemu_aio_set_fd_handler(int fd,
|
||||||
IOHandler *io_read,
|
IOHandler *io_read,
|
||||||
IOHandler *io_write,
|
IOHandler *io_write,
|
||||||
AioFlushHandler *io_flush,
|
AioFlushHandler *io_flush,
|
||||||
AioProcessQueue *io_process_queue,
|
|
||||||
void *opaque);
|
void *opaque);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,6 @@ static void co_sleep_cb(void *opaque)
|
||||||
{
|
{
|
||||||
CoSleepCB *sleep_cb = opaque;
|
CoSleepCB *sleep_cb = opaque;
|
||||||
|
|
||||||
qemu_free_timer(sleep_cb->ts);
|
|
||||||
qemu_coroutine_enter(sleep_cb->co, NULL);
|
qemu_coroutine_enter(sleep_cb->co, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,4 +34,6 @@ void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
|
||||||
sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
|
sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
|
||||||
qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
|
qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
|
||||||
qemu_coroutine_yield();
|
qemu_coroutine_yield();
|
||||||
|
qemu_del_timer(sleep_cb.ts);
|
||||||
|
qemu_free_timer(sleep_cb.ts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,8 @@ static void help(void)
|
||||||
" 'filename' is a disk image filename\n"
|
" 'filename' is a disk image filename\n"
|
||||||
" 'fmt' is the disk image format. It is guessed automatically in most cases\n"
|
" 'fmt' is the disk image format. It is guessed automatically in most cases\n"
|
||||||
" 'cache' is the cache mode used to write the output disk image, the valid\n"
|
" 'cache' is the cache mode used to write the output disk image, the valid\n"
|
||||||
" options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
|
" options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
|
||||||
" and 'unsafe'\n"
|
" 'directsync' and 'unsafe' (default for convert)\n"
|
||||||
" 'size' is the disk image size in bytes. Optional suffixes\n"
|
" 'size' is the disk image size in bytes. Optional suffixes\n"
|
||||||
" 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
|
" 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
|
||||||
" and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
|
" and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
|
||||||
|
|
17
qemu-io.c
17
qemu-io.c
|
@ -15,6 +15,7 @@
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
|
#include "main-loop.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "trace/control.h"
|
#include "trace/control.h"
|
||||||
|
@ -295,7 +296,7 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
|
||||||
bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
|
bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
|
||||||
aio_rw_done, &async_ret);
|
aio_rw_done, &async_ret);
|
||||||
while (async_ret == NOT_DONE) {
|
while (async_ret == NOT_DONE) {
|
||||||
qemu_aio_wait();
|
main_loop_wait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
*total = qiov->size;
|
*total = qiov->size;
|
||||||
|
@ -309,7 +310,7 @@ static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
|
||||||
bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
|
bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
|
||||||
aio_rw_done, &async_ret);
|
aio_rw_done, &async_ret);
|
||||||
while (async_ret == NOT_DONE) {
|
while (async_ret == NOT_DONE) {
|
||||||
qemu_aio_wait();
|
main_loop_wait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
*total = qiov->size;
|
*total = qiov->size;
|
||||||
|
@ -352,7 +353,7 @@ static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (async_ret.num_done < num_reqs) {
|
while (async_ret.num_done < num_reqs) {
|
||||||
qemu_aio_wait();
|
main_loop_wait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return async_ret.error < 0 ? async_ret.error : 1;
|
return async_ret.error < 0 ? async_ret.error : 1;
|
||||||
|
@ -1784,6 +1785,7 @@ static void usage(const char *name)
|
||||||
" -g, --growable allow file to grow (only applies to protocols)\n"
|
" -g, --growable allow file to grow (only applies to protocols)\n"
|
||||||
" -m, --misalign misalign allocations for O_DIRECT\n"
|
" -m, --misalign misalign allocations for O_DIRECT\n"
|
||||||
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
|
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
|
||||||
|
" -t, --cache=MODE use the given cache mode for the image\n"
|
||||||
" -T, --trace FILE enable trace events listed in the given file\n"
|
" -T, --trace FILE enable trace events listed in the given file\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
" -V, --version output version information and exit\n"
|
" -V, --version output version information and exit\n"
|
||||||
|
@ -1796,7 +1798,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int readonly = 0;
|
int readonly = 0;
|
||||||
int growable = 0;
|
int growable = 0;
|
||||||
const char *sopt = "hVc:rsnmgkT:";
|
const char *sopt = "hVc:rsnmgkt:T:";
|
||||||
const struct option lopt[] = {
|
const struct option lopt[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "version", 0, NULL, 'V' },
|
{ "version", 0, NULL, 'V' },
|
||||||
|
@ -1808,6 +1810,7 @@ int main(int argc, char **argv)
|
||||||
{ "misalign", 0, NULL, 'm' },
|
{ "misalign", 0, NULL, 'm' },
|
||||||
{ "growable", 0, NULL, 'g' },
|
{ "growable", 0, NULL, 'g' },
|
||||||
{ "native-aio", 0, NULL, 'k' },
|
{ "native-aio", 0, NULL, 'k' },
|
||||||
|
{ "cache", 1, NULL, 't' },
|
||||||
{ "trace", 1, NULL, 'T' },
|
{ "trace", 1, NULL, 'T' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
@ -1840,6 +1843,12 @@ int main(int argc, char **argv)
|
||||||
case 'k':
|
case 'k':
|
||||||
flags |= BDRV_O_NATIVE_AIO;
|
flags |= BDRV_O_NATIVE_AIO;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
|
||||||
|
error_report("Invalid cache option: %s", optarg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
if (!trace_backend_init(optarg, NULL)) {
|
if (!trace_backend_init(optarg, NULL)) {
|
||||||
exit(1); /* error message will have been printed */
|
exit(1); /* error message will have been printed */
|
||||||
|
|
|
@ -61,7 +61,7 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||||
|
|
||||||
int64_t cpu_get_clock(void)
|
int64_t cpu_get_clock(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return qemu_get_clock_ns(rt_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t cpu_get_icount(void)
|
int64_t cpu_get_icount(void)
|
||||||
|
@ -87,7 +87,6 @@ int qemu_init_main_loop(void)
|
||||||
{
|
{
|
||||||
init_clocks();
|
init_clocks();
|
||||||
init_timer_alarm();
|
init_timer_alarm();
|
||||||
qemu_clock_enable(vm_clock, false);
|
|
||||||
return main_loop_init();
|
return main_loop_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ $QEMU_IO -c "read 1024 4096" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "small write"
|
echo "small write"
|
||||||
$QEMU_IO -c "read 8192 4096" $TEST_IMG | _filter_qemu_io
|
$QEMU_IO -c "write 8192 4096" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
|
|
|
@ -8,6 +8,6 @@ read 4096/4096 bytes at offset 1024
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
small write
|
small write
|
||||||
read 4096/4096 bytes at offset 8192
|
wrote 4096/4096 bytes at offset 8192
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
*** done
|
*** done
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
QA output created by 013
|
QA output created by 013
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 0:
|
At offset 0:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
QA output created by 014
|
QA output created by 014
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
|
||||||
Testing empty image:
|
Testing empty image:
|
||||||
test2: With offset 0
|
test2: With offset 0
|
||||||
=== Clusters to be compressed [1]
|
=== Clusters to be compressed [1]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
QA output created by 015
|
QA output created by 015
|
||||||
|
|
||||||
creating image
|
creating image
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736
|
||||||
creating first snapshot
|
creating first snapshot
|
||||||
wrote 37748736/37748736 bytes at offset 0
|
wrote 37748736/37748736 bytes at offset 0
|
||||||
36 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
36 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
QA output created by 019
|
QA output created by 019
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
|
||||||
Filling base image
|
Filling base image
|
||||||
|
|
||||||
=== IO: pattern 42
|
=== IO: pattern 42
|
||||||
|
@ -269,7 +269,7 @@ qemu-io> wrote 65536/65536 bytes at offset 4296015872
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating test image with backing file
|
Creating test image with backing file
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
|
||||||
Filling test image
|
Filling test image
|
||||||
|
|
||||||
=== IO: pattern 43
|
=== IO: pattern 43
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
QA output created by 022
|
QA output created by 022
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 10485760:
|
At offset 10485760:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
QA output created by 023
|
QA output created by 023
|
||||||
Creating new image; cluster size: 1024
|
Creating new image; cluster size: 1024
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 0:
|
At offset 0:
|
||||||
|
@ -5664,7 +5664,7 @@ qemu-io> read 3072/3072 bytes at offset 4295491072
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating another new image
|
Creating another new image
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
More complex patterns
|
More complex patterns
|
||||||
|
|
||||||
test2: With offset 0
|
test2: With offset 0
|
||||||
|
@ -5887,7 +5887,7 @@ qemu-io> read 2048/2048 bytes at offset 4295001088
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating new image; cluster size: 4096
|
Creating new image; cluster size: 4096
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 0:
|
At offset 0:
|
||||||
|
@ -12270,7 +12270,7 @@ qemu-io> read 12288/12288 bytes at offset 4301256704
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating another new image
|
Creating another new image
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
More complex patterns
|
More complex patterns
|
||||||
|
|
||||||
test2: With offset 0
|
test2: With offset 0
|
||||||
|
@ -12493,7 +12493,7 @@ qemu-io> read 8192/8192 bytes at offset 4295102464
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating new image; cluster size: 16384
|
Creating new image; cluster size: 16384
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 0:
|
At offset 0:
|
||||||
|
@ -18876,7 +18876,7 @@ qemu-io> read 49152/49152 bytes at offset 4395622400
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating another new image
|
Creating another new image
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
More complex patterns
|
More complex patterns
|
||||||
|
|
||||||
test2: With offset 0
|
test2: With offset 0
|
||||||
|
@ -19099,7 +19099,7 @@ qemu-io> read 32768/32768 bytes at offset 4295507968
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating new image; cluster size: 65536
|
Creating new image; cluster size: 65536
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
Testing empty image
|
Testing empty image
|
||||||
|
|
||||||
At offset 0:
|
At offset 0:
|
||||||
|
@ -25482,7 +25482,7 @@ qemu-io> read 196608/196608 bytes at offset 5905547264
|
||||||
qemu-io> No errors were found on the image.
|
qemu-io> No errors were found on the image.
|
||||||
Creating another new image
|
Creating another new image
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
|
||||||
More complex patterns
|
More complex patterns
|
||||||
|
|
||||||
test2: With offset 0
|
test2: With offset 0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
QA output created by 024
|
QA output created by 024
|
||||||
Creating backing file
|
Creating backing file
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
=== IO: pattern 0x11
|
=== IO: pattern 0x11
|
||||||
qemu-io> wrote 65536/65536 bytes at offset 0
|
qemu-io> wrote 65536/65536 bytes at offset 0
|
||||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
@ -21,7 +21,7 @@ qemu-io> wrote 65536/65536 bytes at offset 917504
|
||||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
qemu-io> Creating new backing file
|
qemu-io> Creating new backing file
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
=== IO: pattern 0x22
|
=== IO: pattern 0x22
|
||||||
qemu-io> wrote 131072/131072 bytes at offset 0
|
qemu-io> wrote 131072/131072 bytes at offset 0
|
||||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
@ -33,7 +33,7 @@ qemu-io> wrote 131072/131072 bytes at offset 786432
|
||||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
qemu-io> Creating COW image
|
qemu-io> Creating COW image
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old' cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old'
|
||||||
=== IO: pattern 0x33
|
=== IO: pattern 0x33
|
||||||
qemu-io> wrote 262144/262144 bytes at offset 0
|
qemu-io> wrote 262144/262144 bytes at offset 0
|
||||||
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
|
@ -1,63 +1,63 @@
|
||||||
QA output created by 026
|
QA output created by 026
|
||||||
Errors while writing 128 kB
|
Errors while writing 128 kB
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 5; imm: off; once: on; write
|
Event: l1_update; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 5; imm: off; once: on; write -b
|
Event: l1_update; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 5; imm: off; once: off; write
|
Event: l1_update; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 5; imm: off; once: off; write -b
|
Event: l1_update; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 28; imm: off; once: on; write
|
Event: l1_update; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 28; imm: off; once: on; write -b
|
Event: l1_update; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 28; imm: off; once: off; write
|
Event: l1_update; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_update; errno: 28; imm: off; once: off; write -b
|
Event: l1_update; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 5; imm: off; once: on; write
|
Event: l2_load; errno: 5; imm: off; once: on; write
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -65,7 +65,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
read failed: Input/output error
|
read failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 5; imm: off; once: on; write -b
|
Event: l2_load; errno: 5; imm: off; once: on; write -b
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -73,7 +73,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
read failed: Input/output error
|
read failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 5; imm: off; once: off; write
|
Event: l2_load; errno: 5; imm: off; once: off; write
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -81,7 +81,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
read failed: Input/output error
|
read failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 5; imm: off; once: off; write -b
|
Event: l2_load; errno: 5; imm: off; once: off; write -b
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -89,7 +89,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
read failed: Input/output error
|
read failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 28; imm: off; once: on; write
|
Event: l2_load; errno: 28; imm: off; once: on; write
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -97,7 +97,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
read failed: No space left on device
|
read failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 28; imm: off; once: on; write -b
|
Event: l2_load; errno: 28; imm: off; once: on; write -b
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -105,7 +105,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
read failed: No space left on device
|
read failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 28; imm: off; once: off; write
|
Event: l2_load; errno: 28; imm: off; once: off; write
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -113,7 +113,7 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
read failed: No space left on device
|
read failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_load; errno: 28; imm: off; once: off; write -b
|
Event: l2_load; errno: 28; imm: off; once: off; write -b
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
|
@ -121,306 +121,306 @@ wrote 131072/131072 bytes at offset 0
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
read failed: No space left on device
|
read failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 5; imm: off; once: on; write
|
Event: l2_update; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 5; imm: off; once: on; write -b
|
Event: l2_update; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 5; imm: off; once: off; write
|
Event: l2_update; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 5; imm: off; once: off; write -b
|
Event: l2_update; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 28; imm: off; once: on; write
|
Event: l2_update; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 28; imm: off; once: on; write -b
|
Event: l2_update; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 28; imm: off; once: off; write
|
Event: l2_update; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_update; errno: 28; imm: off; once: off; write -b
|
Event: l2_update; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
128 leaked clusters were found on the image.
|
128 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 5; imm: off; once: on; write
|
Event: l2_alloc.write; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
|
Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 5; imm: off; once: off; write
|
Event: l2_alloc.write; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
|
Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 28; imm: off; once: on; write
|
Event: l2_alloc.write; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
|
Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 28; imm: off; once: off; write
|
Event: l2_alloc.write; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
|
Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
1 leaked clusters were found on the image.
|
1 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 5; imm: off; once: on; write
|
Event: write_aio; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 5; imm: off; once: on; write -b
|
Event: write_aio; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 5; imm: off; once: off; write
|
Event: write_aio; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 5; imm: off; once: off; write -b
|
Event: write_aio; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 28; imm: off; once: on; write
|
Event: write_aio; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 28; imm: off; once: on; write -b
|
Event: write_aio; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 28; imm: off; once: off; write
|
Event: write_aio; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: write_aio; errno: 28; imm: off; once: off; write -b
|
Event: write_aio; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 5; imm: off; once: on; write
|
Event: refblock_load; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 5; imm: off; once: on; write -b
|
Event: refblock_load; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 5; imm: off; once: off; write
|
Event: refblock_load; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 5; imm: off; once: off; write -b
|
Event: refblock_load; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 28; imm: off; once: on; write
|
Event: refblock_load; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 28; imm: off; once: on; write -b
|
Event: refblock_load; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 28; imm: off; once: off; write
|
Event: refblock_load; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_load; errno: 28; imm: off; once: off; write -b
|
Event: refblock_load; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 5; imm: off; once: on; write
|
Event: refblock_update_part; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
|
Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write
|
Event: refblock_update_part; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
|
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 28; imm: off; once: on; write
|
Event: refblock_update_part; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
|
Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write
|
Event: refblock_update_part; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
|
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 5; imm: off; once: on; write
|
Event: refblock_alloc; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 5; imm: off; once: on; write -b
|
Event: refblock_alloc; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write
|
Event: refblock_alloc; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
|
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 5; imm: off; once: on; write
|
Event: cluster_alloc; errno: 5; imm: off; once: on; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 5; imm: off; once: on; write -b
|
Event: cluster_alloc; errno: 5; imm: off; once: on; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 5; imm: off; once: off; write
|
Event: cluster_alloc; errno: 5; imm: off; once: off; write
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
|
Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 28; imm: off; once: on; write
|
Event: cluster_alloc; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 28; imm: off; once: on; write -b
|
Event: cluster_alloc; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 28; imm: off; once: off; write
|
Event: cluster_alloc; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
|
Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
@ -428,116 +428,116 @@ No errors were found on the image.
|
||||||
|
|
||||||
=== Refcout table growth tests ===
|
=== Refcout table growth tests ===
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
55 leaked clusters were found on the image.
|
55 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
251 leaked clusters were found on the image.
|
251 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
10 leaked clusters were found on the image.
|
10 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
23 leaked clusters were found on the image.
|
23 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
10 leaked clusters were found on the image.
|
10 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
23 leaked clusters were found on the image.
|
23 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
|
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
|
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
|
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
|
||||||
10 leaked clusters were found on the image.
|
10 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
|
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
|
@ -547,54 +547,54 @@ This means waste of disk space, but no harm to data.
|
||||||
|
|
||||||
=== L1 growth tests ===
|
=== L1 growth tests ===
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
|
Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
|
Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
|
Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
|
Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.write_table; errno: 5; imm: off; once: on
|
Event: l1_grow.write_table; errno: 5; imm: off; once: on
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.write_table; errno: 5; imm: off; once: off
|
Event: l1_grow.write_table; errno: 5; imm: off; once: off
|
||||||
qcow2_free_clusters failed: Input/output error
|
qcow2_free_clusters failed: Input/output error
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.write_table; errno: 28; imm: off; once: on
|
Event: l1_grow.write_table; errno: 28; imm: off; once: on
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.write_table; errno: 28; imm: off; once: off
|
Event: l1_grow.write_table; errno: 28; imm: off; once: off
|
||||||
qcow2_free_clusters failed: No space left on device
|
qcow2_free_clusters failed: No space left on device
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.activate_table; errno: 5; imm: off; once: on
|
Event: l1_grow.activate_table; errno: 5; imm: off; once: on
|
||||||
write failed: Input/output error
|
write failed: Input/output error
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.activate_table; errno: 5; imm: off; once: off
|
Event: l1_grow.activate_table; errno: 5; imm: off; once: off
|
||||||
qcow2_free_clusters failed: Input/output error
|
qcow2_free_clusters failed: Input/output error
|
||||||
|
@ -602,12 +602,12 @@ write failed: Input/output error
|
||||||
|
|
||||||
96 leaked clusters were found on the image.
|
96 leaked clusters were found on the image.
|
||||||
This means waste of disk space, but no harm to data.
|
This means waste of disk space, but no harm to data.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.activate_table; errno: 28; imm: off; once: on
|
Event: l1_grow.activate_table; errno: 28; imm: off; once: on
|
||||||
write failed: No space left on device
|
write failed: No space left on device
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
|
||||||
|
|
||||||
Event: l1_grow.activate_table; errno: 28; imm: off; once: off
|
Event: l1_grow.activate_table; errno: 28; imm: off; once: off
|
||||||
qcow2_free_clusters failed: No space left on device
|
qcow2_free_clusters failed: No space left on device
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
QA output created by 029
|
QA output created by 029
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
wrote 4096/4096 bytes at offset 0
|
wrote 4096/4096 bytes at offset 0
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 cluster_size=1024
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
|
||||||
wrote 4194304/4194304 bytes at offset 0
|
wrote 4194304/4194304 bytes at offset 0
|
||||||
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
No errors were found on the image.
|
No errors were found on the image.
|
||||||
|
|
|
@ -45,26 +45,34 @@ _supported_proto generic
|
||||||
_supported_os Linux
|
_supported_os Linux
|
||||||
|
|
||||||
CLUSTER_SIZE=65536
|
CLUSTER_SIZE=65536
|
||||||
echo
|
|
||||||
echo === Create image with unknown header extension ===
|
|
||||||
echo
|
|
||||||
_make_test_img 64M
|
|
||||||
./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
|
|
||||||
./qcow2.py $TEST_IMG dump-header
|
|
||||||
_check_test_img
|
|
||||||
|
|
||||||
echo
|
# qcow2.py output depends on the exact options used, so override the command
|
||||||
echo === Rewrite header with no backing file ===
|
# line here as an exception
|
||||||
echo
|
for IMGOPTS in "compat=0.10" "compat=1.1"; do
|
||||||
$QEMU_IMG rebase -u -b "" $TEST_IMG
|
|
||||||
./qcow2.py $TEST_IMG dump-header
|
|
||||||
_check_test_img
|
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo === Add a backing file and format ===
|
echo ===== Testing with -o $IMGOPTS =====
|
||||||
echo
|
echo
|
||||||
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
|
echo === Create image with unknown header extension ===
|
||||||
./qcow2.py $TEST_IMG dump-header
|
echo
|
||||||
|
_make_test_img 64M
|
||||||
|
./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
|
||||||
|
./qcow2.py $TEST_IMG dump-header
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Rewrite header with no backing file ===
|
||||||
|
echo
|
||||||
|
$QEMU_IMG rebase -u -b "" $TEST_IMG
|
||||||
|
./qcow2.py $TEST_IMG dump-header
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Add a backing file and format ===
|
||||||
|
echo
|
||||||
|
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
|
||||||
|
./qcow2.py $TEST_IMG dump-header
|
||||||
|
done
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
QA output created by 031
|
QA output created by 031
|
||||||
|
|
||||||
|
===== Testing with -o compat=0.10 =====
|
||||||
|
|
||||||
=== Create image with unknown header extension ===
|
=== Create image with unknown header extension ===
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
magic 0x514649fb
|
magic 0x514649fb
|
||||||
version 2
|
version 2
|
||||||
backing_file_offset 0x0
|
backing_file_offset 0x0
|
||||||
|
@ -16,6 +18,11 @@ refcount_table_offset 0x10000
|
||||||
refcount_table_clusters 1
|
refcount_table_clusters 1
|
||||||
nb_snapshots 0
|
nb_snapshots 0
|
||||||
snapshot_offset 0x0
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 72
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
|
@ -39,6 +46,16 @@ refcount_table_offset 0x10000
|
||||||
refcount_table_clusters 1
|
refcount_table_clusters 1
|
||||||
nb_snapshots 0
|
nb_snapshots 0
|
||||||
snapshot_offset 0x0
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 72
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x6803f857
|
||||||
|
length 0
|
||||||
|
data ''
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
|
@ -51,7 +68,7 @@ No errors were found on the image.
|
||||||
|
|
||||||
magic 0x514649fb
|
magic 0x514649fb
|
||||||
version 2
|
version 2
|
||||||
backing_file_offset 0x90
|
backing_file_offset 0x98
|
||||||
backing_file_size 0x17
|
backing_file_size 0x17
|
||||||
cluster_bits 16
|
cluster_bits 16
|
||||||
size 67108864
|
size 67108864
|
||||||
|
@ -62,12 +79,123 @@ refcount_table_offset 0x10000
|
||||||
refcount_table_clusters 1
|
refcount_table_clusters 1
|
||||||
nb_snapshots 0
|
nb_snapshots 0
|
||||||
snapshot_offset 0x0
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 72
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0xe2792aca
|
magic 0xe2792aca
|
||||||
length 11
|
length 11
|
||||||
data 'host_device'
|
data 'host_device'
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x6803f857
|
||||||
|
length 0
|
||||||
|
data ''
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x12345678
|
||||||
|
length 31
|
||||||
|
data 'This is a test header extension'
|
||||||
|
|
||||||
|
|
||||||
|
===== Testing with -o compat=1.1 =====
|
||||||
|
|
||||||
|
=== Create image with unknown header extension ===
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
|
magic 0x514649fb
|
||||||
|
version 3
|
||||||
|
backing_file_offset 0x0
|
||||||
|
backing_file_size 0x0
|
||||||
|
cluster_bits 16
|
||||||
|
size 67108864
|
||||||
|
crypt_method 0
|
||||||
|
l1_size 1
|
||||||
|
l1_table_offset 0x30000
|
||||||
|
refcount_table_offset 0x10000
|
||||||
|
refcount_table_clusters 1
|
||||||
|
nb_snapshots 0
|
||||||
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 104
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x12345678
|
||||||
|
length 31
|
||||||
|
data 'This is a test header extension'
|
||||||
|
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
=== Rewrite header with no backing file ===
|
||||||
|
|
||||||
|
magic 0x514649fb
|
||||||
|
version 3
|
||||||
|
backing_file_offset 0x0
|
||||||
|
backing_file_size 0x0
|
||||||
|
cluster_bits 16
|
||||||
|
size 67108864
|
||||||
|
crypt_method 0
|
||||||
|
l1_size 1
|
||||||
|
l1_table_offset 0x30000
|
||||||
|
refcount_table_offset 0x10000
|
||||||
|
refcount_table_clusters 1
|
||||||
|
nb_snapshots 0
|
||||||
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 104
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x6803f857
|
||||||
|
length 0
|
||||||
|
data ''
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x12345678
|
||||||
|
length 31
|
||||||
|
data 'This is a test header extension'
|
||||||
|
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
=== Add a backing file and format ===
|
||||||
|
|
||||||
|
magic 0x514649fb
|
||||||
|
version 3
|
||||||
|
backing_file_offset 0xb8
|
||||||
|
backing_file_size 0x17
|
||||||
|
cluster_bits 16
|
||||||
|
size 67108864
|
||||||
|
crypt_method 0
|
||||||
|
l1_size 1
|
||||||
|
l1_table_offset 0x30000
|
||||||
|
refcount_table_offset 0x10000
|
||||||
|
refcount_table_clusters 1
|
||||||
|
nb_snapshots 0
|
||||||
|
snapshot_offset 0x0
|
||||||
|
incompatible_features 0x0
|
||||||
|
compatible_features 0x0
|
||||||
|
autoclear_features 0x0
|
||||||
|
refcount_order 4
|
||||||
|
header_length 104
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0xe2792aca
|
||||||
|
length 11
|
||||||
|
data 'host_device'
|
||||||
|
|
||||||
|
Header extension:
|
||||||
|
magic 0x6803f857
|
||||||
|
length 0
|
||||||
|
data ''
|
||||||
|
|
||||||
Header extension:
|
Header extension:
|
||||||
magic 0x12345678
|
magic 0x12345678
|
||||||
length 31
|
length 31
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test that AIO requests are drained before an image is closed. This used
|
||||||
|
# to segfault because the request coroutine kept running even after the
|
||||||
|
# BlockDriverState was freed.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2011 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# creator
|
||||||
|
owner=kwolf@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
. ./common.pattern
|
||||||
|
|
||||||
|
# This works for any image format (though unlikely to segfault for raw)
|
||||||
|
_supported_fmt generic
|
||||||
|
_supported_proto generic
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Prepare image ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
CLUSTER_SIZE=65536
|
||||||
|
_make_test_img 64M
|
||||||
|
|
||||||
|
# Allocate every other cluster so that afterwards a big write request will
|
||||||
|
# actually loop a while and issue many I/O requests for the lower layer
|
||||||
|
for i in $(seq 0 128 4096); do echo "write ${i}k 64k"; done | $QEMU_IO $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === AIO request during close ===
|
||||||
|
echo
|
||||||
|
$QEMU_IO -c "aio_write 0 4M" -c "close" $TEST_IMG | _filter_qemu_io
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,78 @@
|
||||||
|
QA output created by 032
|
||||||
|
|
||||||
|
=== Prepare image ===
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 0
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 131072
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 262144
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 393216
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 524288
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 655360
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 786432
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 917504
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1048576
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1179648
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1310720
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1441792
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1572864
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1703936
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1835008
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 1966080
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2097152
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2228224
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2359296
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2490368
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2621440
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2752512
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 2883584
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3014656
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3145728
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3276800
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3407872
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3538944
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3670016
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3801088
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 3932160
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 4063232
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io> wrote 65536/65536 bytes at offset 4194304
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
qemu-io>
|
||||||
|
=== AIO request during close ===
|
||||||
|
|
||||||
|
wrote 4194304/4194304 bytes at offset 0
|
||||||
|
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
*** done
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test aligned and misaligned write zeroes operations.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012 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=pbonzini@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
_supported_fmt generic
|
||||||
|
_supported_proto generic
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
|
||||||
|
size=128M
|
||||||
|
_make_test_img $size
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== preparing image =="
|
||||||
|
$QEMU_IO -c "write -P 0xa 0x200 0x400" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xa 0x20000 0x600" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -z 0x400 0x20000" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying patterns (1) =="
|
||||||
|
$QEMU_IO -c "read -P 0xa 0x200 0x200" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xa 0x20400 0x200" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== rewriting zeroes =="
|
||||||
|
$QEMU_IO -c "write -P 0xb 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -z 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying patterns (2) =="
|
||||||
|
$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,29 @@
|
||||||
|
QA output created by 033
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
|
|
||||||
|
== preparing image ==
|
||||||
|
wrote 1024/1024 bytes at offset 512
|
||||||
|
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 1536/1536 bytes at offset 131072
|
||||||
|
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 131072/131072 bytes at offset 1024
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying patterns (1) ==
|
||||||
|
read 512/512 bytes at offset 512
|
||||||
|
512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 131072/131072 bytes at offset 1024
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 512/512 bytes at offset 132096
|
||||||
|
512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== rewriting zeroes ==
|
||||||
|
wrote 65536/65536 bytes at offset 65536
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 65536/65536 bytes at offset 65536
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== verifying patterns (2) ==
|
||||||
|
read 131072/131072 bytes at offset 1024
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
*** done
|
|
@ -0,0 +1,113 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test bdrv_write_zeroes with backing files
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
# creator
|
||||||
|
owner=kwolf@redhat.com
|
||||||
|
|
||||||
|
seq=`basename $0`
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
_supported_fmt qcow qcow2 vmdk qed
|
||||||
|
_supported_proto generic
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
CLUSTER_SIZE=4k
|
||||||
|
size=128M
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== creating backing file for COW tests =="
|
||||||
|
|
||||||
|
_make_test_img $size
|
||||||
|
$QEMU_IO -c "write -P 0x55 0 1M" $TEST_IMG | _filter_qemu_io
|
||||||
|
mv $TEST_IMG $TEST_IMG.base
|
||||||
|
|
||||||
|
_make_test_img -b $TEST_IMG.base 6G
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== zero write with backing file =="
|
||||||
|
$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -z 513k 13k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying patterns (3) =="
|
||||||
|
$QEMU_IO -c "read -P 0x55 0 64k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x55 256k 257k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== overwriting zero cluster =="
|
||||||
|
$QEMU_IO -c "write -P 0xa 60k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xd 252k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "write -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying patterns (4) =="
|
||||||
|
$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 72k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 80k 168k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x55 260k 64k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== re-zeroing overwritten area =="
|
||||||
|
$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
_check_test_img
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== verifying patterns (5) =="
|
||||||
|
$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x55 260k 253k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
|
||||||
|
$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
|
@ -0,0 +1,81 @@
|
||||||
|
QA output created by 034
|
||||||
|
|
||||||
|
== creating backing file for COW tests ==
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
|
wrote 1048576/1048576 bytes at offset 0
|
||||||
|
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
|
||||||
|
|
||||||
|
== zero write with backing file ==
|
||||||
|
wrote 196608/196608 bytes at offset 65536
|
||||||
|
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 13312/13312 bytes at offset 525312
|
||||||
|
13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
== verifying patterns (3) ==
|
||||||
|
read 65536/65536 bytes at offset 0
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 196608/196608 bytes at offset 65536
|
||||||
|
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 263168/263168 bytes at offset 262144
|
||||||
|
257 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 13312/13312 bytes at offset 525312
|
||||||
|
13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 509952/509952 bytes at offset 538624
|
||||||
|
498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== overwriting zero cluster ==
|
||||||
|
wrote 8192/8192 bytes at offset 61440
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 8192/8192 bytes at offset 65536
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 4096/4096 bytes at offset 77824
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 8192/8192 bytes at offset 258048
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
wrote 8192/8192 bytes at offset 253952
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
== verifying patterns (4) ==
|
||||||
|
read 61440/61440 bytes at offset 0
|
||||||
|
60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 61440
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 8192/8192 bytes at offset 65536
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 73728
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 77824
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 172032/172032 bytes at offset 81920
|
||||||
|
168 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 8192/8192 bytes at offset 253952
|
||||||
|
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 262144
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 65536/65536 bytes at offset 266240
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== re-zeroing overwritten area ==
|
||||||
|
wrote 196608/196608 bytes at offset 65536
|
||||||
|
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
No errors were found on the image.
|
||||||
|
|
||||||
|
== verifying patterns (5) ==
|
||||||
|
read 61440/61440 bytes at offset 0
|
||||||
|
60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 61440
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 196608/196608 bytes at offset 65536
|
||||||
|
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 4096/4096 bytes at offset 262144
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 259072/259072 bytes at offset 266240
|
||||||
|
253 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 13312/13312 bytes at offset 525312
|
||||||
|
13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 509952/509952 bytes at offset 538624
|
||||||
|
498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
*** done
|
|
@ -41,9 +41,6 @@ then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# we need common
|
|
||||||
. ./common
|
|
||||||
|
|
||||||
# we need common.rc
|
# we need common.rc
|
||||||
if ! . ./common.rc
|
if ! . ./common.rc
|
||||||
then
|
then
|
||||||
|
@ -51,6 +48,9 @@ then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# we need common
|
||||||
|
. ./common
|
||||||
|
|
||||||
#if [ `id -u` -ne 0 ]
|
#if [ `id -u` -ne 0 ]
|
||||||
#then
|
#then
|
||||||
# echo "check: QA must be run as root"
|
# echo "check: QA must be run as root"
|
||||||
|
|
|
@ -35,6 +35,7 @@ diff="diff -u"
|
||||||
verbose=false
|
verbose=false
|
||||||
group=false
|
group=false
|
||||||
xgroup=false
|
xgroup=false
|
||||||
|
imgopts=false
|
||||||
showme=false
|
showme=false
|
||||||
sortme=false
|
sortme=false
|
||||||
expunge=true
|
expunge=true
|
||||||
|
@ -44,6 +45,7 @@ rm -f $tmp.list $tmp.tmp $tmp.sed
|
||||||
|
|
||||||
export IMGFMT=raw
|
export IMGFMT=raw
|
||||||
export IMGPROTO=file
|
export IMGPROTO=file
|
||||||
|
export IMGOPTS=""
|
||||||
export QEMU_IO_OPTIONS=""
|
export QEMU_IO_OPTIONS=""
|
||||||
|
|
||||||
for r
|
for r
|
||||||
|
@ -103,6 +105,13 @@ s/ .*//p
|
||||||
mv $tmp.tmp $tmp.list
|
mv $tmp.tmp $tmp.list
|
||||||
xgroup=false
|
xgroup=false
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
elif $imgopts
|
||||||
|
then
|
||||||
|
IMGOPTS="$r"
|
||||||
|
imgopts=false
|
||||||
|
continue
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
xpand=true
|
xpand=true
|
||||||
|
@ -130,6 +139,7 @@ check options
|
||||||
-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
|
||||||
-T output timestamps
|
-T output timestamps
|
||||||
-r randomize test order
|
-r randomize test order
|
||||||
|
|
||||||
|
@ -223,6 +233,10 @@ testlist options
|
||||||
showme=true
|
showme=true
|
||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
|
-o)
|
||||||
|
imgopts=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
-r) # randomize test order
|
-r) # randomize test order
|
||||||
randomize=true
|
randomize=true
|
||||||
xpand=false
|
xpand=false
|
||||||
|
@ -299,6 +313,9 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Set default options for qemu-img create -o if they were not specified
|
||||||
|
_set_default_imgopts
|
||||||
|
|
||||||
if [ -s $tmp.list ]
|
if [ -s $tmp.list ]
|
||||||
then
|
then
|
||||||
# found some valid test numbers ... this is good
|
# found some valid test numbers ... this is good
|
||||||
|
|
|
@ -36,7 +36,7 @@ export LANG=C
|
||||||
|
|
||||||
PATH=".:$PATH"
|
PATH=".:$PATH"
|
||||||
|
|
||||||
HOST=`hostname -s`
|
HOST=`hostname -s 2> /dev/null`
|
||||||
HOSTOS=`uname -s`
|
HOSTOS=`uname -s`
|
||||||
|
|
||||||
EMAIL=root@localhost # where auto-qa will send its status messages
|
EMAIL=root@localhost # where auto-qa will send its status messages
|
||||||
|
|
|
@ -53,21 +53,44 @@ else
|
||||||
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
|
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_optstr_add()
|
||||||
|
{
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
echo "$1,$2"
|
||||||
|
else
|
||||||
|
echo "$2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_set_default_imgopts()
|
||||||
|
{
|
||||||
|
if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
|
||||||
|
IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
_make_test_img()
|
_make_test_img()
|
||||||
{
|
{
|
||||||
# extra qemu-img options can be added by tests
|
# extra qemu-img options can be added by tests
|
||||||
# at least one argument (the image size) needs to be added
|
# at least one argument (the image size) needs to be added
|
||||||
local extra_img_options=""
|
local extra_img_options=""
|
||||||
local cluster_size_filter="s# cluster_size=[0-9]\\+##g"
|
|
||||||
local image_size=$*
|
local image_size=$*
|
||||||
|
local optstr=""
|
||||||
|
|
||||||
|
if [ -n "$IMGOPTS" ]; then
|
||||||
|
optstr=$(_optstr_add "$optstr" "$IMGOPTS")
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$1" = "-b" ]; then
|
if [ "$1" = "-b" ]; then
|
||||||
extra_img_options="$1 $2"
|
extra_img_options="$1 $2"
|
||||||
image_size=$3
|
image_size=$3
|
||||||
fi
|
fi
|
||||||
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
|
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
|
||||||
extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
|
optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
|
||||||
cluster_size_filter=""
|
fi
|
||||||
|
|
||||||
|
if [ -n "$optstr" ]; then
|
||||||
|
extra_img_options="-o $optstr $extra_img_options"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# XXX(hch): have global image options?
|
# XXX(hch): have global image options?
|
||||||
|
@ -76,8 +99,9 @@ _make_test_img()
|
||||||
sed -e "s#$TEST_DIR#TEST_DIR#g" | \
|
sed -e "s#$TEST_DIR#TEST_DIR#g" | \
|
||||||
sed -e "s#$IMGFMT#IMGFMT#g" | \
|
sed -e "s#$IMGFMT#IMGFMT#g" | \
|
||||||
sed -e "s# encryption=off##g" | \
|
sed -e "s# encryption=off##g" | \
|
||||||
sed -e "$cluster_size_filter" | \
|
sed -e "s# cluster_size=[0-9]\\+##g" | \
|
||||||
sed -e "s# table_size=0##g" | \
|
sed -e "s# table_size=0##g" | \
|
||||||
|
sed -e "s# compat='[^']*'##g" | \
|
||||||
sed -e "s# compat6=off##g" | \
|
sed -e "s# compat6=off##g" | \
|
||||||
sed -e "s# static=off##g"
|
sed -e "s# static=off##g"
|
||||||
}
|
}
|
||||||
|
@ -270,7 +294,11 @@ _require_command()
|
||||||
|
|
||||||
_full_imgfmt_details()
|
_full_imgfmt_details()
|
||||||
{
|
{
|
||||||
echo "$IMGFMT"
|
if [ -n "$IMGOPTS" ]; then
|
||||||
|
echo "$IMGFMT ($IMGOPTS)"
|
||||||
|
else
|
||||||
|
echo "$IMGFMT"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_full_imgproto_details()
|
_full_imgproto_details()
|
||||||
|
|
|
@ -38,3 +38,6 @@
|
||||||
029 rw auto quick
|
029 rw auto quick
|
||||||
030 rw auto
|
030 rw auto
|
||||||
031 rw auto quick
|
031 rw auto quick
|
||||||
|
032 rw auto
|
||||||
|
033 rw auto
|
||||||
|
034 rw auto backing
|
||||||
|
|
|
@ -35,6 +35,13 @@ class QcowHeader:
|
||||||
[ uint32_t, '%d', 'refcount_table_clusters' ],
|
[ uint32_t, '%d', 'refcount_table_clusters' ],
|
||||||
[ uint32_t, '%d', 'nb_snapshots' ],
|
[ uint32_t, '%d', 'nb_snapshots' ],
|
||||||
[ uint64_t, '%#x', 'snapshot_offset' ],
|
[ uint64_t, '%#x', 'snapshot_offset' ],
|
||||||
|
|
||||||
|
# Version 3 header fields
|
||||||
|
[ uint64_t, '%#x', 'incompatible_features' ],
|
||||||
|
[ uint64_t, '%#x', 'compatible_features' ],
|
||||||
|
[ uint64_t, '%#x', 'autoclear_features' ],
|
||||||
|
[ uint32_t, '%d', 'refcount_order' ],
|
||||||
|
[ uint32_t, '%d', 'header_length' ],
|
||||||
];
|
];
|
||||||
|
|
||||||
fmt = '>' + ''.join(field[0] for field in fields)
|
fmt = '>' + ''.join(field[0] for field in fields)
|
||||||
|
@ -50,9 +57,10 @@ class QcowHeader:
|
||||||
self.__dict__ = dict((field[2], header[i])
|
self.__dict__ = dict((field[2], header[i])
|
||||||
for i, field in enumerate(QcowHeader.fields))
|
for i, field in enumerate(QcowHeader.fields))
|
||||||
|
|
||||||
|
self.set_defaults()
|
||||||
self.cluster_size = 1 << self.cluster_bits
|
self.cluster_size = 1 << self.cluster_bits
|
||||||
|
|
||||||
fd.seek(self.get_header_length())
|
fd.seek(self.header_length)
|
||||||
self.load_extensions(fd)
|
self.load_extensions(fd)
|
||||||
|
|
||||||
if self.backing_file_offset:
|
if self.backing_file_offset:
|
||||||
|
@ -61,11 +69,13 @@ class QcowHeader:
|
||||||
else:
|
else:
|
||||||
self.backing_file = None
|
self.backing_file = None
|
||||||
|
|
||||||
def get_header_length(self):
|
def set_defaults(self):
|
||||||
if self.version == 2:
|
if self.version == 2:
|
||||||
return 72
|
self.incompatible_features = 0
|
||||||
else:
|
self.compatible_features = 0
|
||||||
raise Exception("version != 2 not supported")
|
self.autoclear_features = 0
|
||||||
|
self.refcount_order = 4
|
||||||
|
self.header_length = 72
|
||||||
|
|
||||||
def load_extensions(self, fd):
|
def load_extensions(self, fd):
|
||||||
self.extensions = []
|
self.extensions = []
|
||||||
|
@ -86,7 +96,7 @@ class QcowHeader:
|
||||||
|
|
||||||
def update_extensions(self, fd):
|
def update_extensions(self, fd):
|
||||||
|
|
||||||
fd.seek(self.get_header_length())
|
fd.seek(self.header_length)
|
||||||
extensions = self.extensions
|
extensions = self.extensions
|
||||||
extensions.append(QcowHeaderExtension(0, 0, ""))
|
extensions.append(QcowHeaderExtension(0, 0, ""))
|
||||||
for ex in extensions:
|
for ex in extensions:
|
||||||
|
@ -103,7 +113,7 @@ class QcowHeader:
|
||||||
|
|
||||||
|
|
||||||
def update(self, fd):
|
def update(self, fd):
|
||||||
header_bytes = self.get_header_length()
|
header_bytes = self.header_length
|
||||||
|
|
||||||
self.update_extensions(fd)
|
self.update_extensions(fd)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue