From patchwork Wed Apr 14 15:50:10 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 50170 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 92CBFB7D2A for ; Thu, 15 Apr 2010 02:00:11 +1000 (EST) Received: from localhost ([127.0.0.1]:47678 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O24zm-0000Q8-4G for incoming@patchwork.ozlabs.org; Wed, 14 Apr 2010 11:59:18 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O24rw-0006HM-LX for qemu-devel@nongnu.org; Wed, 14 Apr 2010 11:51:12 -0400 Received: from [140.186.70.92] (port=53920 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O24rp-0006GP-Pn for qemu-devel@nongnu.org; Wed, 14 Apr 2010 11:51:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O24rd-0004NE-IP for qemu-devel@nongnu.org; Wed, 14 Apr 2010 11:51:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:14664) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O24rd-0004MS-4U for qemu-devel@nongnu.org; Wed, 14 Apr 2010 11:50:53 -0400 Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o3EFolB6001456 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 14 Apr 2010 11:50:47 -0400 Received: from localhost.localdomain (dhcp-5-175.str.redhat.com [10.32.5.175]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o3EFohRo020074; Wed, 14 Apr 2010 11:50:45 -0400 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Wed, 14 Apr 2010 17:50:10 +0200 Message-Id: <1271260214-27443-2-git-send-email-kwolf@redhat.com> In-Reply-To: <1271260214-27443-1-git-send-email-kwolf@redhat.com> References: <1271260214-27443-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: kwolf@redhat.com, hch@lst.de Subject: [Qemu-devel] [RFC PATCH 1/5] block: separate raw images from the file protocol X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Christoph Hellwig We're running into various problems because the "raw" file access, which is used internally by the various image formats is entangled with the "raw" image format, which maps the VM view 1:1 to a file system. This patch renames the raw file backends to the file protocol which is treated like other protocols (e.g. nbd and http) and adds a new "raw" image format which is just a wrapper around calls to the underlying protocol. The patch is surprisingly simple, besides changing the probing logical in block.c to only look for image formats when using bdrv_open and renaming of the old raw protocols to file there's almost nothing in there. For creating images, a new bdrv_create_file is introduced which guesses the protocol to use. This allows using qemu-img create -f raw (or just using the default) for both files and host devices. Converting the other format drivers to use this function to create their images is left for later patches. The only issues still open are in the handling of the host devices. Firstly in current qemu we can specifiy the host* format names on various command line acceping images, but the new code can't do that without adding some translation. Second the layering breaks the no_zero_init flag in the BlockDriver used by qemu-img. I'm not happy how this is done per-driver instead of per-state so I'll prepare a separate patch to clean this up. There's some more cleanup opportunity after this patch, e.g. using separate lists and registration functions for image formats vs protocols and maybe even host drivers, but this can be done at a later stage. Also there's a check for protocol in bdrv_open for the BDRV_O_SNAPSHOT case that I don't quite understand, but which I fear won't work as expected - possibly even before this patch. Note that this patch requires various recent block patches from Kevin and me, which should all be in his block queue. Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- Makefile.objs | 2 +- block.c | 74 ++++++++++++++--------- block.h | 1 + block/raw-posix.c | 15 +++-- block/raw-win32.c | 12 ++-- block/raw.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 40 deletions(-) create mode 100644 block/raw.c diff --git a/Makefile.objs b/Makefile.objs index 67a8a1e..10900c9 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -12,7 +12,7 @@ block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o -block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o +block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o block-nested-y += parallels.o nbd.o blkdebug.o block-nested-$(CONFIG_WIN32) += raw-win32.o diff --git a/block.c b/block.c index 12cf434..715c30e 100644 --- a/block.c +++ b/block.c @@ -54,6 +54,7 @@ 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 BlockDriver *find_protocol(const char *filename); static QTAILQ_HEAD(, BlockDriverState) bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states); @@ -203,6 +204,18 @@ int bdrv_create(BlockDriver *drv, const char* filename, return drv->bdrv_create(filename, options); } +int bdrv_create_file(const char* filename, QEMUOptionParameter *options) +{ + BlockDriver *drv; + + drv = find_protocol(filename); + if (drv == NULL) { + drv = bdrv_find_format("file"); + } + + return bdrv_create(drv, filename, options); +} + #ifdef _WIN32 void get_tmp_filename(char *filename, int size) { @@ -246,6 +259,28 @@ int is_windows_drive(const char *filename) } #endif +/* + * 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; + + QLIST_FOREACH(d, &bdrv_drivers, list) { + 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_protocol(const char *filename) { BlockDriver *drv1; @@ -256,11 +291,16 @@ static BlockDriver *find_protocol(const char *filename) #ifdef _WIN32 if (is_windows_drive(filename) || is_windows_drive_prefix(filename)) - return bdrv_find_format("raw"); + return bdrv_find_format("file"); #endif p = strchr(filename, ':'); - if (!p) - return bdrv_find_format("raw"); + if (!p) { + drv1 = find_hdev_driver(filename); + if (!drv1) { + drv1 = bdrv_find_format("file"); + } + return drv1; + } len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; @@ -275,28 +315,6 @@ static BlockDriver *find_protocol(const char *filename) return NULL; } -/* - * 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; - - QLIST_FOREACH(d, &bdrv_drivers, list) { - 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; @@ -319,6 +337,7 @@ static BlockDriver *find_image_format(const char *filename) } score_max = 0; + drv = NULL; QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (drv1->bdrv_probe) { score = drv1->bdrv_probe(buf, ret, filename); @@ -423,10 +442,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, pstrcpy(bs->filename, sizeof(bs->filename), filename); if (!drv) { - drv = find_hdev_driver(filename); - if (!drv) { - drv = find_image_format(filename); - } + drv = find_image_format(filename); } if (!drv) { diff --git a/block.h b/block.h index 05ad572..f58edf1 100644 --- a/block.h +++ b/block.h @@ -57,6 +57,7 @@ BlockDriver *bdrv_find_format(const char *format_name); BlockDriver *bdrv_find_whitelisted_format(const char *format_name); int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options); +int bdrv_create_file(const char* filename, QEMUOptionParameter *options); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); diff --git a/block/raw-posix.c b/block/raw-posix.c index 4cda9c1..8f57ab0 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -768,8 +768,9 @@ static QEMUOptionParameter raw_create_options[] = { { NULL } }; -static BlockDriver bdrv_raw = { - .format_name = "raw", +static BlockDriver bdrv_file = { + .format_name = "file", + .protocol_name = "file", .instance_size = sizeof(BDRVRawState), .bdrv_probe = NULL, /* no probe for protocols */ .bdrv_open = raw_open, @@ -1026,6 +1027,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options) static BlockDriver bdrv_host_device = { .format_name = "host_device", + .protocol_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = hdev_probe_device, .bdrv_open = hdev_open, @@ -1140,6 +1142,7 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag) static BlockDriver bdrv_host_floppy = { .format_name = "host_floppy", + .protocol_name = "host_floppy", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = floppy_probe_device, .bdrv_open = floppy_open, @@ -1239,6 +1242,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_cdrom = { .format_name = "host_cdrom", + .protocol_name = "host_cdrom", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = cdrom_probe_device, .bdrv_open = cdrom_open, @@ -1361,6 +1365,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_cdrom = { .format_name = "host_cdrom", + .protocol_name = "host_cdrom", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = cdrom_probe_device, .bdrv_open = cdrom_open, @@ -1385,13 +1390,13 @@ static BlockDriver bdrv_host_cdrom = { }; #endif /* __FreeBSD__ */ -static void bdrv_raw_init(void) +static void bdrv_file_init(void) { /* * Register all the drivers. Note that order is important, the driver * registered last will get probed first. */ - bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_file); bdrv_register(&bdrv_host_device); #ifdef __linux__ bdrv_register(&bdrv_host_floppy); @@ -1402,4 +1407,4 @@ static void bdrv_raw_init(void) #endif } -block_init(bdrv_raw_init); +block_init(bdrv_file_init); diff --git a/block/raw-win32.c b/block/raw-win32.c index 526764f..eadebeb 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -238,8 +238,9 @@ static QEMUOptionParameter raw_create_options[] = { { NULL } }; -static BlockDriver bdrv_raw = { - .format_name = "raw", +static BlockDriver bdrv_file = { + .format_name = "file", + .protocol_name = "file", .instance_size = sizeof(BDRVRawState), .bdrv_open = raw_open, .bdrv_close = raw_close, @@ -395,6 +396,7 @@ static int raw_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_device = { .format_name = "host_device", + .protocol_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = hdev_probe_device, .bdrv_open = hdev_open, @@ -406,10 +408,10 @@ static BlockDriver bdrv_host_device = { .bdrv_getlength = raw_getlength, }; -static void bdrv_raw_init(void) +static void bdrv_file_init(void) { - bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_file); bdrv_register(&bdrv_host_device); } -block_init(bdrv_raw_init); +block_init(bdrv_file_init); diff --git a/block/raw.c b/block/raw.c new file mode 100644 index 0000000..953e285 --- /dev/null +++ b/block/raw.c @@ -0,0 +1,171 @@ + +#include "qemu-common.h" +#include "block_int.h" +#include "module.h" + +typedef struct RAWState { + BlockDriverState *hd; +} RAWState; + +static int raw_open(BlockDriverState *bs, const char *filename, int flags) +{ + RAWState *s = bs->opaque; + int ret; + + ret = bdrv_file_open(&s->hd, filename, flags); + if (!ret) { + bs->sg = s->hd->sg; + } + + return ret; +} + +static int raw_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + RAWState *s = bs->opaque; + return bdrv_read(s->hd, sector_num, buf, nb_sectors); +} + +static int raw_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + RAWState *s = bs->opaque; + return bdrv_write(s->hd, sector_num, buf, nb_sectors); +} + +static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RAWState *s = bs->opaque; + + return bdrv_aio_readv(s->hd, 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) +{ + RAWState *s = bs->opaque; + + return bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque); +} + +static void raw_close(BlockDriverState *bs) +{ + RAWState *s = bs->opaque; + bdrv_delete(s->hd); +} + +static void raw_flush(BlockDriverState *bs) +{ + RAWState *s = bs->opaque; + bdrv_flush(s->hd); +} + +static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RAWState *s = bs->opaque; + return bdrv_aio_flush(s->hd, cb, opaque); +} + +static int64_t raw_getlength(BlockDriverState *bs) +{ + RAWState *s = bs->opaque; + return bdrv_getlength(s->hd); +} + +static int raw_truncate(BlockDriverState *bs, int64_t offset) +{ + RAWState *s = bs->opaque; + return bdrv_truncate(s->hd, offset); +} + +static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + return 1; /* everything can be opened as raw image */ +} + +static int raw_is_inserted(BlockDriverState *bs) +{ + RAWState *s = bs->opaque; + return bdrv_is_inserted(s->hd); +} + +static int raw_eject(BlockDriverState *bs, int eject_flag) +{ + RAWState *s = bs->opaque; + return bdrv_eject(s->hd, eject_flag); +} + +static int raw_set_locked(BlockDriverState *bs, int locked) +{ + RAWState *s = bs->opaque; + bdrv_set_locked(s->hd, locked); + return 0; +} + +static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) +{ + RAWState *s = bs->opaque; + return bdrv_ioctl(s->hd, req, buf); +} + +static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, + unsigned long int req, void *buf, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RAWState *s = bs->opaque; + return bdrv_aio_ioctl(s->hd, req, buf, cb, opaque); +} + +static int raw_create(const char *filename, QEMUOptionParameter *options) +{ + return bdrv_create_file(filename, options); +} + +static QEMUOptionParameter raw_create_options[] = { + { + .name = BLOCK_OPT_SIZE, + .type = OPT_SIZE, + .help = "Virtual disk size" + }, + { NULL } +}; + +static BlockDriver bdrv_raw = { + .format_name = "raw", + + .instance_size = sizeof(RAWState), + + .bdrv_open = raw_open, + .bdrv_close = raw_close, + .bdrv_read = raw_read, + .bdrv_write = raw_write, + .bdrv_flush = raw_flush, + .bdrv_probe = raw_probe, + .bdrv_getlength = raw_getlength, + .bdrv_truncate = raw_truncate, + + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, + .bdrv_aio_flush = raw_aio_flush, + + .bdrv_is_inserted = raw_is_inserted, + .bdrv_eject = raw_eject, + .bdrv_set_locked = raw_set_locked, + .bdrv_ioctl = raw_ioctl, + .bdrv_aio_ioctl = raw_aio_ioctl, + + .bdrv_create = raw_create, + .create_options = raw_create_options, +}; + +static void bdrv_raw_init(void) +{ + bdrv_register(&bdrv_raw); +} + +block_init(bdrv_raw_init);