From patchwork Mon Apr 22 11:31:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 238495 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AC7782C0157 for ; Mon, 22 Apr 2013 22:16:56 +1000 (EST) Received: from localhost ([::1]:42484 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUF1p-0000p2-9k for incoming@patchwork.ozlabs.org; Mon, 22 Apr 2013 07:35:25 -0400 Received: from eggs.gnu.org ([208.118.235.92]:37313) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUEyl-0004oh-2c for qemu-devel@nongnu.org; Mon, 22 Apr 2013 07:32:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UUEyi-0002An-RC for qemu-devel@nongnu.org; Mon, 22 Apr 2013 07:32:14 -0400 Received: from mx1.redhat.com ([209.132.183.28]:64739) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UUEyi-0002AU-IY for qemu-devel@nongnu.org; Mon, 22 Apr 2013 07:32:12 -0400 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r3MBWBsa003589 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 22 Apr 2013 07:32:11 -0400 Received: from dhcp-200-207.str.redhat.com (ovpn-116-69.ams2.redhat.com [10.36.116.69]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r3MBVfDl031324; Mon, 22 Apr 2013 07:32:09 -0400 From: Kevin Wolf To: anthony@codemonkey.ws Date: Mon, 22 Apr 2013 13:31:31 +0200 Message-Id: <1366630294-18984-18-git-send-email-kwolf@redhat.com> In-Reply-To: <1366630294-18984-1-git-send-email-kwolf@redhat.com> References: <1366630294-18984-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH 17/20] vvfat: Use bdrv_open options instead of filename X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- block/vvfat.c | 228 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 168 insertions(+), 60 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index ef74c30..f4c06b9 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1,4 +1,4 @@ -/* vim:set shiftwidth=4 ts=8: */ +/* vim:set shiftwidth=4 ts=4: */ /* * QEMU Block driver for virtual VFAT (shadows a local directory) * @@ -28,6 +28,8 @@ #include "block/block_int.h" #include "qemu/module.h" #include "migration/migration.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qbool.h" #ifndef S_IWGRP #define S_IWGRP 0 @@ -988,11 +990,91 @@ static void vvfat_rebind(BlockDriverState *bs) s->bs = bs; } -static int vvfat_open(BlockDriverState *bs, const char* dirname, +static QemuOptsList runtime_opts = { + .name = "vvfat", + .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), + .desc = { + { + .name = "dir", + .type = QEMU_OPT_STRING, + .help = "Host directory to map to the vvfat device", + }, + { + .name = "fat-type", + .type = QEMU_OPT_NUMBER, + .help = "FAT type (12, 16 or 32)", + }, + { + .name = "floppy", + .type = QEMU_OPT_BOOL, + .help = "Create a floppy rather than a hard disk image", + }, + { + .name = "rw", + .type = QEMU_OPT_BOOL, + .help = "Make the image writable", + }, + { /* end of list */ } + }, +}; + +static void vvfat_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + int fat_type = 0; + bool floppy = false; + bool rw = false; + int i; + + if (!strstart(filename, "fat:", NULL)) { + error_setg(errp, "File name string must start with 'fat:'"); + return; + } + + /* Parse options */ + if (strstr(filename, ":32:")) { + fat_type = 32; + } else if (strstr(filename, ":16:")) { + fat_type = 16; + } else if (strstr(filename, ":12:")) { + fat_type = 12; + } + + if (strstr(filename, ":floppy:")) { + floppy = true; + } + + if (strstr(filename, ":rw:")) { + rw = true; + } + + /* Get the directory name without options */ + i = strrchr(filename, ':') - filename; + assert(i >= 3); + if (filename[i - 2] == ':' && qemu_isalpha(filename[i - 1])) { + /* workaround for DOS drive names */ + filename += i - 1; + } else { + filename += i + 1; + } + + /* Fill in the options QDict */ + qdict_put(options, "dir", qstring_from_str(filename)); + qdict_put(options, "fat-type", qint_from_int(fat_type)); + qdict_put(options, "floppy", qbool_from_int(floppy)); + qdict_put(options, "rw", qbool_from_int(rw)); +} + +static int vvfat_open(BlockDriverState *bs, const char* dummy, QDict *options, int flags) { BDRVVVFATState *s = bs->opaque; - int i, cyls, heads, secs; + int cyls, heads, secs; + bool floppy; + const char *dirname; + QemuOpts *opts; + Error *local_err = NULL; + int ret; #ifdef DEBUG vvv = s; @@ -1003,6 +1085,65 @@ DLOG(if (stderr == NULL) { setbuf(stderr, NULL); }) + opts = qemu_opts_create_nofail(&runtime_opts); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + ret = -EINVAL; + goto fail; + } + + dirname = qemu_opt_get(opts, "dir"); + if (!dirname) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, "vvfat block driver requires " + "a 'dir' option"); + ret = -EINVAL; + goto fail; + } + + s->fat_type = qemu_opt_get_number(opts, "fat-type", 0); + floppy = qemu_opt_get_bool(opts, "floppy", false); + + if (floppy) { + /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */ + if (!s->fat_type) { + s->fat_type = 12; + secs = 36; + s->sectors_per_cluster = 2; + } else { + secs = s->fat_type == 12 ? 18 : 36; + s->sectors_per_cluster = 1; + } + s->first_sectors_number = 1; + cyls = 80; + heads = 2; + } else { + /* 32MB or 504MB disk*/ + if (!s->fat_type) { + s->fat_type = 16; + } + cyls = s->fat_type == 12 ? 64 : 1024; + heads = 16; + secs = 63; + } + + switch (s->fat_type) { + case 32: + fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " + "You are welcome to do so!\n"); + break; + case 16: + case 12: + break; + default: + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Valid FAT types are only " + "12, 16 and 32"); + ret = -EINVAL; + goto fail; + } + + s->bs = bs; /* LATER TODO: if FAT32, adjust */ @@ -1018,63 +1159,24 @@ DLOG(if (stderr == NULL) { s->fat2 = NULL; s->downcase_short_names = 1; - if (!strstart(dirname, "fat:", NULL)) - return -1; - - if (strstr(dirname, ":32:")) { - fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); - s->fat_type = 32; - } else if (strstr(dirname, ":16:")) { - s->fat_type = 16; - } else if (strstr(dirname, ":12:")) { - s->fat_type = 12; - } - - if (strstr(dirname, ":floppy:")) { - /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */ - if (!s->fat_type) { - s->fat_type = 12; - secs = 36; - s->sectors_per_cluster=2; - } else { - secs = s->fat_type == 12 ? 18 : 36; - s->sectors_per_cluster=1; - } - s->first_sectors_number = 1; - cyls = 80; - heads = 2; - } else { - /* 32MB or 504MB disk*/ - if (!s->fat_type) { - s->fat_type = 16; - } - cyls = s->fat_type == 12 ? 64 : 1024; - heads = 16; - secs = 63; - } fprintf(stderr, "vvfat %s chs %d,%d,%d\n", dirname, cyls, heads, secs); s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1); - if (strstr(dirname, ":rw:")) { - if (enable_write_target(s)) - return -1; - bs->read_only = 0; + if (qemu_opt_get_bool(opts, "rw", false)) { + if (enable_write_target(s)) { + ret = -EIO; + goto fail; + } + bs->read_only = 0; } - i = strrchr(dirname, ':') - dirname; - assert(i >= 3); - if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1])) - /* workaround for DOS drive names */ - dirname += i-1; - else - dirname += i+1; - bs->total_sectors = cyls * heads * secs; if (init_directories(s, dirname, heads, secs)) { - return -1; + ret = -EIO; + goto fail; } s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; @@ -1094,7 +1196,10 @@ DLOG(if (stderr == NULL) { migrate_add_blocker(s->migration_blocker); } - return 0; + ret = 0; +fail: + qemu_opts_del(opts); + return ret; } static inline void vvfat_close_current_file(BDRVVVFATState *s) @@ -2866,15 +2971,18 @@ static void vvfat_close(BlockDriverState *bs) } static BlockDriver bdrv_vvfat = { - .format_name = "vvfat", - .instance_size = sizeof(BDRVVVFATState), - .bdrv_file_open = vvfat_open, - .bdrv_rebind = vvfat_rebind, - .bdrv_read = vvfat_co_read, - .bdrv_write = vvfat_co_write, - .bdrv_close = vvfat_close, - .bdrv_co_is_allocated = vvfat_co_is_allocated, - .protocol_name = "fat", + .format_name = "vvfat", + .protocol_name = "fat", + .instance_size = sizeof(BDRVVVFATState), + + .bdrv_parse_filename = vvfat_parse_filename, + .bdrv_file_open = vvfat_open, + .bdrv_close = vvfat_close, + .bdrv_rebind = vvfat_rebind, + + .bdrv_read = vvfat_co_read, + .bdrv_write = vvfat_co_write, + .bdrv_co_is_allocated = vvfat_co_is_allocated, }; static void bdrv_vvfat_init(void)