X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=block.c;h=c80d4b90ce9976b8cc6366255099b5140dc9a5f3;hb=388f60b1cff919c2627e6cb5c0cbbeeb42130e19;hp=32503271c74402ce5316f28d5f464ff9954979a1;hpb=42fb2807d9886e485652e7512398b9d5a83bd768;p=qemu diff --git a/block.c b/block.c index 3250327..c80d4b9 100644 --- a/block.c +++ b/block.c @@ -22,21 +22,28 @@ * THE SOFTWARE. */ #include "config-host.h" -#ifdef _BSD +#ifdef HOST_BSD /* include native header before sys-queue.h */ #include #endif #include "qemu-common.h" -#include "console.h" +#include "monitor.h" #include "block_int.h" +#include "module.h" -#ifdef _BSD +#ifdef HOST_BSD #include #include #include +#ifndef __DragonFly__ #include #endif +#endif + +#ifdef _WIN32 +#include +#endif #define SECTOR_BITS 9 #define SECTOR_SIZE (1 << SECTOR_BITS) @@ -45,13 +52,17 @@ typedef struct BlockDriverAIOCBSync { BlockDriverAIOCB common; QEMUBH *bh; int ret; + /* vector translation state */ + QEMUIOVector *qiov; + uint8_t *bounce; + int is_write; } BlockDriverAIOCBSync; -static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors, +static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); -static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, - int64_t sector_num, const uint8_t *buf, int nb_sectors, +static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb); static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, @@ -128,19 +139,20 @@ void path_combine(char *dest, int dest_size, } -static void bdrv_register(BlockDriver *bdrv) +void bdrv_register(BlockDriver *bdrv) { - if (!bdrv->bdrv_aio_read) { + if (!bdrv->bdrv_aio_readv) { /* add AIO emulation layer */ - bdrv->bdrv_aio_read = bdrv_aio_read_em; - bdrv->bdrv_aio_write = bdrv_aio_write_em; + bdrv->bdrv_aio_readv = bdrv_aio_readv_em; + bdrv->bdrv_aio_writev = bdrv_aio_writev_em; bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em; bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync); - } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) { + } else if (!bdrv->bdrv_read) { /* add synchronous IO emulation layer */ bdrv->bdrv_read = bdrv_read_em; bdrv->bdrv_write = bdrv_write_em; } + aio_pool_init(&bdrv->aio_pool, bdrv->aiocb_size, bdrv->bdrv_aio_cancel); bdrv->next = first_drv; first_drv = bdrv; } @@ -151,8 +163,6 @@ BlockDriverState *bdrv_new(const char *device_name) BlockDriverState **pbs, *bs; bs = qemu_mallocz(sizeof(BlockDriverState)); - if(!bs) - return NULL; pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); if (device_name[0] != '\0') { /* insert at the end */ @@ -174,13 +184,49 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } -int bdrv_create(BlockDriver *drv, +int bdrv_create2(BlockDriver *drv, const char *filename, int64_t size_in_sectors, - const char *backing_file, int flags) + const char *backing_file, const char *backing_format, + int flags) +{ + QEMUOptionParameter *options; + + options = parse_option_parameters("", drv->create_options, NULL); + + // Process flags + if (flags & ~(BLOCK_FLAG_ENCRYPT | BLOCK_FLAG_COMPAT6 | BLOCK_FLAG_COMPRESS)) { + return -ENOTSUP; + } + + if (flags & BLOCK_FLAG_ENCRYPT) { + set_option_parameter_int(options, BLOCK_OPT_ENCRYPT, 1); + } + if (flags & BLOCK_FLAG_COMPAT6) { + set_option_parameter_int(options, BLOCK_OPT_COMPAT6, 1); + } + + // Add size to options + set_option_parameter_int(options, BLOCK_OPT_SIZE, size_in_sectors * 512); + + // Backing files + if ((backing_file != NULL && set_option_parameter(options, + BLOCK_OPT_BACKING_FILE, backing_file)) + || (backing_format != NULL && set_option_parameter(options, + BLOCK_OPT_BACKING_FMT, backing_format))) + { + return -ENOTSUP; + } + + return bdrv_create(drv, filename, options); +} + +int bdrv_create(BlockDriver *drv, const char* filename, + QEMUOptionParameter *options) { if (!drv->bdrv_create) return -ENOTSUP; - return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); + + return drv->bdrv_create(filename, options); } #ifdef _WIN32 @@ -236,11 +282,11 @@ static BlockDriver *find_protocol(const char *filename) #ifdef _WIN32 if (is_windows_drive(filename) || is_windows_drive_prefix(filename)) - return &bdrv_raw; + return bdrv_find_format("raw"); #endif p = strchr(filename, ':'); if (!p) - return &bdrv_raw; + return bdrv_find_format("raw"); len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; @@ -266,23 +312,23 @@ static BlockDriver *find_image_format(const char *filename) /* detect host devices. By convention, /dev/cdrom[N] is always recognized as a host CDROM */ if (strstart(filename, "/dev/cdrom", NULL)) - return &bdrv_host_device; + return bdrv_find_format("host_device"); #ifdef _WIN32 if (is_windows_drive(filename)) - return &bdrv_host_device; + return bdrv_find_format("host_device"); #else { struct stat st; if (stat(filename, &st) >= 0 && (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { - return &bdrv_host_device; + return bdrv_find_format("host_device"); } } #endif drv = find_protocol(filename); /* no need to test disk image formats for vvfat */ - if (drv == &bdrv_vvfat) + if (drv && strcmp(drv->format_name, "vvfat") == 0) return drv; ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); @@ -313,13 +359,12 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) int ret; bs = bdrv_new(""); - if (!bs) - return -ENOMEM; ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL); if (ret < 0) { bdrv_delete(bs); return ret; } + bs->growable = 1; *pbs = bs; return 0; } @@ -339,6 +384,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; + bs->valid_key = 0; + /* buffer_alignment defaulted to 512, drivers can change this value */ + bs->buffer_alignment = 512; if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; @@ -350,12 +398,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, /* if there is a backing file, use it */ bs1 = bdrv_new(""); - if (!bs1) { - return -ENOMEM; - } - if (bdrv_open(bs1, filename, 0) < 0) { + ret = bdrv_open2(bs1, filename, 0, drv); + if (ret < 0) { bdrv_delete(bs1); - return -1; + return ret; } total_size = bdrv_getlength(bs1) >> SECTOR_BITS; @@ -373,30 +419,29 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, else realpath(filename, backing_filename); - if (bdrv_create(&bdrv_qcow2, tmp_filename, - total_size, backing_filename, 0) < 0) { - return -1; + ret = bdrv_create2(bdrv_find_format("qcow2"), tmp_filename, + total_size, backing_filename, + (drv ? drv->format_name : NULL), 0); + if (ret < 0) { + return ret; } filename = tmp_filename; + drv = bdrv_find_format("qcow2"); bs->is_temporary = 1; } pstrcpy(bs->filename, sizeof(bs->filename), filename); if (flags & BDRV_O_FILE) { drv = find_protocol(filename); - if (!drv) - return -ENOENT; - } else { - if (!drv) { - drv = find_image_format(filename); - if (!drv) - return -1; - } + } else if (!drv) { + drv = find_image_format(filename); + } + if (!drv) { + ret = -ENOENT; + goto unlink_and_fail; } bs->drv = drv; bs->opaque = qemu_mallocz(drv->instance_size); - if (bs->opaque == NULL && drv->instance_size > 0) - return -1; /* Note: for compatibility, we open disk image files as RDWR, and RDONLY as fallback */ if (!(flags & BDRV_O_FILE)) @@ -412,6 +457,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, qemu_free(bs->opaque); bs->opaque = NULL; bs->drv = NULL; + unlink_and_fail: + if (bs->is_temporary) + unlink(filename); return ret; } if (drv->bdrv_getlength) { @@ -424,23 +472,26 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, #endif if (bs->backing_file[0] != '\0') { /* if there is a backing file, use it */ + BlockDriver *back_drv = NULL; bs->backing_hd = bdrv_new(""); - if (!bs->backing_hd) { - fail: - bdrv_close(bs); - return -ENOMEM; - } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) - goto fail; + if (bs->backing_format[0] != '\0') + back_drv = bdrv_find_format(bs->backing_format); + ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags, + back_drv); + if (ret < 0) { + bdrv_close(bs); + return ret; + } } - /* call the change callback */ - bs->media_changed = 1; - if (bs->change_cb) - bs->change_cb(bs->change_opaque); - + if (!bdrv_key_required(bs)) { + /* call the change callback */ + bs->media_changed = 1; + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + } return 0; } @@ -480,6 +531,20 @@ void bdrv_delete(BlockDriverState *bs) qemu_free(bs); } +/* + * Run consistency checks on an image + * + * Returns the number of errors or -errno when an internal error occurs + */ +int bdrv_check(BlockDriverState *bs) +{ + if (bs->drv->bdrv_check == NULL) { + return -ENOTSUP; + } + + return bs->drv->bdrv_check(bs); +} + /* commit COW file into the raw image */ int bdrv_commit(BlockDriverState *bs) { @@ -523,6 +588,34 @@ int bdrv_commit(BlockDriverState *bs) return 0; } +static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset, + size_t size) +{ + int64_t len; + + if (!bdrv_is_inserted(bs)) + return -ENOMEDIUM; + + if (bs->growable) + return 0; + + len = bdrv_getlength(bs); + + if (offset < 0) + return -EIO; + + if ((offset > len) || (len - offset < size)) + return -EIO; + + return 0; +} + +static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num, + int nb_sectors) +{ + return bdrv_check_byte_request(bs, sector_num * 512, nb_sectors * 512); +} + /* 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) @@ -531,23 +624,10 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, if (!drv) return -ENOMEDIUM; + if (bdrv_check_request(bs, sector_num, nb_sectors)) + return -EIO; - if (drv->bdrv_pread) { - int ret, len; - len = nb_sectors * 512; - ret = drv->bdrv_pread(bs, sector_num * 512, buf, len); - if (ret < 0) - return ret; - else if (ret != len) - return -EINVAL; - else { - bs->rd_bytes += (unsigned) len; - bs->rd_ops ++; - return 0; - } - } else { - return drv->bdrv_read(bs, sector_num, buf, nb_sectors); - } + return drv->bdrv_read(bs, sector_num, buf, nb_sectors); } /* Return < 0 if error. Important errors are: @@ -564,27 +644,14 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, return -ENOMEDIUM; if (bs->read_only) return -EACCES; - if (drv->bdrv_pwrite) { - int ret, len, count = 0; - len = nb_sectors * 512; - do { - ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len - count); - if (ret < 0) { - printf("bdrv_write ret=%d\n", ret); - return ret; - } - count += ret; - buf += ret; - } while (count != len); - bs->wr_bytes += (unsigned) len; - bs->wr_ops ++; - return 0; - } + if (bdrv_check_request(bs, sector_num, nb_sectors)) + return -EIO; + return drv->bdrv_write(bs, sector_num, buf, nb_sectors); } -static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, - uint8_t *buf, int count1) +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count1) { uint8_t tmp_buf[SECTOR_SIZE]; int len, nb_sectors, count; @@ -627,8 +694,8 @@ static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, return count1; } -static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, - const uint8_t *buf, int count1) +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count1) { uint8_t tmp_buf[SECTOR_SIZE]; int len, nb_sectors, count; @@ -676,36 +743,6 @@ static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, } /** - * Read with byte offsets (needed only for file protocols) - */ -int bdrv_pread(BlockDriverState *bs, int64_t offset, - void *buf1, int count1) -{ - BlockDriver *drv = bs->drv; - - if (!drv) - return -ENOMEDIUM; - if (!drv->bdrv_pread) - return bdrv_pread_em(bs, offset, buf1, count1); - return drv->bdrv_pread(bs, offset, buf1, count1); -} - -/** - * Write with byte offsets (needed only for file protocols) - */ -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, - const void *buf1, int count1) -{ - BlockDriver *drv = bs->drv; - - if (!drv) - return -ENOMEDIUM; - if (!drv->bdrv_pwrite) - return bdrv_pwrite_em(bs, offset, buf1, count1); - return drv->bdrv_pwrite(bs, offset, buf1, count1); -} - -/** * Truncate file to 'offset' bytes (needed only for file protocols) */ int bdrv_truncate(BlockDriverState *bs, int64_t offset) @@ -929,6 +966,15 @@ int bdrv_is_encrypted(BlockDriverState *bs) return bs->encrypted; } +int bdrv_key_required(BlockDriverState *bs) +{ + BlockDriverState *backing_hd = bs->backing_hd; + + if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key) + return 1; + return (bs->encrypted && !bs->valid_key); +} + int bdrv_set_key(BlockDriverState *bs, const char *key) { int ret; @@ -941,7 +987,17 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) } if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) return -1; - return bs->drv->bdrv_set_key(bs, key); + ret = bs->drv->bdrv_set_key(bs, key); + if (ret < 0) { + bs->valid_key = 0; + } else if (!bs->valid_key) { + bs->valid_key = 1; + /* call the change callback now, we skipped it on open */ + bs->media_changed = 1; + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + } + return ret; } void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) @@ -974,12 +1030,12 @@ BlockDriverState *bdrv_find(const char *name) return NULL; } -void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) +void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque) { BlockDriverState *bs; for (bs = bdrv_first; bs != NULL; bs = bs->next) { - it(opaque, bs->device_name); + it(opaque, bs); } } @@ -990,6 +1046,8 @@ const char *bdrv_get_device_name(BlockDriverState *bs) void bdrv_flush(BlockDriverState *bs) { + if (!bs->drv) + return; if (bs->drv->bdrv_flush) bs->drv->bdrv_flush(bs); if (bs->backing_hd) @@ -1033,64 +1091,73 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum); } -void bdrv_info(void) +void bdrv_info(Monitor *mon) { BlockDriverState *bs; for (bs = bdrv_first; bs != NULL; bs = bs->next) { - term_printf("%s:", bs->device_name); - term_printf(" type="); + monitor_printf(mon, "%s:", bs->device_name); + monitor_printf(mon, " type="); switch(bs->type) { case BDRV_TYPE_HD: - term_printf("hd"); + monitor_printf(mon, "hd"); break; case BDRV_TYPE_CDROM: - term_printf("cdrom"); + monitor_printf(mon, "cdrom"); break; case BDRV_TYPE_FLOPPY: - term_printf("floppy"); + monitor_printf(mon, "floppy"); break; } - term_printf(" removable=%d", bs->removable); + monitor_printf(mon, " removable=%d", bs->removable); if (bs->removable) { - term_printf(" locked=%d", bs->locked); + monitor_printf(mon, " locked=%d", bs->locked); } if (bs->drv) { - term_printf(" file="); - term_print_filename(bs->filename); + monitor_printf(mon, " file="); + monitor_print_filename(mon, bs->filename); if (bs->backing_file[0] != '\0') { - term_printf(" backing_file="); - term_print_filename(bs->backing_file); - } - term_printf(" ro=%d", bs->read_only); - term_printf(" drv=%s", bs->drv->format_name); - if (bs->encrypted) - term_printf(" encrypted"); + monitor_printf(mon, " backing_file="); + monitor_print_filename(mon, bs->backing_file); + } + monitor_printf(mon, " ro=%d", bs->read_only); + monitor_printf(mon, " drv=%s", bs->drv->format_name); + monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs)); } else { - term_printf(" [not inserted]"); + monitor_printf(mon, " [not inserted]"); } - term_printf("\n"); + monitor_printf(mon, "\n"); } } /* The "info blockstats" command. */ -void bdrv_info_stats (void) +void bdrv_info_stats(Monitor *mon) { BlockDriverState *bs; for (bs = bdrv_first; bs != NULL; bs = bs->next) { - term_printf ("%s:" - " rd_bytes=%" PRIu64 - " wr_bytes=%" PRIu64 - " rd_operations=%" PRIu64 - " wr_operations=%" PRIu64 - "\n", - bs->device_name, - bs->rd_bytes, bs->wr_bytes, - bs->rd_ops, bs->wr_ops); + monitor_printf(mon, "%s:" + " rd_bytes=%" PRIu64 + " wr_bytes=%" PRIu64 + " rd_operations=%" PRIu64 + " wr_operations=%" PRIu64 + "\n", + bs->device_name, + bs->rd_bytes, bs->wr_bytes, + bs->rd_ops, bs->wr_ops); } } +const char *bdrv_get_encrypted_filename(BlockDriverState *bs) +{ + if (bs->backing_hd && bs->backing_hd->encrypted) + return bs->backing_file; + else if (bs->encrypted) + return bs->filename; + else + return NULL; +} + void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size) { @@ -1109,6 +1176,8 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, return -ENOMEDIUM; if (!drv->bdrv_write_compressed) return -ENOTSUP; + if (bdrv_check_request(bs, sector_num, nb_sectors)) + return -EIO; return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); } @@ -1123,6 +1192,26 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return drv->bdrv_get_info(bs, bdi); } +int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_put_buffer) + return -ENOTSUP; + return drv->bdrv_put_buffer(bs, buf, pos, size); +} + +int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (!drv->bdrv_get_buffer) + return -ENOTSUP; + return drv->bdrv_get_buffer(bs, buf, pos, size); +} + /**************************************************************/ /* handling of snapshots */ @@ -1246,17 +1335,20 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) /**************************************************************/ /* async I/Os */ -BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) +BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, + QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { BlockDriver *drv = bs->drv; BlockDriverAIOCB *ret; if (!drv) return NULL; + if (bdrv_check_request(bs, sector_num, nb_sectors)) + return NULL; - ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); + ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors, + cb, opaque); if (ret) { /* Update stats even though technically transfer has not happened. */ @@ -1267,9 +1359,9 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, return ret; } -BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) +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; @@ -1278,8 +1370,11 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, return NULL; if (bs->read_only) return NULL; + if (bdrv_check_request(bs, sector_num, nb_sectors)) + return NULL; - ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); + ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors, + cb, opaque); if (ret) { /* Update stats even though technically transfer has not happened. */ @@ -1292,9 +1387,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, void bdrv_aio_cancel(BlockDriverAIOCB *acb) { - BlockDriver *drv = acb->bs->drv; - - drv->bdrv_aio_cancel(acb); + acb->pool->cancel(acb); } @@ -1304,42 +1397,61 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb) static void bdrv_aio_bh_cb(void *opaque) { BlockDriverAIOCBSync *acb = opaque; + + if (!acb->is_write) + qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size); + qemu_vfree(acb->bounce); acb->common.cb(acb->common.opaque, acb->ret); + qemu_aio_release(acb); } -static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) +static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, + int64_t sector_num, + QEMUIOVector *qiov, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque, + int is_write) + { BlockDriverAIOCBSync *acb; - int ret; acb = qemu_aio_get(bs, cb, opaque); + acb->is_write = is_write; + acb->qiov = qiov; + acb->bounce = qemu_blockalign(bs, qiov->size); + if (!acb->bh) acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); - ret = bdrv_read(bs, sector_num, buf, nb_sectors); - acb->ret = ret; + + if (is_write) { + qemu_iovec_to_buffer(acb->qiov, acb->bounce); + acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors); + } else { + acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors); + } + qemu_bh_schedule(acb->bh); + return &acb->common; } -static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, - int64_t sector_num, const uint8_t *buf, int nb_sectors, +static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverAIOCBSync *acb; - int ret; + return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0); +} - acb = qemu_aio_get(bs, cb, opaque); - if (!acb->bh) - acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); - ret = bdrv_write(bs, sector_num, buf, nb_sectors); - acb->ret = ret; - qemu_bh_schedule(acb->bh); - return &acb->common; +static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1); } + static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) { BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; @@ -1362,10 +1474,15 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, { int async_ret; BlockDriverAIOCB *acb; + struct iovec iov; + QEMUIOVector qiov; async_ret = NOT_DONE; - acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, - bdrv_rw_em_cb, &async_ret); + iov.iov_base = (void *)buf; + iov.iov_len = nb_sectors * 512; + 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) return -1; @@ -1381,10 +1498,15 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, { int async_ret; BlockDriverAIOCB *acb; + struct iovec iov; + QEMUIOVector qiov; async_ret = NOT_DONE; - acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, - bdrv_rw_em_cb, &async_ret); + iov.iov_base = (void *)buf; + iov.iov_len = nb_sectors * 512; + 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) return -1; while (async_ret == NOT_DONE) { @@ -1395,37 +1517,28 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, void bdrv_init(void) { - bdrv_register(&bdrv_raw); - bdrv_register(&bdrv_host_device); -#ifndef _WIN32 - bdrv_register(&bdrv_cow); -#endif - bdrv_register(&bdrv_qcow); - bdrv_register(&bdrv_vmdk); - bdrv_register(&bdrv_cloop); - bdrv_register(&bdrv_dmg); - bdrv_register(&bdrv_bochs); - bdrv_register(&bdrv_vpc); - bdrv_register(&bdrv_vvfat); - bdrv_register(&bdrv_qcow2); - bdrv_register(&bdrv_parallels); - bdrv_register(&bdrv_nbd); + module_call_init(MODULE_INIT_BLOCK); } -void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, - void *opaque) +void aio_pool_init(AIOPool *pool, int aiocb_size, + void (*cancel)(BlockDriverAIOCB *acb)) +{ + pool->aiocb_size = aiocb_size; + pool->cancel = cancel; + pool->free_aiocb = NULL; +} + +void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriver *drv; BlockDriverAIOCB *acb; - drv = bs->drv; - if (drv->free_aiocb) { - acb = drv->free_aiocb; - drv->free_aiocb = acb->next; + if (pool->free_aiocb) { + acb = pool->free_aiocb; + pool->free_aiocb = acb->next; } else { - acb = qemu_mallocz(drv->aiocb_size); - if (!acb) - return NULL; + acb = qemu_mallocz(pool->aiocb_size); + acb->pool = pool; } acb->bs = bs; acb->cb = cb; @@ -1433,12 +1546,18 @@ void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, return acb; } +void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, + void *opaque) +{ + return qemu_aio_get_pool(&bs->drv->aio_pool, bs, cb, opaque); +} + void qemu_aio_release(void *p) { - BlockDriverAIOCB *acb = p; - BlockDriver *drv = acb->bs->drv; - acb->next = drv->free_aiocb; - drv->free_aiocb = acb; + BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p; + AIOPool *pool = acb->pool; + acb->next = pool->free_aiocb; + pool->free_aiocb = acb; } /**************************************************************/ @@ -1526,3 +1645,19 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) return drv->bdrv_ioctl(bs, req, buf); return -ENOTSUP; } + +BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, + unsigned long int req, void *buf, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BlockDriver *drv = bs->drv; + + if (drv && drv->bdrv_aio_ioctl) + return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque); + return NULL; +} + +void *qemu_blockalign(BlockDriverState *bs, size_t size) +{ + return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size); +}