Commit 83f64091 authored by bellard's avatar bellard
Browse files

async file I/O API


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2075 c046a42c-6fe2-441c-8c8c-71466251a162
parent 7954c734
version 0.8.3:
- Support for relative paths in backing files for disk images
- Async file I/O API
version 0.8.2:
- ACPI support
......
......@@ -25,14 +25,22 @@ else
DOCS=
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
LIBS+=-lrt
endif
endif
endif
all: $(TOOLS) $(DOCS) recurse-all
subdir-%: dyngen$(EXESUF)
$(MAKE) -C $(subst subdir-,,$@) all
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
qemu-img$(EXESUF): qemu-img.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
dyngen$(EXESUF): dyngen.c
......
......@@ -289,7 +289,8 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o
VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o
VL_OBJS+=block.o block-raw.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
ifdef CONFIG_WIN32
VL_OBJS+=tap-win32.o
......
......@@ -85,15 +85,15 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int bochs_open(BlockDriverState *bs, const char *filename)
static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVBochsState *s = bs->opaque;
int fd, i;
struct bochs_header bochs;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDWR | O_BINARY);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
}
......
......@@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cloop_open(BlockDriverState *bs, const char *filename)
static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCloopState *s = bs->opaque;
uint32_t offsets_size,max_compressed_block_size=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
s->fd = open(filename, O_RDONLY | O_BINARY);
if (s->fd < 0)
return -1;
return -errno;
bs->read_only = 1;
/* read header */
......
......@@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int cow_open(BlockDriverState *bs, const char *filename)
static int cow_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVCowState *s = bs->opaque;
int fd;
......@@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs, const char *filename)
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
#if 0
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
#endif
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
......@@ -179,8 +163,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num,
if (ret != n * 512)
return -1;
} else {
if (bs->backing_hd) {
/* read from the base image */
ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
if (ret < 0)
return -1;
} else {
memset(buf, 0, n * 512);
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
......@@ -220,7 +211,7 @@ static int cow_create(const char *filename, int64_t image_sectors,
if (flags)
return -ENOTSUP;
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
if (cow_fd < 0)
return -1;
......@@ -228,18 +219,23 @@ static int cow_create(const char *filename, int64_t image_sectors,
cow_header.magic = cpu_to_be32(COW_MAGIC);
cow_header.version = cpu_to_be32(COW_VERSION);
if (image_filename) {
/* Note: if no file, we put a dummy mtime */
cow_header.mtime = cpu_to_be32(0);
fd = open(image_filename, O_RDONLY | O_BINARY);
if (fd < 0) {
close(cow_fd);
return -1;
goto mtime_fail;
}
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
goto mtime_fail;
}
close(fd);
cow_header.mtime = cpu_to_be32(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
mtime_fail:
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
image_filename);
}
cow_header.sectorsize = cpu_to_be32(512);
cow_header.size = cpu_to_be64(image_sectors * 512);
......
......@@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
return be32_to_cpu(buffer);
}
static int dmg_open(BlockDriverState *bs, const char *filename)
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVDMGState *s = bs->opaque;
off_t info_begin,info_end,last_in_offset,last_out_offset;
uint32_t count;
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
s->fd = open(filename, O_RDONLY | O_BINARY);
if (s->fd < 0)
return -1;
return -errno;
bs->read_only = 1;
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
......@@ -93,7 +93,7 @@ dmg_close:
close(s->fd);
/* open raw instead */
bs->drv=&bdrv_raw;
return bs->drv->bdrv_open(bs,filename);
return bs->drv->bdrv_open(bs, filename, flags);
}
info_begin=read_off(s->fd);
if(info_begin==0)
......
This diff is collapsed.
This diff is collapsed.
......@@ -89,7 +89,7 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vmdk_open(BlockDriverState *bs, const char *filename)
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVmdkState *s = bs->opaque;
int fd, i;
......
......@@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0;
}
static int vpc_open(BlockDriverState *bs, const char *filename)
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVPCState *s = bs->opaque;
int fd, i;
struct vpc_subheader header;
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0)
return -1;
}
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
bs->read_only = 1; // no write support yet
s->fd = fd;
......
......@@ -351,13 +351,6 @@ typedef struct BDRVVVFATState {
} BDRVVVFATState;
static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (strstart(filename, "fat:", NULL))
return 100;
return 0;
}
static void init_mbr(BDRVVVFATState* s)
{
/* TODO: if the files mbr.img and bootsect.img exist, use them */
......@@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATState* s,
return 0;
}
#ifdef DEBUG
static BDRVVVFATState *vvv = NULL;
#endif
static int enable_write_target(BDRVVVFATState *s);
static int is_consistent(BDRVVVFATState *s);
static int vvfat_open(BlockDriverState *bs, const char* dirname)
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
{
BDRVVVFATState *s = bs->opaque;
int floppy = 0;
int i;
#ifdef DEBUG
vvv = s;
#endif
DLOG(if (stderr == NULL) {
stderr = fopen("vvfat.log", "a");
......@@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) {
bs->heads = bs->cyls = bs->secs = 0;
// assert(is_consistent(s));
return 0;
}
......@@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFATState *s)
array_init(&(s->commits), sizeof(commit_t));
s->qcow_filename = malloc(1024);
strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
get_tmp_filename(s->qcow_filename, 1024);
if (bdrv_create(&bdrv_qcow,
s->qcow_filename, s->sector_count, "fat:", 0) < 0)
return -1;
......@@ -2767,14 +2762,15 @@ static void vvfat_close(BlockDriverState *bs)
BlockDriver bdrv_vvfat = {
"vvfat",
sizeof(BDRVVVFATState),
vvfat_probe,
NULL, /* no probe for protocols */
vvfat_open,
vvfat_read,
vvfat_write,
vvfat_close,
NULL, /* ??? Not sure if we can do any meaningful flushing. */
NULL,
vvfat_is_allocated
vvfat_is_allocated,
.protocol_name = "fat",
};
#ifdef DEBUG
......
This diff is collapsed.
......@@ -28,7 +28,7 @@ struct BlockDriver {
const char *format_name;
int instance_size;
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename);
int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
......@@ -41,11 +41,28 @@ struct BlockDriver {
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
/* aio */
int (*bdrv_aio_new)(BlockDriverAIOCB *acb);
int (*bdrv_aio_read)(BlockDriverAIOCB *acb, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int (*bdrv_aio_write)(BlockDriverAIOCB *acb, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
void (*bdrv_aio_delete)(BlockDriverAIOCB *acb);
const char *protocol_name;
int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
uint8_t *buf, int count);
int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
const uint8_t *buf, int count);
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
struct BlockDriver *next;
};
struct BlockDriverState {
int64_t total_sectors;
int64_t total_sectors; /* XXX: will be suppressed */
int read_only; /* if true, the media is read only */
int inserted; /* if true, the media is present */
int removable; /* if true, the media can be removed */
......@@ -67,6 +84,9 @@ struct BlockDriverState {
int is_temporary;
BlockDriverState *backing_hd;
/* sync read/write emulation */
BlockDriverAIOCB *sync_aiocb;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
......@@ -76,6 +96,14 @@ struct BlockDriverState {
BlockDriverState *next;
};
struct BlockDriverAIOCB {
BlockDriverState *bs;
BlockDriverCompletionFunc *cb;
void *cb_opaque;
void *opaque; /* driver opaque */
};
void get_tmp_filename(char *filename, int size);
#endif /* BLOCK_INT_H */
......@@ -4771,6 +4771,77 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
struct QEMUBH {
QEMUBHFunc *cb;
void *opaque;
int scheduled;
QEMUBH *next;
};
static QEMUBH *first_bh = NULL;
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
{
QEMUBH *bh;
bh = qemu_mallocz(sizeof(QEMUBH));
if (!bh)
return NULL;
bh->cb = cb;
bh->opaque = opaque;
return bh;
}
void qemu_bh_poll(void)
{
QEMUBH *bh, **pbh;
for(;;) {
pbh = &first_bh;
bh = *pbh;
if (!bh)
break;
*pbh = bh->next;
bh->scheduled = 0;
bh->cb(bh->opaque);
}
}
void qemu_bh_schedule(QEMUBH *bh)
{
CPUState *env = cpu_single_env;
if (bh->scheduled)
return;
bh->scheduled = 1;
bh->next = first_bh;
first_bh = bh;
/* stop the currently executing CPU to execute the BH ASAP */
if (env) {
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
}
}
void qemu_bh_cancel(QEMUBH *bh)
{
QEMUBH **pbh;
if (bh->scheduled) {
pbh = &first_bh;
while (*pbh != bh)
pbh = &(*pbh)->next;
*pbh = bh->next;
bh->scheduled = 0;
}
}
void qemu_bh_delete(QEMUBH *bh)
{
qemu_bh_cancel(bh);
qemu_free(bh);
}
/***********************************************************/
/* machine registration */
......@@ -5030,6 +5101,8 @@ void main_loop_wait(int timeout)
#ifdef _WIN32
tap_win32_poll();
#endif
qemu_aio_poll();
qemu_bh_poll();
if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
......@@ -6049,6 +6122,7 @@ int main(int argc, char **argv)
init_timers();
init_timer_alarm();
qemu_aio_init();
#ifdef _WIN32
socket_init();
......@@ -6093,7 +6167,7 @@ int main(int argc, char **argv)
snprintf(buf, sizeof(buf), "hd%c", i + 'a');
bs_table[i] = bdrv_new(buf);
}
if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) {
if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
hd_filename[i]);
exit(1);
......@@ -6118,7 +6192,8 @@ int main(int argc, char **argv)
bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
}
if (fd_filename[i] != '\0') {
if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) {
if (bdrv_open(fd_table[i], fd_filename[i],
snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",
fd_filename[i]);
exit(1);
......
......@@ -481,6 +481,16 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
void cpu_save(QEMUFile *f, void *opaque);
int cpu_load(QEMUFile *f, void *opaque, int version_id);
/* bottom halves */
typedef struct QEMUBH QEMUBH;
typedef void QEMUBHFunc(void *opaque);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule(QEMUBH *bh);
void qemu_bh_cancel(QEMUBH *bh);
void qemu_bh_delete(QEMUBH *bh);
void qemu_bh_poll(void);
/* block.c */
typedef struct BlockDriverState BlockDriverState;
typedef struct BlockDriver BlockDriver;
......@@ -495,6 +505,16 @@ extern BlockDriver bdrv_bochs;
extern BlockDriver bdrv_vpc;
extern BlockDriver bdrv_vvfat;
#define BDRV_O_RDONLY 0x0000
#define BDRV_O_RDWR 0x0002
#define BDRV_O_ACCESS 0x0003
#define BDRV_O_CREAT 0x0004 /* create an empty file */
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to
use a disk image format on top of
it (default for
bdrv_file_open()) */
void bdrv_init(void);
BlockDriver *bdrv_find_format(const char *format_name);
int bdrv_create(BlockDriver *drv,
......@@ -502,17 +522,44 @@ int bdrv_create(BlockDriver *drv,
const char *backing_file, int flags);
BlockDriverState *bdrv_new(const char *device_name);
void bdrv_delete(BlockDriverState *bs);
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot);
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
void bdrv_close(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count);
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
int bdrv_commit(BlockDriverState *bs);
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
/* async block I/O */
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
BlockDriverAIOCB *bdrv_aio_new(BlockDriverState *bs);
int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num,
uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
int bdrv_aio_write(BlockDriverAIOCB *acb, int64_t sector_num,
const uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
void bdrv_aio_delete(BlockDriverAIOCB *acb);
void qemu_aio_init(void);
void qemu_aio_poll(void);
void qemu_aio_wait_start(void);
void qemu_aio_wait(void);
void qemu_aio_wait_end(void);
/* Ensure contents are flushed to disk. */
void bdrv_flush(BlockDriverState *bs);
......@@ -551,6 +598,13 @@ const char *bdrv_get_device_name(BlockDriverState *bs);
int qcow_get_cluster_size(BlockDriverState *bs);
int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf);
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size);
int path_is_absolute(const char *path);
void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename);
#ifndef QEMU_TOOL
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment