#include "qemu-common.h"
#include "monitor.h"
#include "block_int.h"
+#include "module.h"
#ifdef HOST_BSD
#include <sys/types.h>
#define SECTOR_BITS 9
#define SECTOR_SIZE (1 << SECTOR_BITS)
-static AIOPool vectored_aio_pool;
-
-typedef struct BlockDriverAIOCBSync {
- BlockDriverAIOCB common;
- QEMUBH *bh;
- int ret;
-} 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,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
}
}
-
-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_cancel = bdrv_aio_cancel_em;
- bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
+ bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
+ bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
} else if (!bdrv->bdrv_read) {
/* add synchronous IO emulation layer */
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
- aio_pool_init(&bdrv->aio_pool, bdrv->aiocb_size, bdrv->bdrv_aio_cancel);
bdrv->next = first_drv;
first_drv = bdrv;
}
return NULL;
}
-int bdrv_create(BlockDriver *drv,
- const char *filename, int64_t size_in_sectors,
- const char *backing_file, int flags)
+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
filename[1] == ':');
}
-static int is_windows_drive(const char *filename)
+int is_windows_drive(const char *filename)
{
if (is_windows_drive_prefix(filename) &&
filename[2] == '\0')
#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;
return NULL;
}
-/* XXX: force raw format if block or character device ? It would
- simplify the BSD case */
+/*
+ * Detect host devices. By convention, /dev/cdrom[N] is always
+ * recognized as a host CDROM.
+ */
+static BlockDriver *find_hdev_driver(const char *filename)
+{
+ int score_max = 0, score;
+ BlockDriver *drv = NULL, *d;
+
+ for (d = first_drv; d; d = d->next) {
+ if (d->bdrv_probe_device) {
+ score = d->bdrv_probe_device(filename);
+ if (score > score_max) {
+ score_max = score;
+ drv = d;
+ }
+ }
+ }
+
+ return drv;
+}
+
static BlockDriver *find_image_format(const char *filename)
{
int ret, score, score_max;
uint8_t buf[2048];
BlockDriverState *bs;
- /* 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;
-#ifdef _WIN32
- if (is_windows_drive(filename))
- return &bdrv_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;
- }
- }
-#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);
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;
int64_t total_size;
int is_protocol = 0;
+ BlockDriver *bdrv_qcow2;
+ QEMUOptionParameter *options;
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
/* if there is a backing file, use it */
bs1 = bdrv_new("");
- ret = bdrv_open(bs1, filename, 0);
+ ret = bdrv_open2(bs1, filename, 0, drv);
if (ret < 0) {
bdrv_delete(bs1);
return ret;
else
realpath(filename, backing_filename);
- ret = bdrv_create(&bdrv_qcow2, tmp_filename,
- total_size, backing_filename, 0);
+ bdrv_qcow2 = bdrv_find_format("qcow2");
+ options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
+
+ set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size * 512);
+ set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
+ if (drv) {
+ set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
+ drv->format_name);
+ }
+
+ ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
if (ret < 0) {
return ret;
}
+
filename = tmp_filename;
+ drv = bdrv_qcow2;
bs->is_temporary = 1;
}
if (flags & BDRV_O_FILE) {
drv = find_protocol(filename);
} else if (!drv) {
- drv = find_image_format(filename);
+ drv = find_hdev_driver(filename);
+ if (!drv) {
+ drv = find_image_format(filename);
+ }
}
if (!drv) {
ret = -ENOENT;
#endif
if (bs->backing_file[0] != '\0') {
/* if there is a backing file, use it */
+ BlockDriver *back_drv = NULL;
bs->backing_hd = bdrv_new("");
path_combine(backing_filename, sizeof(backing_filename),
filename, bs->backing_file);
- ret = bdrv_open(bs->backing_hd, backing_filename, open_flags);
+ 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;
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)
{
len = bdrv_getlength(bs);
- if ((offset + size) > len)
+ 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)
{
- int64_t offset;
-
- /* Deal with byte accesses */
- if (sector_num < 0)
- offset = -sector_num;
- else
- offset = sector_num * 512;
-
- return bdrv_check_byte_request(bs, offset, nb_sectors * 512);
+ return bdrv_check_byte_request(bs, sector_num * 512, nb_sectors * 512);
}
/* return < 0 if error. See bdrv_write() for the return codes */
void bdrv_flush(BlockDriverState *bs)
{
+ if (!bs->drv)
+ return;
if (bs->drv->bdrv_flush)
bs->drv->bdrv_flush(bs);
if (bs->backing_hd)
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);
}
return drv->bdrv_get_info(bs, bdi);
}
+int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
+ int64_t pos, int size)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_save_vmstate)
+ return -ENOTSUP;
+ return drv->bdrv_save_vmstate(bs, buf, pos, size);
+}
+
+int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
+ int64_t pos, int size)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_load_vmstate)
+ return -ENOTSUP;
+ return drv->bdrv_load_vmstate(bs, buf, pos, size);
+}
+
/**************************************************************/
/* handling of snapshots */
/**************************************************************/
/* async I/Os */
-typedef struct VectorTranslationAIOCB {
- BlockDriverAIOCB common;
- QEMUIOVector *iov;
- uint8_t *bounce;
- int is_write;
- BlockDriverAIOCB *aiocb;
-} VectorTranslationAIOCB;
-
-static void bdrv_aio_cancel_vector(BlockDriverAIOCB *_acb)
-{
- VectorTranslationAIOCB *acb
- = container_of(_acb, VectorTranslationAIOCB, common);
-
- bdrv_aio_cancel(acb->aiocb);
-}
-
-static void bdrv_aio_rw_vector_cb(void *opaque, int ret)
-{
- VectorTranslationAIOCB *s = (VectorTranslationAIOCB *)opaque;
-
- if (!s->is_write) {
- qemu_iovec_from_buffer(s->iov, s->bounce, s->iov->size);
- }
- qemu_vfree(s->bounce);
- s->common.cb(s->common.opaque, ret);
- qemu_aio_release(s);
-}
-
-static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
- int64_t sector_num,
- QEMUIOVector *iov,
- int nb_sectors,
- BlockDriverCompletionFunc *cb,
- void *opaque,
- int is_write)
-
-{
- VectorTranslationAIOCB *s = qemu_aio_get_pool(&vectored_aio_pool, bs,
- cb, opaque);
-
- s->iov = iov;
- s->bounce = qemu_memalign(512, nb_sectors * 512);
- s->is_write = is_write;
- if (is_write) {
- qemu_iovec_to_buffer(s->iov, s->bounce);
- s->aiocb = bdrv_aio_write(bs, sector_num, s->bounce, nb_sectors,
- bdrv_aio_rw_vector_cb, s);
- } else {
- s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors,
- bdrv_aio_rw_vector_cb, s);
- }
- return &s->common;
-}
-
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *iov, int nb_sectors,
+ QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
-{
- if (bdrv_check_request(bs, sector_num, nb_sectors))
- return NULL;
-
- return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
- cb, opaque, 0);
-}
-
-BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
- QEMUIOVector *iov, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- if (bdrv_check_request(bs, sector_num, nb_sectors))
- return NULL;
-
- return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
- cb, opaque, 1);
-}
-
-BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
BlockDriverAIOCB *ret;
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. */
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;
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. */
/**************************************************************/
/* async block device emulation */
+typedef struct BlockDriverAIOCBSync {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ int ret;
+ /* vector translation state */
+ QEMUIOVector *qiov;
+ uint8_t *bounce;
+ int is_write;
+} BlockDriverAIOCBSync;
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+ BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
+ qemu_bh_delete(acb->bh);
+ acb->bh = NULL;
+ qemu_aio_release(acb);
+}
+
+static AIOPool bdrv_em_aio_pool = {
+ .aiocb_size = sizeof(BlockDriverAIOCBSync),
+ .cancel = bdrv_aio_cancel_em,
+};
+
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_bh_delete(acb->bh);
+ acb->bh = NULL;
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 = qemu_aio_get(&bdrv_em_aio_pool, 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;
-
- 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;
+ return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
-static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
- BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
- qemu_bh_cancel(acb->bh);
- qemu_aio_release(acb);
+ return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
/**************************************************************/
{
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;
{
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) {
void bdrv_init(void)
{
- aio_pool_init(&vectored_aio_pool, sizeof(VectorTranslationAIOCB),
- bdrv_aio_cancel_vector);
-
- 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);
-}
-
-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;
+ module_call_init(MODULE_INIT_BLOCK);
}
-void *qemu_aio_get_pool(AIOPool *pool, BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque)
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriverAIOCB *acb;
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 = (BlockDriverAIOCB *)p;
/**
* If eject_flag is TRUE, eject the media. Otherwise, close the tray
*/
-void bdrv_eject(BlockDriverState *bs, int eject_flag)
+int bdrv_eject(BlockDriverState *bs, int eject_flag)
{
BlockDriver *drv = bs->drv;
int ret;
+ if (bs->locked) {
+ return -EBUSY;
+ }
+
if (!drv || !drv->bdrv_eject) {
ret = -ENOTSUP;
} else {
if (ret == -ENOTSUP) {
if (eject_flag)
bdrv_close(bs);
+ ret = 0;
}
+
+ return ret;
}
int bdrv_is_locked(BlockDriverState *bs)
return -ENOTSUP;
}
-int bdrv_sg_send_command(BlockDriverState *bs, void *buf, int count)
-{
- return bs->drv->bdrv_sg_send_command(bs, buf, count);
-}
-
-int bdrv_sg_recv_response(BlockDriverState *bs, void *buf, int count)
+BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
- return bs->drv->bdrv_sg_recv_response(bs, buf, count);
-}
+ BlockDriver *drv = bs->drv;
-BlockDriverAIOCB *bdrv_sg_aio_read(BlockDriverState *bs, void *buf, int count,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- return bs->drv->bdrv_sg_aio_read(bs, buf, count, cb, opaque);
+ if (drv && drv->bdrv_aio_ioctl)
+ return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque);
+ return NULL;
}
-BlockDriverAIOCB *bdrv_sg_aio_write(BlockDriverState *bs, void *buf, int count,
- BlockDriverCompletionFunc *cb, void *opaque)
+void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
- return bs->drv->bdrv_sg_aio_write(bs, buf, count, cb, opaque);
+ return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
}