From: Martin Pitt Date: Sun, 19 Jun 2011 18:48:22 +0000 (+0200) Subject: Bug 34710 — CD-ROM polling failed due to O_EXCL flag X-Git-Tag: upstream/2.1.2~552 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2d0272eb3be71f6ee3f52c55a3d608764b675fb0;p=platform%2Fupstream%2Fudisks2.git Bug 34710 — CD-ROM polling failed due to O_EXCL flag Newer kernels (2.6.38+) support in-kernel polling of CD-ROM/SD card devices. udev 172 and later enable this feature by default: http://git.kernel.org/?p=linux/hotplug/udev.git;a=commitdiff;h=c5a41da949 That will also handle the eject button properly and send out remove uevents, which causes stale mounts to be cleaned up properly. In-kernel polling avoids the userspace race conditions with accessing the drive. If kernel polling is not supported or enabled, fall back to the previous method of unlocking the CD drive door right after mounting, to keep the hardware button working. --- diff --git a/src/device-private.h b/src/device-private.h index a6db7f2..e519083 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -59,6 +59,9 @@ struct DevicePrivate gboolean job_is_cancellable; double job_percentage; + gboolean checked_in_kernel_polling; + gboolean using_in_kernel_polling; + guint linux_md_poll_timeout_id; /* A list of current polling inhibitors (Inhibitor objects) */ diff --git a/src/device.c b/src/device.c index b30fe1c..c4b4ab3 100644 --- a/src/device.c +++ b/src/device.c @@ -6213,7 +6213,12 @@ filesystem_mount_completed_cb (DBusGMethodInvocation *context, update_info (device); drain_pending_changes (device, FALSE); - unlock_cd_tray (device); + /* If the kernel and device support sending EJECT_REQUEST change uevents + * and we use in-kernel polling, keep the door locked, as udev calls + * eject on pressing the button. Otherwise unlock it, to keep the + * hardware button working without userspace support */ + if (!device->priv->using_in_kernel_polling) + unlock_cd_tray (device); dbus_g_method_return (context, data->mount_point); } diff --git a/src/poller.c b/src/poller.c index 9517b5d..cc807d8 100644 --- a/src/poller.c +++ b/src/poller.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "poller.h" #include "device.h" @@ -304,6 +305,52 @@ poller_setup (int argc, /* ---------------------------------------------------------------------------------------------------- */ +static gboolean +check_in_kernel_polling (Device* d) +{ + /* only check once */ + if (!d->priv->checked_in_kernel_polling) + { + int poll_time; + int fd; + char c; + + d->priv->checked_in_kernel_polling = TRUE; + + poll_time = g_udev_device_get_sysfs_attr_as_int (d->priv->d, "events_poll_msecs"); +#ifdef POLL_SHOW_DEBUG + g_print("**** POLLER (%d): per-device poll time for %s: %i\n", getpid (), d->priv->device_file, poll_time); +#endif + + if (poll_time >= 0) + { + d->priv->using_in_kernel_polling = (poll_time > 0); + goto out; + } + + /* -1 means using global polling interval, so check the global default */ + /* check global default */ + fd = open("/sys/module/block/parameters/events_dfl_poll_msecs", O_RDONLY); + if (fd > 0) + { + if (read (fd, &c, 1) > 0) + { +#ifdef POLL_SHOW_DEBUG + g_print("**** POLLER (%d): global poll time first char: %c\n", getpid (), c); +#endif + /* if this is positive, we use in-kernel polling */ + d->priv->using_in_kernel_polling = (c != '0' && c != '-'); + } + close (fd); + } + } + +out: + return d->priv->using_in_kernel_polling; +} + +/* ---------------------------------------------------------------------------------------------------- */ + void poller_set_devices (GList *devices) { @@ -320,6 +367,14 @@ poller_set_devices (GList *devices) { Device *device = DEVICE (l->data); + if (check_in_kernel_polling (device)) + { +#ifdef POLL_SHOW_DEBUG + g_print("**** POLLER (%d): Kernel is polling %s already, ignoring\n", getpid (), device->priv->device_file); +#endif + continue; + } + device_array[n++] = device->priv->device_file; }