raw-win32: add emulated AIO support
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9f8540ecef
commit
fc4edb84bf
|
@ -25,6 +25,10 @@
|
||||||
#include "qemu-timer.h"
|
#include "qemu-timer.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "raw-aio.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "thread-pool.h"
|
||||||
|
#include "iov.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
|
@ -32,12 +36,127 @@
|
||||||
#define FTYPE_CD 1
|
#define FTYPE_CD 1
|
||||||
#define FTYPE_HARDDISK 2
|
#define FTYPE_HARDDISK 2
|
||||||
|
|
||||||
|
typedef struct RawWin32AIOData {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
HANDLE hfile;
|
||||||
|
struct iovec *aio_iov;
|
||||||
|
int aio_niov;
|
||||||
|
size_t aio_nbytes;
|
||||||
|
off64_t aio_offset;
|
||||||
|
int aio_type;
|
||||||
|
} RawWin32AIOData;
|
||||||
|
|
||||||
typedef struct BDRVRawState {
|
typedef struct BDRVRawState {
|
||||||
HANDLE hfile;
|
HANDLE hfile;
|
||||||
int type;
|
int type;
|
||||||
char drive_path[16]; /* format: "d:\" */
|
char drive_path[16]; /* format: "d:\" */
|
||||||
} BDRVRawState;
|
} BDRVRawState;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read/writes the data to/from a given linear buffer.
|
||||||
|
*
|
||||||
|
* Returns the number of bytes handles or -errno in case of an error. Short
|
||||||
|
* reads are only returned if the end of the file is reached.
|
||||||
|
*/
|
||||||
|
static size_t handle_aiocb_rw(RawWin32AIOData *aiocb)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < aiocb->aio_niov; i++) {
|
||||||
|
OVERLAPPED ov;
|
||||||
|
DWORD ret, ret_count, len;
|
||||||
|
|
||||||
|
memset(&ov, 0, sizeof(ov));
|
||||||
|
ov.Offset = (aiocb->aio_offset + offset);
|
||||||
|
ov.OffsetHigh = (aiocb->aio_offset + offset) >> 32;
|
||||||
|
len = aiocb->aio_iov[i].iov_len;
|
||||||
|
if (aiocb->aio_type & QEMU_AIO_WRITE) {
|
||||||
|
ret = WriteFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
|
||||||
|
len, &ret_count, &ov);
|
||||||
|
} else {
|
||||||
|
ret = ReadFile(aiocb->hfile, aiocb->aio_iov[i].iov_base,
|
||||||
|
len, &ret_count, &ov);
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
ret_count = 0;
|
||||||
|
}
|
||||||
|
if (ret_count != len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aio_worker(void *arg)
|
||||||
|
{
|
||||||
|
RawWin32AIOData *aiocb = arg;
|
||||||
|
ssize_t ret = 0;
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
|
||||||
|
case QEMU_AIO_READ:
|
||||||
|
count = handle_aiocb_rw(aiocb);
|
||||||
|
if (count < aiocb->aio_nbytes && aiocb->bs->growable) {
|
||||||
|
/* A short read means that we have reached EOF. Pad the buffer
|
||||||
|
* with zeros for bytes after EOF. */
|
||||||
|
iov_memset(aiocb->aio_iov, aiocb->aio_niov, count,
|
||||||
|
0, aiocb->aio_nbytes - count);
|
||||||
|
|
||||||
|
count = aiocb->aio_nbytes;
|
||||||
|
}
|
||||||
|
if (count == aiocb->aio_nbytes) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QEMU_AIO_WRITE:
|
||||||
|
count = handle_aiocb_rw(aiocb);
|
||||||
|
if (count == aiocb->aio_nbytes) {
|
||||||
|
count = 0;
|
||||||
|
} else {
|
||||||
|
count = -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QEMU_AIO_FLUSH:
|
||||||
|
if (!FlushFileBuffers(aiocb->hfile)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slice_free(RawWin32AIOData, aiocb);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
|
||||||
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||||
|
{
|
||||||
|
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
|
||||||
|
|
||||||
|
acb->bs = bs;
|
||||||
|
acb->hfile = hfile;
|
||||||
|
acb->aio_type = type;
|
||||||
|
|
||||||
|
if (qiov) {
|
||||||
|
acb->aio_iov = qiov->iov;
|
||||||
|
acb->aio_niov = qiov->niov;
|
||||||
|
}
|
||||||
|
acb->aio_nbytes = nb_sectors * 512;
|
||||||
|
acb->aio_offset = sector_num * 512;
|
||||||
|
|
||||||
|
trace_paio_submit(acb, opaque, sector_num, nb_sectors, type);
|
||||||
|
return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
int qemu_ftruncate64(int fd, int64_t length)
|
int qemu_ftruncate64(int fd, int64_t length)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER li;
|
LARGE_INTEGER li;
|
||||||
|
@ -117,59 +236,29 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_read(BlockDriverState *bs, int64_t sector_num,
|
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||||
uint8_t *buf, int nb_sectors)
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
OVERLAPPED ov;
|
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
|
||||||
DWORD ret_count;
|
cb, opaque, QEMU_AIO_READ);
|
||||||
int ret;
|
|
||||||
int64_t offset = sector_num * 512;
|
|
||||||
int count = nb_sectors * 512;
|
|
||||||
|
|
||||||
memset(&ov, 0, sizeof(ov));
|
|
||||||
ov.Offset = offset;
|
|
||||||
ov.OffsetHigh = offset >> 32;
|
|
||||||
ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
|
|
||||||
if (!ret)
|
|
||||||
return ret_count;
|
|
||||||
if (ret_count == count)
|
|
||||||
ret_count = 0;
|
|
||||||
return ret_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_write(BlockDriverState *bs, int64_t sector_num,
|
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||||
const uint8_t *buf, int nb_sectors)
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
OVERLAPPED ov;
|
return paio_submit(bs, s->hfile, sector_num, qiov, nb_sectors,
|
||||||
DWORD ret_count;
|
cb, opaque, QEMU_AIO_WRITE);
|
||||||
int ret;
|
|
||||||
int64_t offset = sector_num * 512;
|
|
||||||
int count = nb_sectors * 512;
|
|
||||||
|
|
||||||
memset(&ov, 0, sizeof(ov));
|
|
||||||
ov.Offset = offset;
|
|
||||||
ov.OffsetHigh = offset >> 32;
|
|
||||||
ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
|
|
||||||
if (!ret)
|
|
||||||
return ret_count;
|
|
||||||
if (ret_count == count)
|
|
||||||
ret_count = 0;
|
|
||||||
return ret_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int raw_flush(BlockDriverState *bs)
|
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||||
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
int ret;
|
return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
|
||||||
|
|
||||||
ret = FlushFileBuffers(s->hfile);
|
|
||||||
if (ret == 0) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raw_close(BlockDriverState *bs)
|
static void raw_close(BlockDriverState *bs)
|
||||||
|
@ -290,9 +379,9 @@ static BlockDriver bdrv_file = {
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_create = raw_create,
|
.bdrv_create = raw_create,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_write = raw_write,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_co_flush_to_disk = raw_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
|
@ -413,9 +502,9 @@ static BlockDriver bdrv_host_device = {
|
||||||
.bdrv_close = raw_close,
|
.bdrv_close = raw_close,
|
||||||
.bdrv_has_zero_init = hdev_has_zero_init,
|
.bdrv_has_zero_init = hdev_has_zero_init,
|
||||||
|
|
||||||
.bdrv_read = raw_read,
|
.bdrv_aio_readv = raw_aio_readv,
|
||||||
.bdrv_write = raw_write,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_co_flush_to_disk = raw_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
|
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
.bdrv_get_allocated_file_size
|
.bdrv_get_allocated_file_size
|
||||||
|
|
Loading…
Reference in New Issue