mirror of https://github.com/xemu-project/xemu.git
Merge remote-tracking branch 'kwolf/for-anthony' into staging
This commit is contained in:
commit
2a22e6eb1b
428
block.c
428
block.c
|
@ -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
10
block.h
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
32
block/raw.c
32
block/raw.c
|
@ -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,
|
||||
|
||||
|
|
109
block/vvfat.c
109
block/vvfat.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
21
linux-aio.c
21
linux-aio.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue