Merge remote-tracking branch 'kwolf/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2011-10-14 12:36:50 -05:00
commit 2a22e6eb1b
12 changed files with 285 additions and 635 deletions

428
block.c
View File

@ -44,6 +44,8 @@
#include <windows.h>
#endif
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@ -55,16 +57,6 @@ static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
@ -72,6 +64,18 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque,
bool is_write);
static void coroutine_fn bdrv_co_do_rw(void *opaque);
static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
QTAILQ_HEAD_INITIALIZER(bdrv_states);
@ -184,24 +188,18 @@ void path_combine(char *dest, int dest_size,
void bdrv_register(BlockDriver *bdrv)
{
if (bdrv->bdrv_co_readv) {
/* Emulate AIO by coroutines, and sync by AIO */
bdrv->bdrv_aio_readv = bdrv_co_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_co_aio_writev_em;
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
} else {
/* Block drivers without coroutine functions need emulation */
if (!bdrv->bdrv_co_readv) {
bdrv->bdrv_co_readv = bdrv_co_readv_em;
bdrv->bdrv_co_writev = bdrv_co_writev_em;
/* bdrv_co_readv_em()/brdv_co_writev_em() work in terms of aio, so if
* the block driver lacks aio we need to emulate that too.
*/
if (!bdrv->bdrv_aio_readv) {
/* add AIO emulation layer */
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
} else if (!bdrv->bdrv_read) {
/* add synchronous IO emulation layer */
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
}
@ -221,6 +219,7 @@ BlockDriverState *bdrv_new(const char *device_name)
if (device_name[0] != '\0') {
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
}
bdrv_iostatus_disable(bs);
return bs;
}
@ -772,6 +771,7 @@ int bdrv_attach_dev(BlockDriverState *bs, void *dev)
return -EBUSY;
}
bs->dev = dev;
bdrv_iostatus_reset(bs);
return 0;
}
@ -1027,41 +1027,74 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
nb_sectors * BDRV_SECTOR_SIZE);
}
static inline bool bdrv_has_async_rw(BlockDriver *drv)
{
return drv->bdrv_co_readv != bdrv_co_readv_em
|| drv->bdrv_aio_readv != bdrv_aio_readv_em;
}
static inline bool bdrv_has_async_flush(BlockDriver *drv)
{
return drv->bdrv_aio_flush != bdrv_aio_flush_em;
}
typedef struct RwCo {
BlockDriverState *bs;
int64_t sector_num;
int nb_sectors;
QEMUIOVector *qiov;
bool is_write;
int ret;
} RwCo;
static void coroutine_fn bdrv_rw_co_entry(void *opaque)
{
RwCo *rwco = opaque;
if (!rwco->is_write) {
rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
rwco->nb_sectors, rwco->qiov);
} else {
rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
rwco->nb_sectors, rwco->qiov);
}
}
/*
* Process a synchronous request using coroutines
*/
static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf,
int nb_sectors, bool is_write)
{
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
Coroutine *co;
RwCo rwco = {
.bs = bs,
.sector_num = sector_num,
.nb_sectors = nb_sectors,
.qiov = &qiov,
.is_write = is_write,
.ret = NOT_DONE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_rw_co_entry(&rwco);
} else {
co = qemu_coroutine_create(bdrv_rw_co_entry);
qemu_coroutine_enter(co, &rwco);
while (rwco.ret == NOT_DONE) {
qemu_aio_wait();
}
}
return rwco.ret;
}
/* return < 0 if error. See bdrv_write() for the return codes */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BlockDriver *drv = bs->drv;
if (!drv)
return -ENOMEDIUM;
if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_co_readv(bs, sector_num, nb_sectors, &qiov);
}
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
}
static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
@ -1101,36 +1134,7 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BlockDriver *drv = bs->drv;
if (!bs->drv)
return -ENOMEDIUM;
if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
QEMUIOVector qiov;
struct iovec iov = {
.iov_base = (void *)buf,
.iov_len = nb_sectors * BDRV_SECTOR_SIZE,
};
qemu_iovec_init_external(&qiov, &iov, 1);
return bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
}
if (bs->read_only)
return -EACCES;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
}
int bdrv_pread(BlockDriverState *bs, int64_t offset,
@ -1251,13 +1255,14 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
return 0;
}
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
/*
* Handle a read request in coroutine context
*/
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
BlockDriver *drv = bs->drv;
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
if (!drv) {
return -ENOMEDIUM;
}
@ -1268,12 +1273,22 @@ int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
}
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
BlockDriver *drv = bs->drv;
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
trace_bdrv_co_writev(bs, sector_num, nb_sectors);
return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
}
/*
* Handle a write request in coroutine context
*/
static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
BlockDriver *drv = bs->drv;
int ret;
if (!bs->drv) {
return -ENOMEDIUM;
@ -1285,6 +1300,8 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
return -EIO;
}
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
@ -1293,7 +1310,15 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
return drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
return ret;
}
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
trace_bdrv_co_writev(bs, sector_num, nb_sectors);
return bdrv_co_do_writev(bs, sector_num, nb_sectors, qiov);
}
/**
@ -1866,6 +1891,11 @@ static void bdrv_print_dict(QObject *obj, void *opaque)
monitor_printf(mon, " tray-open=%d",
qdict_get_bool(bs_dict, "tray-open"));
}
if (qdict_haskey(bs_dict, "io-status")) {
monitor_printf(mon, " io-status=%s", qdict_get_str(bs_dict, "io-status"));
}
if (qdict_haskey(bs_dict, "inserted")) {
QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
@ -1891,6 +1921,12 @@ void bdrv_info_print(Monitor *mon, const QObject *data)
qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
}
static const char *const io_status_name[BDRV_IOS_MAX] = {
[BDRV_IOS_OK] = "ok",
[BDRV_IOS_FAILED] = "failed",
[BDRV_IOS_ENOSPC] = "nospace",
};
void bdrv_info(Monitor *mon, QObject **ret_data)
{
QList *bs_list;
@ -1913,6 +1949,12 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
qdict_put(bs_dict, "tray-open",
qbool_from_int(bdrv_dev_is_tray_open(bs)));
}
if (bdrv_iostatus_is_enabled(bs)) {
qdict_put(bs_dict, "io-status",
qstring_from_str(io_status_name[bs->iostatus]));
}
if (bs->drv) {
QObject *obj;
@ -2314,89 +2356,20 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
if (!drv)
return NULL;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
return drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
cb, opaque);
}
typedef struct BlockCompleteData {
BlockDriverCompletionFunc *cb;
void *opaque;
BlockDriverState *bs;
int64_t sector_num;
int nb_sectors;
} BlockCompleteData;
static void block_complete_cb(void *opaque, int ret)
{
BlockCompleteData *b = opaque;
if (b->bs->dirty_bitmap) {
set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
}
b->cb(b->opaque, ret);
g_free(b);
}
static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
BlockCompleteData *blkdata = g_malloc0(sizeof(BlockCompleteData));
blkdata->bs = bs;
blkdata->cb = cb;
blkdata->opaque = opaque;
blkdata->sector_num = sector_num;
blkdata->nb_sectors = nb_sectors;
return blkdata;
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
cb, opaque, false);
}
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
BlockDriverAIOCB *ret;
BlockCompleteData *blk_cb_data;
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
if (!drv)
return NULL;
if (bs->read_only)
return NULL;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
if (bs->dirty_bitmap) {
blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
opaque);
cb = &block_complete_cb;
opaque = blk_cb_data;
}
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
cb, opaque);
if (ret) {
if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
bs->wr_highest_sector = sector_num + nb_sectors - 1;
}
}
return ret;
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
cb, opaque, true);
}
@ -2720,9 +2693,9 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
if (is_write) {
qemu_iovec_to_buffer(acb->qiov, acb->bounce);
acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
acb->ret = bs->drv->bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
} else {
acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
acb->ret = bs->drv->bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
}
qemu_bh_schedule(acb->bh);
@ -2771,16 +2744,17 @@ static void bdrv_co_rw_bh(void *opaque)
qemu_aio_release(acb);
}
static void coroutine_fn bdrv_co_rw(void *opaque)
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
static void coroutine_fn bdrv_co_do_rw(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockDriverState *bs = acb->common.bs;
if (!acb->is_write) {
acb->req.error = bs->drv->bdrv_co_readv(bs, acb->req.sector,
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
} else {
acb->req.error = bs->drv->bdrv_co_writev(bs, acb->req.sector,
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
}
@ -2805,28 +2779,12 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
acb->req.qiov = qiov;
acb->is_write = is_write;
co = qemu_coroutine_create(bdrv_co_rw);
co = qemu_coroutine_create(bdrv_co_do_rw);
qemu_coroutine_enter(co, acb);
return &acb->common;
}
static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
false);
}
static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
true);
}
static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
@ -2865,70 +2823,6 @@ static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
return &acb->common;
}
/**************************************************************/
/* sync block device emulation */
static void bdrv_rw_em_cb(void *opaque, int ret)
{
*(int *)opaque = ret;
}
#define NOT_DONE 0x7fffffff
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int async_ret;
BlockDriverAIOCB *acb;
struct iovec iov;
QEMUIOVector qiov;
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&qiov, &iov, 1);
acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
bdrv_rw_em_cb, &async_ret);
if (acb == NULL) {
async_ret = -1;
goto fail;
}
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
fail:
return async_ret;
}
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int async_ret;
BlockDriverAIOCB *acb;
struct iovec iov;
QEMUIOVector qiov;
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&qiov, &iov, 1);
acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
bdrv_rw_em_cb, &async_ret);
if (acb == NULL) {
async_ret = -1;
goto fail;
}
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
fail:
return async_ret;
}
void bdrv_init(void)
{
module_call_init(MODULE_INIT_BLOCK);
@ -2992,11 +2886,11 @@ static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
BlockDriverAIOCB *acb;
if (is_write) {
acb = bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
} else {
acb = bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
bdrv_co_io_em_complete, &co);
}
trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
@ -3183,6 +3077,44 @@ int bdrv_in_use(BlockDriverState *bs)
return bs->in_use;
}
void bdrv_iostatus_enable(BlockDriverState *bs)
{
bs->iostatus = BDRV_IOS_OK;
}
/* The I/O status is only enabled if the drive explicitly
* enables it _and_ the VM is configured to stop on errors */
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
{
return (bs->iostatus != BDRV_IOS_INVAL &&
(bs->on_write_error == BLOCK_ERR_STOP_ENOSPC ||
bs->on_write_error == BLOCK_ERR_STOP_ANY ||
bs->on_read_error == BLOCK_ERR_STOP_ANY));
}
void bdrv_iostatus_disable(BlockDriverState *bs)
{
bs->iostatus = BDRV_IOS_INVAL;
}
void bdrv_iostatus_reset(BlockDriverState *bs)
{
if (bdrv_iostatus_is_enabled(bs)) {
bs->iostatus = BDRV_IOS_OK;
}
}
/* XXX: Today this is set by device models because it makes the implementation
quite simple. However, the block layer knows about the error, so it's
possible to implement this without device models being involved */
void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
{
if (bdrv_iostatus_is_enabled(bs) && bs->iostatus == BDRV_IOS_OK) {
assert(error >= 0);
bs->iostatus = error == ENOSPC ? BDRV_IOS_ENOSPC : BDRV_IOS_FAILED;
}
}
void
bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
enum BlockAcctType type)

