We need to use O_EXCL in order to suppress event generation in the kernel. However, O_EXCL by definition fails when the CD-ROM drive is mounted. Automatically unmount it when it is passed through to the guest.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- Makefile.objs | 3 + block.c | 7 +++ block/raw-posix-udisks.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ block/raw-posix-udisks.h | 39 +++++++++++++++++ block/raw-posix.c | 17 ++++++- 5 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 block/raw-posix-udisks.c create mode 100644 block/raw-posix-udisks.h diff --git a/Makefile.objs b/Makefile.objs index ec35320..a30a80d 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -41,6 +41,9 @@ block-nested-$(CONFIG_POSIX) += raw-posix.o block-nested-$(CONFIG_LIBISCSI) += iscsi.o block-nested-$(CONFIG_CURL) += curl.o block-nested-$(CONFIG_RBD) += rbd.o +ifeq ($(CONFIG_DBUS),y) +block-nested-$(CONFIG_LINUX) += raw-posix-udisks.o +endif block-obj-y += $(addprefix block/, $(block-nested-y)) diff --git a/block.c b/block.c index 3621d11..6dad6b5 100644 --- a/block.c +++ b/block.c @@ -42,6 +42,10 @@ #endif #endif +#ifdef CONFIG_DBUS +#include <glib-object.h> +#endif + #ifdef _WIN32 #include <windows.h> #endif @@ -3278,6 +3282,9 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, void bdrv_init(void) { module_call_init(MODULE_INIT_BLOCK); +#ifdef CONFIG_DBUS + g_type_init(); +#endif } void bdrv_init_with_whitelist(void) diff --git a/block/raw-posix-udisks.c b/block/raw-posix-udisks.c new file mode 100644 index 0000000..3ab3cbe --- /dev/null +++ b/block/raw-posix-udisks.c @@ -0,0 +1,105 @@ +/* + * Udisks interaction for CD-ROM unmounting + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonz...@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include "block/raw-posix-udisks.h" + +static void udisks_find_device_by_device_file(DBusGConnection *bus, + const char *path, + char **object_path, + GError **error) +{ + DBusGProxy *proxy; + proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.UDisks", + "/org/freedesktop/UDisks", + "org.freedesktop.UDisks"); + dbus_g_proxy_call (proxy, "FindDeviceByDeviceFile", error, + G_TYPE_STRING, path, G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, object_path, G_TYPE_INVALID); + g_object_unref (proxy); +} + +static void udisks_device_filesystem_unmount(DBusGConnection *bus, + const char *object_path, + GError **error) +{ + DBusGProxy *proxy; + proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.UDisks", + object_path, + "org.freedesktop.UDisks.Device"); + dbus_g_proxy_call (proxy, "FilesystemUnmount", error, + G_TYPE_STRV, NULL, G_TYPE_INVALID, + G_TYPE_INVALID); + g_object_unref (proxy); +} + +int +udisks_unmount (const char *path) +{ + DBusGConnection *bus; + char *object_path; + GError *error; + int ret; + + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", error->message); + ret = -EACCES; + goto out; + } + + udisks_find_device_by_device_file(bus, path, &object_path, &error); + if (error || !object_path) { + ret = -ENODEV; + goto out; + } + + udisks_device_filesystem_unmount(bus, object_path, &error); + if (error) { + g_print ("Unmount failed: %s\n", error->message); + ret = -EBUSY; + goto out; + } + + ret = 0; /* success */ +out: + g_free (object_path); + if (error != NULL) { + g_error_free (error); + } + if (bus != NULL) { + dbus_g_connection_unref (bus); + } + return ret; +} diff --git a/block/raw-posix-udisks.h b/block/raw-posix-udisks.h new file mode 100644 index 0000000..47dd638 --- /dev/null +++ b/block/raw-posix-udisks.h @@ -0,0 +1,39 @@ +/* + * Udisks interaction for CD-ROM unmounting + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonz...@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_UDISKS_H +#define QEMU_UDISKS_H 1 + +#include "config-host.h" +#include <errno.h> + +#ifdef CONFIG_DBUS +int udisks_unmount (const char *path); +#else +static int udisks_unmount (const char *path) { return -ENOSYS; } +#endif + +#endif diff --git a/block/raw-posix.c b/block/raw-posix.c index 1b51bd4..c61d07a 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -28,6 +28,7 @@ #include "block_int.h" #include "module.h" #include "block/raw-posix-aio.h" +#include "block/raw-posix-udisks.h" #ifdef CONFIG_COCOA #include <paths.h> @@ -1069,15 +1070,25 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; int rc; + int i; s->type = FTYPE_CD; /* open will not fail even if no CD is inserted, so add O_NONBLOCK. First * try with O_EXCL to see whether the CD is mounted. */ - rc = raw_open_common(bs, filename, flags, O_NONBLOCK | O_EXCL); - if (rc < 0 && rc != -EBUSY) { - return rc; + for (i = 0; i < 20; i++) { + rc = raw_open_common(bs, filename, flags, O_NONBLOCK | O_EXCL); + if (rc == 0) { + break; + } + if (rc != -EBUSY) { + return rc; + } + if (i == 0 && udisks_unmount(filename) < 0) { + break; + } + usleep(100 * 1000); } s->cd.manage_door = false; -- 1.7.7.6