From: David Zeuthen Date: Tue, 25 Mar 2008 07:35:22 +0000 (-0400) Subject: forcibly unmount devices mounted by ourselves on unsafe media removal X-Git-Tag: upstream/2.1.2~1051 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2b6c1899079ab9bac5b73e82c5a10f6c3e3fee22;p=platform%2Fupstream%2Fudisks2.git forcibly unmount devices mounted by ourselves on unsafe media removal --- diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index 78b6129..d4143d8 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -167,8 +167,8 @@ devkit_disks_daemon_reset_killtimer (DevkitDisksDaemon *daemon) /*--------------------------------------------------------------------------------------------------------------*/ -static void -update_mount_state (DevkitDisksDaemon *daemon, GList *devices) +void +devkit_disks_daemon_local_update_mount_state (DevkitDisksDaemon *daemon, GList *devices, gboolean emit_changed) { GList *l; GList *mounts; @@ -206,7 +206,7 @@ update_mount_state (DevkitDisksDaemon *daemon, GList *devices) /* same mount path; no changes */ } else { /* device was just mounted... or the mount path changed */ - devkit_disks_device_local_set_mounted (device, mount_path); + devkit_disks_device_local_set_mounted (device, mount_path, emit_changed); } /* we're mounted so remove from list of devices (see below) */ @@ -236,7 +236,7 @@ update_mount_state (DevkitDisksDaemon *daemon, GList *devices) device_mount_path = devkit_disks_device_local_get_mount_path (device); if (device_mount_path != NULL) { - devkit_disks_device_local_set_unmounted (device); + devkit_disks_device_local_set_unmounted (device, emit_changed); } } @@ -564,7 +564,6 @@ static void device_add (DevkitDisksDaemon *daemon, const char *native_path, gboolean emit_event) { DevkitDisksDevice *device; - GList *l; device = g_hash_table_lookup (daemon->priv->map_native_path_to_device, native_path); if (device != NULL) { @@ -575,11 +574,6 @@ device_add (DevkitDisksDaemon *daemon, const char *native_path, gboolean emit_ev device = devkit_disks_device_new (daemon, native_path); if (device != NULL) { - /* update whether device is mounted */ - l = g_list_prepend (NULL, device); - update_mount_state (daemon, l); - g_list_free (l); - /* only take a weak ref; the device will stay on the bus until * it's unreffed. So if we ref it, it'll never go away. Stupid * dbus-glib, no cookie for you. @@ -742,7 +736,7 @@ mounts_changed (GUnixMountMonitor *monitor, gpointer user_data) GList *devices; devices = g_hash_table_get_values (daemon->priv->map_native_path_to_device); - update_mount_state (daemon, devices); + devkit_disks_daemon_local_update_mount_state (daemon, devices, TRUE); g_list_free (devices); } diff --git a/src/devkit-disks-daemon.h b/src/devkit-disks-daemon.h index 075ce81..d22696f 100644 --- a/src/devkit-disks-daemon.h +++ b/src/devkit-disks-daemon.h @@ -84,6 +84,11 @@ gboolean devkit_disks_damon_local_check_auth (DevkitDisksD PolKitCaller *pk_caller, const char *action_id, DBusGMethodInvocation *context); + +void devkit_disks_daemon_local_update_mount_state (DevkitDisksDaemon *daemon, + GList *devices, + gboolean emit_changed); + /* exported methods */ gboolean devkit_disks_daemon_inhibit_shutdown (DevkitDisksDaemon *daemon, diff --git a/src/devkit-disks-device.c b/src/devkit-disks-device.c index 203c8cd..56cfacf 100644 --- a/src/devkit-disks-device.c +++ b/src/devkit-disks-device.c @@ -93,6 +93,8 @@ devkit_disks_device_create_filesystem_internal (DevkitDisksDevice *device, gpointer hook_user_data, DBusGMethodInvocation *context); +static void force_unmount (DevkitDisksDevice *device, gboolean remove_dir_on_unmount); + enum { PROP_0, @@ -1121,6 +1123,7 @@ update_info (DevkitDisksDevice *device) char *path; GDir *dir; const char *name; + GList *l; ret = FALSE; info = NULL; @@ -1235,6 +1238,11 @@ update_info (DevkitDisksDevice *device) update_slaves (device); + /* update whether device is mounted */ + l = g_list_prepend (NULL, device); + devkit_disks_daemon_local_update_mount_state (device->priv->daemon, l, FALSE); + g_list_free (l); + ret = TRUE; out: @@ -1272,6 +1280,20 @@ void devkit_disks_device_removed (DevkitDisksDevice *device) { update_slaves (device); + + /* if this device was mounted by us, then forcibly unmount it + * + * This is the normally the path where the enclosing device is + * removed. Compare with devkit_disks_device_changed() for the + * other path. + */ + if (device->priv->info.device_is_mounted && device->priv->info.device_mount_path != NULL) { + gboolean remove_dir_on_unmount; + if (mounts_file_has_device (device, NULL, &remove_dir_on_unmount)) { + g_warning ("Force unmounting device %s", device->priv->info.device_file); + force_unmount (device, remove_dir_on_unmount); + } + } } DevkitDisksDevice * @@ -1343,6 +1365,48 @@ devkit_disks_device_changed (DevkitDisksDevice *device) /* TODO: fix up update_info to return TRUE iff something has changed */ if (update_info (device)) emit_changed (device); + + /* Check if media was removed. If so, we need to forcibly unmount the device + * or all the partitions of the device + * + * This is the normally the path where the media is removed but the enclosing + * device is still present. Compare with devkit_disks_device_removed() for + * the other path. + */ + if (!device->priv->info.device_is_media_available) { + gboolean remove_dir_on_unmount; + + if (device->priv->info.device_is_mounted && device->priv->info.device_mount_path != NULL) { + if (mounts_file_has_device (device, NULL, &remove_dir_on_unmount)) { + g_warning ("Force unmounting device %s", device->priv->info.device_file); + force_unmount (device, remove_dir_on_unmount); + } + } else { + GList *l; + GList *devices; + + /* check all partitions */ + devices = devkit_disks_daemon_local_get_all_devices (device->priv->daemon); + for (l = devices; l != NULL; l = l->next) { + DevkitDisksDevice *d = DEVKIT_DISKS_DEVICE (l->data); + + if (d->priv->info.device_is_partition && + d->priv->info.partition_slave != NULL && + strcmp (d->priv->info.partition_slave, device->priv->object_path) == 0) { + + if (d->priv->info.device_is_mounted && + d->priv->info.device_mount_path != NULL) { + if (mounts_file_has_device (d, NULL, &remove_dir_on_unmount)) { + g_warning ("Force unmounting device %s", + d->priv->info.device_file); + force_unmount (d, remove_dir_on_unmount); + } + } + + } + } /* for all devices */ + } + } } /*--------------------------------------------------------------------------------------------------------------*/ @@ -1444,16 +1508,20 @@ devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device) } void -devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, const char *mount_path) +devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, + const char *mount_path, + gboolean emit_changed_signal) { g_free (device->priv->info.device_mount_path); device->priv->info.device_mount_path = g_strdup (mount_path); device->priv->info.device_is_mounted = TRUE; - emit_changed (device); + if (emit_changed_signal) + emit_changed (device); } void -devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device) +devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device, + gboolean emit_changed_signal) { char *mount_path; gboolean remove_dir_on_unmount; @@ -1479,7 +1547,8 @@ devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device) } } - emit_changed (device); + if (emit_changed_signal) + emit_changed (device); g_free (mount_path); } @@ -2218,7 +2287,7 @@ mount_completed_cb (DBusGMethodInvocation *context, if (WEXITSTATUS (status) == 0 && !job_was_cancelled) { if (!data->is_remount) { - devkit_disks_device_local_set_mounted (device, data->mount_point); + devkit_disks_device_local_set_mounted (device, data->mount_point, TRUE); mounts_file_add (device, uid, data->remove_dir_on_unmount); } dbus_g_method_return (context, data->mount_point); @@ -2487,7 +2556,7 @@ unmount_completed_cb (DBusGMethodInvocation *context, char *mount_path = user_data; if (WEXITSTATUS (status) == 0 && !job_was_cancelled) { - devkit_disks_device_local_set_unmounted (device); + devkit_disks_device_local_set_unmounted (device, TRUE); mounts_file_remove (device, mount_path); dbus_g_method_return (context); } else { @@ -4275,3 +4344,65 @@ out: } /*--------------------------------------------------------------------------------------------------------------*/ + +static void +force_unmount_completed_cb (DBusGMethodInvocation *context, + DevkitDisksDevice *device, + PolKitCaller *pk_caller, + gboolean job_was_cancelled, + int status, + const char *stderr, + const char *stdout, + gpointer user_data) +{ + const char *mount_path = user_data; + char *touch_str; + + if (WEXITSTATUS (status) == 0 && !job_was_cancelled) { + + g_warning ("Successfully force unmounted device %s", device->priv->info.device_file); + devkit_disks_device_local_set_unmounted (device, TRUE); + mounts_file_remove (device, mount_path); + + /* TODO: when we add polling, this can probably be removed. I have no idea why hal's + * poller don't cause the kernel to revalidate the (missing) media + */ + touch_str = g_strdup_printf ("touch %s", device->priv->info.device_file); + g_spawn_command_line_async (touch_str, NULL); + g_free (touch_str); + } else { + g_warning ("force unmount failed: %s", stderr); + } +} + +static void +force_unmount (DevkitDisksDevice *device, gboolean remove_dir_on_unmount) +{ + int n; + char *argv[16]; + GError *error; + + n = 0; + argv[n++] = "umount"; + /* on Linux, we only have lazy unmount for now */ + argv[n++] = "-l"; + argv[n++] = device->priv->info.device_mount_path; + argv[n++] = NULL; + + error = NULL; + if (!job_new (NULL, + "ForceUnmount", + FALSE, + device, + NULL, + argv, + NULL, + force_unmount_completed_cb, + g_strdup (device->priv->info.device_mount_path), + g_free)) { + g_warning ("Couldn't spawn unmount for force unmounting: %s", error->message); + g_error_free (error); + } +} + +/*--------------------------------------------------------------------------------------------------------------*/ diff --git a/src/devkit-disks-device.h b/src/devkit-disks-device.h index 198fbf3..36bd74c 100644 --- a/src/devkit-disks-device.h +++ b/src/devkit-disks-device.h @@ -90,16 +90,19 @@ GList *devkit_disks_enumerate_native_paths (void); /* local methods */ -const char *devkit_disks_device_local_get_object_path (DevkitDisksDevice *device); -const char *devkit_disks_device_local_get_native_path (DevkitDisksDevice *device); +const char *devkit_disks_device_local_get_object_path (DevkitDisksDevice *device); +const char *devkit_disks_device_local_get_native_path (DevkitDisksDevice *device); -const char *devkit_disks_device_local_get_device_file (DevkitDisksDevice *device); -const char *devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device); +const char *devkit_disks_device_local_get_device_file (DevkitDisksDevice *device); +const char *devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device); -void devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, const char *mount_path); -void devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device); +void devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, + const char *mount_path, + gboolean emit_changed_signal); +void devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device, + gboolean emit_changed_signal); -gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device); +gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device); gboolean devkit_disks_device_local_partitions_are_busy (DevkitDisksDevice *device); /* exported methods */ diff --git a/src/mounts-file.c b/src/mounts-file.c index 4fdb035..4d3814d 100644 --- a/src/mounts-file.c +++ b/src/mounts-file.c @@ -191,9 +191,6 @@ mounts_file_remove (DevkitDisksDevice *device, const char *mount_path) device_file_escaped = NULL; mount_path_escaped = NULL; - g_return_if_fail (!device->priv->info.device_is_mounted); - g_return_if_fail (device->priv->info.device_mount_path == NULL); - device_file_escaped = g_uri_escape_string (device->priv->info.device_file, NULL, TRUE); mount_path_escaped = g_uri_escape_string (mount_path, NULL, TRUE);