10
block.h
View File

@ -77,6 +77,16 @@ typedef enum {
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
} BlockMonEventAction;
typedef enum {
BDRV_IOS_INVAL, BDRV_IOS_OK, BDRV_IOS_FAILED, BDRV_IOS_ENOSPC,
BDRV_IOS_MAX
} BlockIOStatus;
void bdrv_iostatus_enable(BlockDriverState *bs);
void bdrv_iostatus_reset(BlockDriverState *bs);
void bdrv_iostatus_disable(BlockDriverState *bs);
bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
void bdrv_mon_event(const BlockDriverState *bdrv,
BlockMonEventAction action, int is_read);
void bdrv_info_print(Monitor *mon, const QObject *data);

View File

@ -296,273 +296,6 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
#endif
*/
/*
* offset and count are in bytes, but must be multiples of 512 for files
* opened with O_DIRECT. buf must be aligned to 512 bytes then.
*
* This function may be called without alignment if the caller ensures
* that O_DIRECT is not in effect.
*/
static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
int ret;
ret = fd_open(bs);
if (ret < 0)
return ret;
ret = pread(s->fd, buf, count, offset);
if (ret == count)
return ret;
/* Allow reads beyond the end (needed for pwrite) */
if ((ret == 0) && bs->growable) {
int64_t size = raw_getlength(bs);
if (offset >= size) {
memset(buf, 0, count);
return count;
}
}
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
"] read failed %d : %d = %s\n",
s->fd, bs->filename, offset, buf, count,
bs->total_sectors, ret, errno, strerror(errno));
/* Try harder for CDrom. */
if (s->type != FTYPE_FILE) {
ret = pread(s->fd, buf, count, offset);
if (ret == count)
return ret;
ret = pread(s->fd, buf, count, offset);
if (ret == count)
return ret;
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
"] retry read failed %d : %d = %s\n",
s->fd, bs->filename, offset, buf, count,
bs->total_sectors, ret, errno, strerror(errno));
}
return (ret < 0) ? -errno : ret;
}
/*
* offset and count are in bytes, but must be multiples of the sector size
* for files opened with O_DIRECT. buf must be aligned to sector size bytes
* then.
*
* This function may be called without alignment if the caller ensures
* that O_DIRECT is not in effect.
*/
static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
int ret;
ret = fd_open(bs);
if (ret < 0)
return -errno;
ret = pwrite(s->fd, buf, count, offset);
if (ret == count)
return ret;
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
"] write failed %d : %d = %s\n",
s->fd, bs->filename, offset, buf, count,
bs->total_sectors, ret, errno, strerror(errno));
return (ret < 0) ? -errno : ret;
}
/*
* offset and count are in bytes and possibly not aligned. For files opened
* with O_DIRECT, necessary alignments are ensured before calling
* raw_pread_aligned to do the actual read.
*/
static int raw_pread(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
unsigned sector_mask = bs->buffer_alignment - 1;
int size, ret, shift, sum;
sum = 0;
if (s->aligned_buf != NULL) {
if (offset & sector_mask) {
/* align offset on a sector size bytes boundary */
shift = offset & sector_mask;
size = (shift + count + sector_mask) & ~sector_mask;
if (size > s->aligned_buf_size)
size = s->aligned_buf_size;
ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size);
if (ret < 0)
return ret;
size = bs->buffer_alignment - shift;
if (size > count)
size = count;
memcpy(buf, s->aligned_buf + shift, size);
buf += size;
offset += size;
count -= size;
sum += size;
if (count == 0)
return sum;
}
if (count & sector_mask || (uintptr_t) buf & sector_mask) {
/* read on aligned buffer */
while (count) {
size = (count + sector_mask) & ~sector_mask;
if (size > s->aligned_buf_size)
size = s->aligned_buf_size;
ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
if (ret < 0) {
return ret;
} else if (ret == 0) {
fprintf(stderr, "raw_pread: read beyond end of file\n");
abort();
}
size = ret;
if (size > count)
size = count;
memcpy(buf, s->aligned_buf, size);
buf += size;
offset += size;
count -= size;
sum += size;
}
return sum;
}
}
return raw_pread_aligned(bs, offset, buf, count) + sum;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret;
ret = raw_pread(bs, sector_num * BDRV_SECTOR_SIZE, buf,
nb_sectors * BDRV_SECTOR_SIZE);
if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
ret = 0;
return ret;
}
/*
* offset and count are in bytes and possibly not aligned. For files opened
* with O_DIRECT, necessary alignments are ensured before calling
* raw_pwrite_aligned to do the actual write.
*/
static int raw_pwrite(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count)
{
BDRVRawState *s = bs->opaque;
unsigned sector_mask = bs->buffer_alignment - 1;
int size, ret, shift, sum;
sum = 0;
if (s->aligned_buf != NULL) {
if (offset & sector_mask) {
/* align offset on a sector size bytes boundary */
shift = offset & sector_mask;
ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf,
bs->buffer_alignment);
if (ret < 0)
return ret;
size = bs->buffer_alignment - shift;
if (size > count)
size = count;
memcpy(s->aligned_buf + shift, buf, size);
ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf,
bs->buffer_alignment);
if (ret < 0)
return ret;
buf += size;
offset += size;
count -= size;
sum += size;
if (count == 0)
return sum;
}
if (count & sector_mask || (uintptr_t) buf & sector_mask) {
while ((size = (count & ~sector_mask)) != 0) {
if (size > s->aligned_buf_size)
size = s->aligned_buf_size;
memcpy(s->aligned_buf, buf, size);
ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size);
if (ret < 0)
return ret;
buf += ret;
offset += ret;
count -= ret;
sum += ret;
}
/* here, count < sector_size because (count & ~sector_mask) == 0 */
if (count) {
ret = raw_pread_aligned(bs, offset, s->aligned_buf,
bs->buffer_alignment);
if (ret < 0)
return ret;
memcpy(s->aligned_buf, buf, count);
ret = raw_pwrite_aligned(bs, offset, s->aligned_buf,
bs->buffer_alignment);
if (ret < 0)
return ret;
if (count < ret)
ret = count;
sum += ret;
}
return sum;
}
}
return raw_pwrite_aligned(bs, offset, buf, count) + sum;
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int ret;
ret = raw_pwrite(bs, sector_num * BDRV_SECTOR_SIZE, buf,
nb_sectors * BDRV_SECTOR_SIZE);
if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
ret = 0;
return ret;
}
/*
* Check if all memory in this vector is sector aligned.
*/
@ -649,10 +382,24 @@ static void raw_close(BlockDriverState *bs)
static int raw_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVRawState *s = bs->opaque;
if (s->type != FTYPE_FILE)
return -ENOTSUP;
if (ftruncate(s->fd, offset) < 0)
struct stat st;
if (fstat(s->fd, &st)) {
return -errno;
}
if (S_ISREG(st.st_mode)) {
if (ftruncate(s->fd, offset) < 0) {
return -errno;
}
} else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
if (offset > raw_getlength(bs)) {
return -EINVAL;
}
} else {
return -ENOTSUP;
}
return 0;
}
@ -896,8 +643,6 @@ static BlockDriver bdrv_file = {
.instance_size = sizeof(BDRVRawState),
.bdrv_probe = NULL, /* no probe for protocols */
.bdrv_file_open = raw_open,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
.bdrv_flush = raw_flush,
@ -1176,8 +921,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
@ -1297,8 +1041,7 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
@ -1398,8 +1141,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
@ -1519,8 +1261,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,

View File

@ -9,30 +9,16 @@ static int raw_open(BlockDriverState *bs, int flags)
return 0;
}
static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
return bdrv_read(bs->file, sector_num, buf, nb_sectors);
return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
}
static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov)
{
return bdrv_write(bs->file, sector_num, buf, nb_sectors);
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
}
static void raw_close(BlockDriverState *bs)
@ -129,15 +115,13 @@ static BlockDriver bdrv_raw = {
.bdrv_open = raw_open,
.bdrv_close = raw_close,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
.bdrv_co_readv = raw_co_readv,
.bdrv_co_writev = raw_co_writev,
.bdrv_flush = raw_flush,
.bdrv_probe = raw_probe,
.bdrv_getlength = raw_getlength,
.bdrv_truncate = raw_truncate,
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
.bdrv_discard = raw_discard,

View File

@ -86,8 +86,7 @@ static inline void array_init(array_t* array,unsigned int item_size)
static inline void array_free(array_t* array)
{
if(array->pointer)
free(array->pointer);
g_free(array->pointer);
array->size=array->next=0;
}
@ -169,7 +168,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
memcpy(to,buf,is*count);
free(buf);
g_free(buf);
return 0;
}
@ -732,7 +731,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
if(stat(buffer,&st)<0) {
free(buffer);
g_free(buffer);
continue;
}
@ -755,7 +754,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
direntry->begin=0; /* do that later */
if (st.st_size > 0x7fffffff) {
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
free(buffer);
g_free(buffer);
closedir(dir);
return -2;
}
@ -825,20 +824,6 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
return s->faked_sectors + s->sectors_per_cluster * cluster_num;
}
static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
{
return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
}
#ifdef DBG
static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
{
if(mapping->mode==MODE_UNDEFINED)
return 0;
return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
}
#endif
static int init_directories(BDRVVVFATState* s,
const char* dirname)
{
@ -1138,25 +1123,6 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_
return mapping;
}
/*
* This function simply compares path == mapping->path. Since the mappings
* are sorted by cluster, this is expensive: O(n).
*/
static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
const char* path)
{
int i;
for (i = 0; i < s->mapping.next; i++) {
mapping_t* mapping = array_get(&(s->mapping), i);
if (mapping->first_mapping_index < 0 &&
!strcmp(path, mapping->path))
return mapping;
}
return NULL;
}
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
{
if(!mapping)
@ -1223,23 +1189,6 @@ read_cluster_directory:
}
#ifdef DEBUG
static void hexdump(const void* address, uint32_t len)
{
const unsigned char* p = address;
int i, j;
for (i = 0; i < len; i += 16) {
for (j = 0; j < 16 && i + j < len; j++)
fprintf(stderr, "%02x ", p[i + j]);
for (; j < 16; j++)
fprintf(stderr, " ");
fprintf(stderr, " ");
for (j = 0; j < 16 && i + j < len; j++)
fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
fprintf(stderr, "\n");
}
}
static void print_direntry(const direntry_t* direntry)
{
int j = 0;
@ -1375,7 +1324,7 @@ DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
assert(commit->path || commit->action == ACTION_WRITEOUT);
if (commit->action != ACTION_WRITEOUT) {
assert(commit->path);
free(commit->path);
g_free(commit->path);
} else
assert(commit->path == NULL);
}
@ -1741,7 +1690,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
long_file_name lfn;
int path_len = strlen(path);
char path2[PATH_MAX];
char path2[PATH_MAX + 1];
assert(path_len < PATH_MAX); /* len was tested before! */
pstrcpy(path2, sizeof(path2), path);
@ -1782,7 +1731,7 @@ DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)clu
if (subret) {
fprintf(stderr, "Error fetching direntries\n");
fail:
free(cluster);
g_free(cluster);
return 0;
}
@ -1850,7 +1799,7 @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i))
cluster_num = modified_fat_get(s, cluster_num);
} while(!fat_eof(s, cluster_num));
free(cluster);
g_free(cluster);
return ret;
}
@ -1995,8 +1944,9 @@ static int remove_mapping(BDRVVVFATState* s, int mapping_index)
mapping_t* first_mapping = array_get(&(s->mapping), 0);
/* free mapping */
if (mapping->first_mapping_index < 0)
free(mapping->path);
if (mapping->first_mapping_index < 0) {
g_free(mapping->path);
}
/* remove from s->mapping */
array_remove(&(s->mapping), mapping_index);
@ -2232,11 +2182,15 @@ static int commit_one_file(BDRVVVFATState* s,
if (fd < 0) {
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
strerror(errno), errno);
g_free(cluster);
return fd;
}
if (offset > 0)
if (lseek(fd, offset, SEEK_SET) != offset)
return -3;
if (offset > 0) {
if (lseek(fd, offset, SEEK_SET) != offset) {
g_free(cluster);
return -3;
}
}
while (offset < size) {
uint32_t c1;
@ -2252,11 +2206,15 @@ static int commit_one_file(BDRVVVFATState* s,
ret = vvfat_read(s->bs, cluster2sector(s, c),
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
if (ret < 0)
return ret;
if (ret < 0) {
g_free(cluster);
return ret;
}
if (write(fd, cluster, rest_size) < 0)
return -2;
if (write(fd, cluster, rest_size) < 0) {
g_free(cluster);
return -2;
}
offset += rest_size;
c = c1;
@ -2265,9 +2223,11 @@ static int commit_one_file(BDRVVVFATState* s,
if (ftruncate(fd, size)) {
perror("ftruncate()");
close(fd);
g_free(cluster);
return -4;
}
close(fd);
g_free(cluster);
return commit_mappings(s, first_cluster, dir_index);
}
@ -2399,7 +2359,7 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
}
}
free(old_path);
g_free(old_path);
array_remove(&(s->commits), i);
continue;
} else if (commit->action == ACTION_MKDIR) {
@ -2775,7 +2735,7 @@ static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
static void write_target_close(BlockDriverState *bs) {
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
bdrv_delete(s->qcow);
free(s->qcow_filename);
g_free(s->qcow_filename);
}
static BlockDriver vvfat_write_target = {
@ -2836,8 +2796,7 @@ static void vvfat_close(BlockDriverState *bs)
array_free(&(s->fat));
array_free(&(s->directory));
array_free(&(s->mapping));
if(s->cluster_buffer)
free(s->cluster_buffer);
g_free(s->cluster_buffer);
}
static BlockDriver bdrv_vvfat = {
@ -2878,11 +2837,5 @@ static void checkpoint(void) {
direntry = array_get(&(vvv->directory), mapping->dir_index);
assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
#endif
return;
/* avoid compiler warnings: */
hexdump(NULL, 100);
remove_mapping(vvv, 0);
print_mapping(NULL);
print_direntry(NULL);
}
#endif

View File

@ -199,6 +199,7 @@ struct BlockDriverState {
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
BlockErrorAction on_read_error, on_write_error;
BlockIOStatus iostatus;
char device_name[32];
unsigned long *dirty_bitmap;
int64_t dirty_count;

View File

@ -529,6 +529,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
s->bus->error_status = op;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->bs, error);
} else {
if (op & BM_STATUS_DMA_RETRY) {
dma_buf_commit(s, 0);
@ -1873,6 +1874,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
}
ide_reset(s);
bdrv_iostatus_enable(bs);
return 0;
}

View File

@ -228,6 +228,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->bs, error);
} else {
switch (error) {
case ENOMEM:
@ -1260,6 +1261,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
bdrv_iostatus_enable(s->bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
}

View File

@ -78,6 +78,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
s->rq = req;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->bs, error);
} else {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
bdrv_acct_done(s->bs, &req->acct);
@ -603,6 +604,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
bdrv_iostatus_enable(s->bs);
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
return &s->vdev;

View File

@ -31,6 +31,8 @@ struct qemu_laiocb {
struct iocb iocb;
ssize_t ret;
size_t nbytes;
QEMUIOVector *qiov;
bool is_read;
QLIST_ENTRY(qemu_laiocb) node;
};
@ -57,10 +59,17 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
ret = laiocb->ret;
if (ret != -ECANCELED) {
if (ret == laiocb->nbytes)
if (ret == laiocb->nbytes) {
ret = 0;
else if (ret >= 0)
ret = -EINVAL;
} else if (ret >= 0) {
/* Short reads mean EOF, pad with zeros. */
if (laiocb->is_read) {
qemu_iovec_memset_skip(laiocb->qiov, 0,
laiocb->qiov->size - ret, ret);
} else {
ret = -EINVAL;
}
}
laiocb->common.cb(laiocb->common.opaque, ret);
}
@ -162,6 +171,8 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
laiocb->nbytes = nb_sectors * 512;
laiocb->ctx = s;
laiocb->ret = -EINPROGRESS;
laiocb->is_read = (type == QEMU_AIO_READ);
laiocb->qiov = qiov;
iocbs = &laiocb->iocb;
@ -185,10 +196,10 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
goto out_dec_count;
return &laiocb->common;
out_free_aiocb:
qemu_aio_release(laiocb);
out_dec_count:
s->count--;
out_free_aiocb:
qemu_aio_release(laiocb);
return NULL;
}

View File

@ -1221,6 +1221,11 @@ struct bdrv_iterate_context {
int err;
};
static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
{
bdrv_iostatus_reset(bs);
}
/**
* do_cont(): Resume emulation.
*/
@ -1237,6 +1242,7 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
return -1;
}
bdrv_iterate(iostatus_bdrv_it, NULL);
bdrv_iterate(encrypted_bdrv_it, &context);
/* only resume the vm if all keys are set and valid */
if (!context.err) {

View File

@ -1154,6 +1154,10 @@ Each json-object contain the following:
"tftp", "vdi", "vmdk", "vpc", "vvfat"
- "backing_file": backing file name (json-string, optional)
- "encrypted": true if encrypted, false otherwise (json-bool)
- "io-status": I/O operation status, only present if the device supports it
and the VM is configured to stop on errors. It's always reset
to "ok" when the "cont" command is issued (json_string, optional)
- Possible values: "ok", "failed", "nospace"
Example:
@ -1161,6 +1165,7 @@ Example:
<- {
"return":[
{
"io-status": "ok",
"device":"ide0-hd0",
"locked":false,
"removable":false,
@ -1173,6 +1178,7 @@ Example:
"type":"unknown"
},
{
"io-status": "ok",
"device":"ide1-cd0",
"locked":false,
"removable":true,