[libvirt] [PATCH] Support QEMU's virtual FAT block device driver

Daniel Veillard veillard at redhat.com
Tue Nov 17 15:08:08 UTC 2009


On Tue, Nov 17, 2009 at 01:20:15PM +0000, Daniel P. Berrange wrote:
> Introduce a new type="dir"  mode for <disks> that allows use of
> QEMU's  virtual FAT block device driver. eg
> 
>     <disk type='dir' device='floppy'>
>       <source dir='/tmp/test'/>
>       <target dev='fda' bus='fdc'/>
>       <readonly/>
>     </disk>
> 
> gets turned into
> 
>   -drive file=fat:floppy:/tmp/test,if=floppy,index=0
> 
> Only read-only disks are supported with virtual FAT mode
> 
> * src/conf/domain_conf.c, src/conf/domain_conf.h: Add type="dir"
> * docs/schemas/domain.rng: Document new disk type
> * src/xen/xend_internal.c, src/xen/xm_internal.c: Raise error for
>   unsupported disk types
> * tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom-empty.args: Fix
>   empty disk file handling
> * tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.args,
>   tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.xml,
>   tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.args,
>   tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.xml
>   tests/qemuxml2argvtest.c: Test QEMU vitual FAT driver
> * src/qemu/qemu_conf.c: Support generating fat:/some/dir type
>   disk args
> * src/security/security_selinux.c: Temporarily skip labelling
>   of directory based disks
> ---
>  docs/schemas/domain.rng                            |   16 ++++++
>  src/conf/domain_conf.c                             |   36 ++++++++++++--
>  src/conf/domain_conf.h                             |    1 +
>  src/qemu/qemu_conf.c                               |   49 ++++++++++++++++++-
>  src/security/security_selinux.c                    |    3 +
>  src/xen/xend_internal.c                            |    7 ++-
>  src/xen/xm_internal.c                              |   16 +++++-
>  .../qemuxml2argv-disk-cdrom-empty.args             |    2 +-
>  .../qemuxml2argv-disk-drive-fat.args               |    1 +
>  .../qemuxml2argv-disk-drive-fat.xml                |   24 ++++++++++
>  .../qemuxml2argv-floppy-drive-fat.args             |    1 +
>  .../qemuxml2argv-floppy-drive-fat.xml              |   24 ++++++++++
>  tests/qemuxml2argvtest.c                           |    4 ++
>  tests/qemuxml2xmltest.c                            |    2 +
>  14 files changed, 173 insertions(+), 13 deletions(-)
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.args
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.xml
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.args
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.xml
> 
> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
> index 1bf44fd..7a3ef97 100644
> --- a/docs/schemas/domain.rng
> +++ b/docs/schemas/domain.rng
> @@ -434,6 +434,22 @@
>              <ref name="diskspec"/>
>            </interleave>
>          </group>
> +        <group>
> +          <attribute name="type">
> +            <value>dir</value>
> +          </attribute>
> +          <interleave>
> +            <optional>
> +              <element name="source">
> +                <attribute name="dir">
> +                  <ref name="absFilePath"/>
> +                </attribute>
> +                <empty/>
> +              </element>
> +            </optional>
> +            <ref name="diskspec"/>
> +          </interleave>
> +        </group>
>          <ref name="diskspec"/>
>        </choice>
>      </element>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 0a7eef7..42820a7 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -90,7 +90,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
>  
>  VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
>                "block",
> -              "file")
> +              "file",
> +              "dir")
>  
>  VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
>                "disk",
> @@ -777,10 +778,22 @@ virDomainDiskDefParseXML(virConnectPtr conn,
>              if ((source == NULL) &&
>                  (xmlStrEqual(cur->name, BAD_CAST "source"))) {
>  
> -                if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
> +                switch (def->type) {
> +                case VIR_DOMAIN_DISK_TYPE_FILE:
>                      source = virXMLPropString(cur, "file");
> -                else
> +                    break;
> +                case VIR_DOMAIN_DISK_TYPE_BLOCK:
>                      source = virXMLPropString(cur, "dev");
> +                    break;
> +                case VIR_DOMAIN_DISK_TYPE_DIR:
> +                    source = virXMLPropString(cur, "dir");
> +                    break;
> +                default:
> +                    virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                                         _("unexpected disk type %s"),
> +                                         virDomainDiskTypeToString(def->type));
> +                    goto error;
> +                }
>  
>                  /* People sometimes pass a bogus '' source path
>                     when they mean to omit the source element
> @@ -3951,12 +3964,25 @@ virDomainDiskDefFormat(virConnectPtr conn,
>      }
>  
>      if (def->src) {
> -        if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
> +        switch (def->type) {
> +        case VIR_DOMAIN_DISK_TYPE_FILE:
>              virBufferEscapeString(buf, "      <source file='%s'/>\n",
>                                    def->src);
> -        else
> +            break;
> +        case VIR_DOMAIN_DISK_TYPE_BLOCK:
>              virBufferEscapeString(buf, "      <source dev='%s'/>\n",
>                                    def->src);
> +            break;
> +        case VIR_DOMAIN_DISK_TYPE_DIR:
> +            virBufferEscapeString(buf, "      <source dir='%s'/>\n",
> +                                  def->src);
> +            break;
> +        default:
> +            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                                 _("unexpected disk type %s"),
> +                                 virDomainDiskTypeToString(def->type));
> +            return -1;
> +        }
>      }
>  
>      virBufferVSprintf(buf, "      <target dev='%s' bus='%s'/>\n",
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 1fdb4fa..6201463 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -67,6 +67,7 @@ enum virDomainVirtType {
>  enum virDomainDiskType {
>      VIR_DOMAIN_DISK_TYPE_BLOCK,
>      VIR_DOMAIN_DISK_TYPE_FILE,
> +    VIR_DOMAIN_DISK_TYPE_DIR,
>  
>      VIR_DOMAIN_DISK_TYPE_LAST
>  };
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index c807688..2d72b4b 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -1980,8 +1980,30 @@ int qemudBuildCommandLine(virConnectPtr conn,
>                  break;
>              }
>  
> -            virBufferVSprintf(&opt, "file=%s", disk->src ? disk->src : "");
> -            virBufferVSprintf(&opt, ",if=%s", bus);
> +            if (disk->src) {
> +                if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
> +                    /* QEMU only supports magic FAT format for now */
> +                    if (disk->driverType &&
> +                        STRNEQ(disk->driverType, "fat")) {
> +                        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> +                                         _("unsupported disk driver type for '%s'"),
> +                                         disk->driverType);
> +                        goto error;
> +                    }
> +                    if (!disk->readonly) {
> +                        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
> +                                         _("cannot create virtual FAT disks in read-write mode"));
> +                        goto error;
> +                    }
> +                    if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
> +                        virBufferVSprintf(&opt, "file=fat:floppy:%s,", disk->src);
> +                    else
> +                        virBufferVSprintf(&opt, "file=fat:%s,", disk->src);
> +                } else {
> +                    virBufferVSprintf(&opt, "file=%s,", disk->src);
> +                }
> +            }
> +            virBufferVSprintf(&opt, "if=%s", bus);
>              if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
>                  virBufferAddLit(&opt, ",media=cdrom");
>              virBufferVSprintf(&opt, ",index=%d", idx);
> @@ -1989,6 +2011,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
>                  disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
>                  virBufferAddLit(&opt, ",boot=on");
>              if (disk->driverType &&
> +                disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
>                  qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_FORMAT)
>                  virBufferVSprintf(&opt, ",format=%s", disk->driverType);
>              if (disk->serial &&
> @@ -2057,7 +2080,27 @@ int qemudBuildCommandLine(virConnectPtr conn,
>                  }
>              }
>  
> -            snprintf(file, PATH_MAX, "%s", disk->src);
> +            if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
> +                /* QEMU only supports magic FAT format for now */
> +                if (disk->driverType &&
> +                    STRNEQ(disk->driverType, "fat")) {
> +                    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
> +                                     _("unsupported disk driver type for '%s'"),
> +                                     disk->driverType);
> +                    goto error;
> +                }
> +                if (!disk->readonly) {
> +                    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
> +                                     _("cannot create virtual FAT disks in read-write mode"));
> +                    goto error;
> +                }
> +                if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
> +                    snprintf(file, PATH_MAX, "fat:floppy:%s", disk->src);
> +                else
> +                    snprintf(file, PATH_MAX, "fat:%s", disk->src);
> +            } else {
> +                snprintf(file, PATH_MAX, "%s", disk->src);
> +            }
>  
>              ADD_ARG_LIT(dev);
>              ADD_ARG_LIT(file);
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index bd838e6..255ba53 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -687,6 +687,9 @@ SELinuxSetSecurityLabel(virConnectPtr conn,
>  
>      if (secdef->imagelabel) {
>          for (i = 0 ; i < vm->def->ndisks ; i++) {
> +            /* XXX fixme - we need to recursively label the entriy tree :-( */
> +            if (vm->def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR)
> +                continue;
>              if (SELinuxSetSecurityImageLabel(conn, vm, vm->def->disks[i]) < 0)
>                  return -1;
>          }
> diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
> index d61e9e6..e370eb8 100644
> --- a/src/xen/xend_internal.c
> +++ b/src/xen/xend_internal.c
> @@ -5375,11 +5375,16 @@ xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
>          } else {
>              if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
>                  virBufferVSprintf(buf, "(uname 'file:%s')", def->src);
> -            } else {
> +            } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
>                  if (def->src[0] == '/')
>                      virBufferVSprintf(buf, "(uname 'phy:%s')", def->src);
>                  else
>                      virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", def->src);
> +            } else {
> +                virXendError(conn, VIR_ERR_CONFIG_UNSUPPORTED,
> +                             _("unsupported disk type %s"),
> +                             virDomainDiskTypeToString(def->type));
> +                return -1;
>              }
>          }
>      }
> diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
> index f833ce7..31cff12 100644
> --- a/src/xen/xm_internal.c
> +++ b/src/xen/xm_internal.c
> @@ -1973,9 +1973,19 @@ static int xenXMDomainConfigFormatDisk(virConnectPtr conn,
>              if (STREQ(disk->driverName, "tap"))
>                  virBufferVSprintf(&buf, "%s:", disk->driverType ? disk->driverType : "aio");
>          } else {
> -            virBufferVSprintf(&buf, "%s:",
> -                              disk->type == VIR_DOMAIN_DISK_TYPE_FILE ?
> -                              "file" : "phy");
> +            switch (disk->type) {
> +            case VIR_DOMAIN_DISK_TYPE_FILE:
> +                virBufferAddLit(&buf, "file:");
> +                break;
> +            case VIR_DOMAIN_DISK_TYPE_BLOCK:
> +                virBufferAddLit(&buf, "phy:");
> +                break;
> +            default:
> +                xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
> +                           _("unsupported disk type %s"),
> +                           virDomainDiskTypeToString(disk->type));
> +                goto cleanup;
> +            }
>          }
>          virBufferVSprintf(&buf, "%s", disk->src);
>      }
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom-empty.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom-empty.args
> index 1ef2602..1dd90d0 100644
> --- a/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom-empty.args
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-cdrom-empty.args
> @@ -1 +1 @@
> -LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -drive file=/dev/HostVG/QEMUGuest1,if=ide,index=0 -drive file=,if=ide,media=cdrom,index=2 -net none -serial none -parallel none -usb
> +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -drive file=/dev/HostVG/QEMUGuest1,if=ide,index=0 -drive if=ide,media=cdrom,index=2 -net none -serial none -parallel none -usb
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.args
> new file mode 100644
> index 0000000..da1163b
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.args
> @@ -0,0 +1 @@
> +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -drive file=fat:/var/somefiles,if=ide,index=0,boot=on -net none -serial none -parallel none -usb
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.xml
> new file mode 100644
> index 0000000..818ca93
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-fat.xml
> @@ -0,0 +1,24 @@
> +<domain type='qemu'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory>219200</memory>
> +  <currentMemory>219200</currentMemory>
> +  <vcpu>1</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu</emulator>
> +    <disk type='dir' device='disk'>
> +      <driver name='qemu' type='fat'/>
> +      <source dir='/var/somefiles'/>
> +      <target dev='hda' bus='ide'/>
> +      <readonly/>
> +    </disk>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.args b/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.args
> new file mode 100644
> index 0000000..4b4e3f4
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.args
> @@ -0,0 +1 @@
> +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot a -drive file=fat:floppy:/var/somefiles,if=floppy,index=0 -net none -serial none -parallel none -usb
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.xml b/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.xml
> new file mode 100644
> index 0000000..9e32b68
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-floppy-drive-fat.xml
> @@ -0,0 +1,24 @@
> +<domain type='qemu'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory>219200</memory>
> +  <currentMemory>219200</currentMemory>
> +  <vcpu>1</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='fd'/>
> +  </os>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu</emulator>
> +    <disk type='dir' device='floppy'>
> +      <driver name='qemu' type='fat'/>
> +      <source dir='/var/somefiles'/>
> +      <target dev='fda' bus='fdc'/>
> +      <readonly/>
> +    </disk>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> index c948379..677c5b4 100644
> --- a/tests/qemuxml2argvtest.c
> +++ b/tests/qemuxml2argvtest.c
> @@ -211,6 +211,10 @@ mymain(int argc, char **argv)
>              QEMUD_CMD_FLAG_DRIVE_BOOT);
>      DO_TEST("disk-drive-boot-cdrom", QEMUD_CMD_FLAG_DRIVE |
>              QEMUD_CMD_FLAG_DRIVE_BOOT);
> +    DO_TEST("floppy-drive-fat", QEMUD_CMD_FLAG_DRIVE |
> +            QEMUD_CMD_FLAG_DRIVE_BOOT | QEMUD_CMD_FLAG_DRIVE_FORMAT);
> +    DO_TEST("disk-drive-fat", QEMUD_CMD_FLAG_DRIVE |
> +            QEMUD_CMD_FLAG_DRIVE_BOOT | QEMUD_CMD_FLAG_DRIVE_FORMAT);
>      DO_TEST("disk-drive-fmt-qcow", QEMUD_CMD_FLAG_DRIVE |
>              QEMUD_CMD_FLAG_DRIVE_BOOT | QEMUD_CMD_FLAG_DRIVE_FORMAT);
>      DO_TEST("disk-drive-shared", QEMUD_CMD_FLAG_DRIVE |
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 25ef2ce..793900c 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -98,6 +98,8 @@ mymain(int argc, char **argv)
>      DO_TEST("disk-many");
>      DO_TEST("disk-xenvbd");
>      DO_TEST("disk-usb");
> +    DO_TEST("floppy-drive-fat");
> +    DO_TEST("disk-drive-fat");
>      DO_TEST("disk-drive-fmt-qcow");
>      DO_TEST("disk-drive-cache-v1-wt");
>      DO_TEST("disk-drive-cache-v1-wb");

  ACK, that's funky, and I guess this will stay a qemu only feature.
One thing I wonder about the semantic is what happen if the underlying
files get modified while QEmu tries to access that 'floppy'. I assume
"domain can crash an burn" is just fine

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list