mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-07 11:19:59 +00:00
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>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||||
|
|
||||||
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
|
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
|
||||||
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
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);
|
BlockDriverCompletionFunc *cb, void *opaque);
|
||||||
static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
|
static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
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,
|
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
|
||||||
int64_t sector_num, int nb_sectors,
|
int64_t sector_num, int nb_sectors,
|
||||||
QEMUIOVector *iov);
|
QEMUIOVector *iov);
|
||||||
@ -72,6 +64,18 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
|
|||||||
int64_t sector_num, int nb_sectors,
|
int64_t sector_num, int nb_sectors,
|
||||||
QEMUIOVector *iov);
|
QEMUIOVector *iov);
|
||||||
static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
|
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 =
|
static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
|
||||||
QTAILQ_HEAD_INITIALIZER(bdrv_states);
|
QTAILQ_HEAD_INITIALIZER(bdrv_states);
|
||||||
@ -184,24 +188,18 @@ void path_combine(char *dest, int dest_size,
|
|||||||
|
|
||||||
void bdrv_register(BlockDriver *bdrv)
|
void bdrv_register(BlockDriver *bdrv)
|
||||||
{
|
{
|
||||||
if (bdrv->bdrv_co_readv) {
|
/* Block drivers without coroutine functions need emulation */
|
||||||
/* Emulate AIO by coroutines, and sync by AIO */
|
if (!bdrv->bdrv_co_readv) {
|
||||||
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 {
|
|
||||||
bdrv->bdrv_co_readv = bdrv_co_readv_em;
|
bdrv->bdrv_co_readv = bdrv_co_readv_em;
|
||||||
bdrv->bdrv_co_writev = bdrv_co_writev_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) {
|
if (!bdrv->bdrv_aio_readv) {
|
||||||
/* add AIO emulation layer */
|
/* add AIO emulation layer */
|
||||||
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
|
bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
|
||||||
bdrv->bdrv_aio_writev = bdrv_aio_writev_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') {
|
if (device_name[0] != '\0') {
|
||||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
|
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
|
||||||
}
|
}
|
||||||
|
bdrv_iostatus_disable(bs);
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,6 +771,7 @@ int bdrv_attach_dev(BlockDriverState *bs, void *dev)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
bs->dev = dev;
|
bs->dev = dev;
|
||||||
|
bdrv_iostatus_reset(bs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,41 +1027,74 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
|||||||
nb_sectors * BDRV_SECTOR_SIZE);
|
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)
|
static inline bool bdrv_has_async_flush(BlockDriver *drv)
|
||||||
{
|
{
|
||||||
return drv->bdrv_aio_flush != bdrv_aio_flush_em;
|
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 */
|
/* return < 0 if error. See bdrv_write() for the return codes */
|
||||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
|
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,
|
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
const uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
return bdrv_rw_co(bs, sector_num, (uint8_t *)buf, nb_sectors, true);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||||
@ -1251,13 +1255,14 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
|||||||
return 0;
|
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;
|
BlockDriver *drv = bs->drv;
|
||||||
|
|
||||||
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
|
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
return -ENOMEDIUM;
|
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);
|
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)
|
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) {
|
if (!bs->drv) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
@ -1285,6 +1300,8 @@ int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
|
||||||
|
|
||||||
if (bs->dirty_bitmap) {
|
if (bs->dirty_bitmap) {
|
||||||
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
|
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;
|
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",
|
monitor_printf(mon, " tray-open=%d",
|
||||||
qdict_get_bool(bs_dict, "tray-open"));
|
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")) {
|
if (qdict_haskey(bs_dict, "inserted")) {
|
||||||
QDict *qdict = qobject_to_qdict(qdict_get(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);
|
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)
|
void bdrv_info(Monitor *mon, QObject **ret_data)
|
||||||
{
|
{
|
||||||
QList *bs_list;
|
QList *bs_list;
|
||||||
@ -1913,6 +1949,12 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
|
|||||||
qdict_put(bs_dict, "tray-open",
|
qdict_put(bs_dict, "tray-open",
|
||||||
qbool_from_int(bdrv_dev_is_tray_open(bs)));
|
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) {
|
if (bs->drv) {
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
|
|
||||||
@ -2314,89 +2356,20 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
QEMUIOVector *qiov, int nb_sectors,
|
QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
|
||||||
|
|
||||||
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
if (!drv)
|
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
||||||
return NULL;
|
cb, opaque, false);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
QEMUIOVector *qiov, int nb_sectors,
|
QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
|
||||||
BlockDriverAIOCB *ret;
|
|
||||||
BlockCompleteData *blk_cb_data;
|
|
||||||
|
|
||||||
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
||||||
|
|
||||||
if (!drv)
|
return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors,
|
||||||
return NULL;
|
cb, opaque, true);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2720,9 +2693,9 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
qemu_iovec_to_buffer(acb->qiov, acb->bounce);
|
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 {
|
} 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);
|
qemu_bh_schedule(acb->bh);
|
||||||
@ -2771,16 +2744,17 @@ static void bdrv_co_rw_bh(void *opaque)
|
|||||||
qemu_aio_release(acb);
|
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;
|
BlockDriverAIOCBCoroutine *acb = opaque;
|
||||||
BlockDriverState *bs = acb->common.bs;
|
BlockDriverState *bs = acb->common.bs;
|
||||||
|
|
||||||
if (!acb->is_write) {
|
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);
|
acb->req.nb_sectors, acb->req.qiov);
|
||||||
} else {
|
} 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);
|
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->req.qiov = qiov;
|
||||||
acb->is_write = is_write;
|
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);
|
qemu_coroutine_enter(co, acb);
|
||||||
|
|
||||||
return &acb->common;
|
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,
|
static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
@ -2865,70 +2823,6 @@ static BlockDriverAIOCB *bdrv_aio_noop_em(BlockDriverState *bs,
|
|||||||
return &acb->common;
|
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)
|
void bdrv_init(void)
|
||||||
{
|
{
|
||||||
module_call_init(MODULE_INIT_BLOCK);
|
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;
|
BlockDriverAIOCB *acb;
|
||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
acb = bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
|
acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
|
||||||
bdrv_co_io_em_complete, &co);
|
bdrv_co_io_em_complete, &co);
|
||||||
} else {
|
} else {
|
||||||
acb = bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
|
acb = bs->drv->bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
|
||||||
bdrv_co_io_em_complete, &co);
|
bdrv_co_io_em_complete, &co);
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
|
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;
|
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
|
void
|
||||||
bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
|
bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
|
||||||
enum BlockAcctType type)
|
enum BlockAcctType type)
|
||||||
|
10
block.h
10
block.h
@ -77,6 +77,16 @@ typedef enum {
|
|||||||
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
|
BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP
|
||||||
} BlockMonEventAction;
|
} 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,
|
void bdrv_mon_event(const BlockDriverState *bdrv,
|
||||||
BlockMonEventAction action, int is_read);
|
BlockMonEventAction action, int is_read);
|
||||||
void bdrv_info_print(Monitor *mon, const QObject *data);
|
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
|
#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.
|
* 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)
|
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
if (s->type != FTYPE_FILE)
|
struct stat st;
|
||||||
return -ENOTSUP;
|
|
||||||
if (ftruncate(s->fd, offset) < 0)
|
if (fstat(s->fd, &st)) {
|
||||||
return -errno;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -896,8 +643,6 @@ static BlockDriver bdrv_file = {
|
|||||||
.instance_size = sizeof(BDRVRawState),
|
.instance_size = sizeof(BDRVRawState),
|
||||||
.bdrv_probe = NULL, /* no probe for protocols */
|
.bdrv_probe = NULL, /* no probe for protocols */
|
||||||
.bdrv_file_open = raw_open,
|
.bdrv_file_open = raw_open,
|
||||||
.bdrv_read = raw_read,
|
|
||||||
.bdrv_write = raw_write,
|
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_create = raw_create,
|
.bdrv_create = raw_create,
|
||||||
.bdrv_flush = raw_flush,
|
.bdrv_flush = raw_flush,
|
||||||
@ -1176,8 +921,7 @@ static BlockDriver bdrv_host_device = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_write = raw_write,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_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_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_write = raw_write,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_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_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_write = raw_write,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_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_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_write = raw_write,
|
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
= raw_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_read(BlockDriverState *bs, int64_t sector_num,
|
static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
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,
|
static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
const uint8_t *buf, int nb_sectors)
|
int nb_sectors, QEMUIOVector *qiov)
|
||||||
{
|
{
|
||||||
return bdrv_write(bs->file, sector_num, buf, nb_sectors);
|
return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raw_close(BlockDriverState *bs)
|
static void raw_close(BlockDriverState *bs)
|
||||||
@ -129,15 +115,13 @@ static BlockDriver bdrv_raw = {
|
|||||||
|
|
||||||
.bdrv_open = raw_open,
|
.bdrv_open = raw_open,
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_read = raw_read,
|
.bdrv_co_readv = raw_co_readv,
|
||||||
.bdrv_write = raw_write,
|
.bdrv_co_writev = raw_co_writev,
|
||||||
.bdrv_flush = raw_flush,
|
.bdrv_flush = raw_flush,
|
||||||
.bdrv_probe = raw_probe,
|
.bdrv_probe = raw_probe,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
|
|
||||||
.bdrv_aio_readv = raw_aio_readv,
|
|
||||||
.bdrv_aio_writev = raw_aio_writev,
|
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_discard = raw_discard,
|
.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)
|
static inline void array_free(array_t* array)
|
||||||
{
|
{
|
||||||
if(array->pointer)
|
g_free(array->pointer);
|
||||||
free(array->pointer);
|
|
||||||
array->size=array->next=0;
|
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);
|
memcpy(to,buf,is*count);
|
||||||
|
|
||||||
free(buf);
|
g_free(buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -732,7 +731,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
|||||||
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
|
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
|
||||||
|
|
||||||
if(stat(buffer,&st)<0) {
|
if(stat(buffer,&st)<0) {
|
||||||
free(buffer);
|
g_free(buffer);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,7 +754,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
|||||||
direntry->begin=0; /* do that later */
|
direntry->begin=0; /* do that later */
|
||||||
if (st.st_size > 0x7fffffff) {
|
if (st.st_size > 0x7fffffff) {
|
||||||
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
|
fprintf(stderr, "File %s is larger than 2GB\n", buffer);
|
||||||
free(buffer);
|
g_free(buffer);
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return -2;
|
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;
|
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,
|
static int init_directories(BDRVVVFATState* s,
|
||||||
const char* dirname)
|
const char* dirname)
|
||||||
{
|
{
|
||||||
@ -1138,25 +1123,6 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_
|
|||||||
return mapping;
|
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)
|
static int open_file(BDRVVVFATState* s,mapping_t* mapping)
|
||||||
{
|
{
|
||||||
if(!mapping)
|
if(!mapping)
|
||||||
@ -1223,23 +1189,6 @@ read_cluster_directory:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#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)
|
static void print_direntry(const direntry_t* direntry)
|
||||||
{
|
{
|
||||||
int j = 0;
|
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);
|
assert(commit->path || commit->action == ACTION_WRITEOUT);
|
||||||
if (commit->action != ACTION_WRITEOUT) {
|
if (commit->action != ACTION_WRITEOUT) {
|
||||||
assert(commit->path);
|
assert(commit->path);
|
||||||
free(commit->path);
|
g_free(commit->path);
|
||||||
} else
|
} else
|
||||||
assert(commit->path == NULL);
|
assert(commit->path == NULL);
|
||||||
}
|
}
|
||||||
@ -1741,7 +1690,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
|||||||
|
|
||||||
long_file_name lfn;
|
long_file_name lfn;
|
||||||
int path_len = strlen(path);
|
int path_len = strlen(path);
|
||||||
char path2[PATH_MAX];
|
char path2[PATH_MAX + 1];
|
||||||
|
|
||||||
assert(path_len < PATH_MAX); /* len was tested before! */
|
assert(path_len < PATH_MAX); /* len was tested before! */
|
||||||
pstrcpy(path2, sizeof(path2), path);
|
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) {
|
if (subret) {
|
||||||
fprintf(stderr, "Error fetching direntries\n");
|
fprintf(stderr, "Error fetching direntries\n");
|
||||||
fail:
|
fail:
|
||||||
free(cluster);
|
g_free(cluster);
|
||||||
return 0;
|
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);
|
cluster_num = modified_fat_get(s, cluster_num);
|
||||||
} while(!fat_eof(s, cluster_num));
|
} while(!fat_eof(s, cluster_num));
|
||||||
|
|
||||||
free(cluster);
|
g_free(cluster);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1995,8 +1944,9 @@ static int remove_mapping(BDRVVVFATState* s, int mapping_index)
|
|||||||
mapping_t* first_mapping = array_get(&(s->mapping), 0);
|
mapping_t* first_mapping = array_get(&(s->mapping), 0);
|
||||||
|
|
||||||
/* free mapping */
|
/* free mapping */
|
||||||
if (mapping->first_mapping_index < 0)
|
if (mapping->first_mapping_index < 0) {
|
||||||
free(mapping->path);
|
g_free(mapping->path);
|
||||||
|
}
|
||||||
|
|
||||||
/* remove from s->mapping */
|
/* remove from s->mapping */
|
||||||
array_remove(&(s->mapping), mapping_index);
|
array_remove(&(s->mapping), mapping_index);
|
||||||
@ -2232,11 +2182,15 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
|
||||||
strerror(errno), errno);
|
strerror(errno), errno);
|
||||||
|
g_free(cluster);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
if (offset > 0)
|
if (offset > 0) {
|
||||||
if (lseek(fd, offset, SEEK_SET) != offset)
|
if (lseek(fd, offset, SEEK_SET) != offset) {
|
||||||
return -3;
|
g_free(cluster);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (offset < size) {
|
while (offset < size) {
|
||||||
uint32_t c1;
|
uint32_t c1;
|
||||||
@ -2252,11 +2206,15 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
ret = vvfat_read(s->bs, cluster2sector(s, c),
|
ret = vvfat_read(s->bs, cluster2sector(s, c),
|
||||||
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
|
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return ret;
|
g_free(cluster);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (write(fd, cluster, rest_size) < 0)
|
if (write(fd, cluster, rest_size) < 0) {
|
||||||
return -2;
|
g_free(cluster);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
offset += rest_size;
|
offset += rest_size;
|
||||||
c = c1;
|
c = c1;
|
||||||
@ -2265,9 +2223,11 @@ static int commit_one_file(BDRVVVFATState* s,
|
|||||||
if (ftruncate(fd, size)) {
|
if (ftruncate(fd, size)) {
|
||||||
perror("ftruncate()");
|
perror("ftruncate()");
|
||||||
close(fd);
|
close(fd);
|
||||||
|
g_free(cluster);
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
g_free(cluster);
|
||||||
|
|
||||||
return commit_mappings(s, first_cluster, dir_index);
|
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);
|
array_remove(&(s->commits), i);
|
||||||
continue;
|
continue;
|
||||||
} else if (commit->action == ACTION_MKDIR) {
|
} 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) {
|
static void write_target_close(BlockDriverState *bs) {
|
||||||
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
|
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
|
||||||
bdrv_delete(s->qcow);
|
bdrv_delete(s->qcow);
|
||||||
free(s->qcow_filename);
|
g_free(s->qcow_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriver vvfat_write_target = {
|
static BlockDriver vvfat_write_target = {
|
||||||
@ -2836,8 +2796,7 @@ static void vvfat_close(BlockDriverState *bs)
|
|||||||
array_free(&(s->fat));
|
array_free(&(s->fat));
|
||||||
array_free(&(s->directory));
|
array_free(&(s->directory));
|
||||||
array_free(&(s->mapping));
|
array_free(&(s->mapping));
|
||||||
if(s->cluster_buffer)
|
g_free(s->cluster_buffer);
|
||||||
free(s->cluster_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BlockDriver bdrv_vvfat = {
|
static BlockDriver bdrv_vvfat = {
|
||||||
@ -2878,11 +2837,5 @@ static void checkpoint(void) {
|
|||||||
direntry = array_get(&(vvv->directory), mapping->dir_index);
|
direntry = array_get(&(vvv->directory), mapping->dir_index);
|
||||||
assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
|
assert(!memcmp(direntry->name, "USB H ", 11) || direntry->name[0]==0);
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
/* avoid compiler warnings: */
|
|
||||||
hexdump(NULL, 100);
|
|
||||||
remove_mapping(vvv, 0);
|
|
||||||
print_mapping(NULL);
|
|
||||||
print_direntry(NULL);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -199,6 +199,7 @@ struct BlockDriverState {
|
|||||||
drivers. They are not used by the block driver */
|
drivers. They are not used by the block driver */
|
||||||
int cyls, heads, secs, translation;
|
int cyls, heads, secs, translation;
|
||||||
BlockErrorAction on_read_error, on_write_error;
|
BlockErrorAction on_read_error, on_write_error;
|
||||||
|
BlockIOStatus iostatus;
|
||||||
char device_name[32];
|
char device_name[32];
|
||||||
unsigned long *dirty_bitmap;
|
unsigned long *dirty_bitmap;
|
||||||
int64_t dirty_count;
|
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;
|
s->bus->error_status = op;
|
||||||
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
|
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
|
||||||
vm_stop(RUN_STATE_IO_ERROR);
|
vm_stop(RUN_STATE_IO_ERROR);
|
||||||
|
bdrv_iostatus_set_err(s->bs, error);
|
||||||
} else {
|
} else {
|
||||||
if (op & BM_STATUS_DMA_RETRY) {
|
if (op & BM_STATUS_DMA_RETRY) {
|
||||||
dma_buf_commit(s, 0);
|
dma_buf_commit(s, 0);
|
||||||
@ -1873,6 +1874,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ide_reset(s);
|
ide_reset(s);
|
||||||
|
bdrv_iostatus_enable(bs);
|
||||||
return 0;
|
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);
|
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
|
||||||
vm_stop(RUN_STATE_IO_ERROR);
|
vm_stop(RUN_STATE_IO_ERROR);
|
||||||
|
bdrv_iostatus_set_err(s->bs, error);
|
||||||
} else {
|
} else {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case ENOMEM:
|
case ENOMEM:
|
||||||
@ -1260,6 +1261,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
|
|||||||
|
|
||||||
s->qdev.type = scsi_type;
|
s->qdev.type = scsi_type;
|
||||||
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
|
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");
|
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
|
|||||||
s->rq = req;
|
s->rq = req;
|
||||||
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
|
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
|
||||||
vm_stop(RUN_STATE_IO_ERROR);
|
vm_stop(RUN_STATE_IO_ERROR);
|
||||||
|
bdrv_iostatus_set_err(s->bs, error);
|
||||||
} else {
|
} else {
|
||||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||||
bdrv_acct_done(s->bs, &req->acct);
|
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_dev_ops(s->bs, &virtio_block_ops, s);
|
||||||
bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
|
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");
|
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
|
||||||
|
|
||||||
return &s->vdev;
|
return &s->vdev;
|
||||||
|
21
linux-aio.c
21
linux-aio.c
@ -31,6 +31,8 @@ struct qemu_laiocb {
|
|||||||
struct iocb iocb;
|
struct iocb iocb;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
QEMUIOVector *qiov;
|
||||||
|
bool is_read;
|
||||||
QLIST_ENTRY(qemu_laiocb) node;
|
QLIST_ENTRY(qemu_laiocb) node;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,10 +59,17 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
|
|||||||
|
|
||||||
ret = laiocb->ret;
|
ret = laiocb->ret;
|
||||||
if (ret != -ECANCELED) {
|
if (ret != -ECANCELED) {
|
||||||
if (ret == laiocb->nbytes)
|
if (ret == laiocb->nbytes) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else if (ret >= 0)
|
} else if (ret >= 0) {
|
||||||
ret = -EINVAL;
|
/* 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);
|
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->nbytes = nb_sectors * 512;
|
||||||
laiocb->ctx = s;
|
laiocb->ctx = s;
|
||||||
laiocb->ret = -EINPROGRESS;
|
laiocb->ret = -EINPROGRESS;
|
||||||
|
laiocb->is_read = (type == QEMU_AIO_READ);
|
||||||
|
laiocb->qiov = qiov;
|
||||||
|
|
||||||
iocbs = &laiocb->iocb;
|
iocbs = &laiocb->iocb;
|
||||||
|
|
||||||
@ -185,10 +196,10 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
goto out_dec_count;
|
goto out_dec_count;
|
||||||
return &laiocb->common;
|
return &laiocb->common;
|
||||||
|
|
||||||
out_free_aiocb:
|
|
||||||
qemu_aio_release(laiocb);
|
|
||||||
out_dec_count:
|
out_dec_count:
|
||||||
s->count--;
|
s->count--;
|
||||||
|
out_free_aiocb:
|
||||||
|
qemu_aio_release(laiocb);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,6 +1221,11 @@ struct bdrv_iterate_context {
|
|||||||
int err;
|
int err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
bdrv_iostatus_reset(bs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* do_cont(): Resume emulation.
|
* do_cont(): Resume emulation.
|
||||||
*/
|
*/
|
||||||
@ -1237,6 +1242,7 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bdrv_iterate(iostatus_bdrv_it, NULL);
|
||||||
bdrv_iterate(encrypted_bdrv_it, &context);
|
bdrv_iterate(encrypted_bdrv_it, &context);
|
||||||
/* only resume the vm if all keys are set and valid */
|
/* only resume the vm if all keys are set and valid */
|
||||||
if (!context.err) {
|
if (!context.err) {
|
||||||
|
@ -1154,6 +1154,10 @@ Each json-object contain the following:
|
|||||||
"tftp", "vdi", "vmdk", "vpc", "vvfat"
|
"tftp", "vdi", "vmdk", "vpc", "vvfat"
|
||||||
- "backing_file": backing file name (json-string, optional)
|
- "backing_file": backing file name (json-string, optional)
|
||||||
- "encrypted": true if encrypted, false otherwise (json-bool)
|
- "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:
|
Example:
|
||||||
|
|
||||||
@ -1161,6 +1165,7 @@ Example:
|
|||||||
<- {
|
<- {
|
||||||
"return":[
|
"return":[
|
||||||
{
|
{
|
||||||
|
"io-status": "ok",
|
||||||
"device":"ide0-hd0",
|
"device":"ide0-hd0",
|
||||||
"locked":false,
|
"locked":false,
|
||||||
"removable":false,
|
"removable":false,
|
||||||
@ -1173,6 +1178,7 @@ Example:
|
|||||||
"type":"unknown"
|
"type":"unknown"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"io-status": "ok",
|
||||||
"device":"ide1-cd0",
|
"device":"ide1-cd0",
|
||||||
"locked":false,
|
"locked":false,
|
||||||
"removable":true,
|
"removable":true,
|
||||||
|
Loading…
Reference in New Issue
Block a user