From 0a4f7ab47c2997a8020c2ad29e01eab5f7cea578 Mon Sep 17 00:00:00 2001 From: Yunmi Ha Date: Mon, 2 Dec 2019 10:57:01 +0900 Subject: [PATCH] block: Improve stability of unmount - Using AddPowerOffWait/RemovePowerOffWait method of deviced. - Change unmount processing order Change-Id: I8754f1d3b732f15c5aa77a2233d918578e9c2aae Signed-off-by: Yunmi Ha --- src/block/block.c | 109 ++++++++++++++++++++++++++++++++++-------------------- src/block/utils.c | 34 ++++++++++++++++- src/block/utils.h | 1 + 3 files changed, 103 insertions(+), 41 deletions(-) diff --git a/src/block/block.c b/src/block/block.c index a718697..acbd1b2 100644 --- a/src/block/block.c +++ b/src/block/block.c @@ -78,6 +78,8 @@ #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */ #define SIGNAL_POWEROFF_STATE "ChangeState" +#define METHOD_ADD_POWEROFF_WAIT "AddPowerOffWait" +#define METHOD_REMOVE_POWEROFF_WAIT "RemovePowerOffWait" #define BLOCK_DEVICE_ADDED "DeviceAdded" #define BLOCK_DEVICE_REMOVED "DeviceRemoved" @@ -212,6 +214,7 @@ static fd_handler_h phandler; static bool block_control = false; static bool block_boot = false; static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER; +static bool add_poweroff_wait = false; /* Assume there is only one physical internal storage */ static int dev_internal = -1; @@ -228,6 +231,7 @@ static void remove_operation(struct block_device *bdev); static void check_removed(struct block_device *bdev, dd_list **queue, struct operation_queue **op); static bool check_unmount(struct block_device *bdev, dd_list **queue, struct operation_queue **op); static int change_mount_point(struct block_device *bdev, const char *mount_point); +static void terminate_threads(void); #define nullstr(x) (x ? x : "") static GVariant *block_data_to_gvariant(struct block_data *data, int flags); @@ -1389,52 +1393,40 @@ static int block_unmount(struct block_device *bdev, _I("Execute force unmount."); /* Force Unmount Scenario */ - while (1) { - switch (retry++) { - case 0: - /* Mobile specific: - * should unmount the below vconf key. */ - if ((data->block_type == BLOCK_MMC_DEV || - data->block_type == BLOCK_EXTENDEDSD_DEV) && - data->primary) { - /* At first, notify to other app - * who already access sdcard */ - _I("Notify to other app who already access sdcard."); - vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, - VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED); - } - break; - case 1: - /* Second, kill app with SIGTERM */ - _I("Kill app with SIGTERM."); - terminate_process(data->mount_point, false); - break; - case 2: - /* Last time, kill app with SIGKILL */ - _I("Kill app with SIGKILL."); - terminate_process(data->mount_point, true); - break; - default: - if (umount2(data->mount_point, MNT_DETACH) != 0) { - _I("Failed to unmount with lazy option: %d", - errno); - return -errno; - } - goto out; - } - /* it takes some seconds til other app completely clean up */ - time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER; + /* Mobile specific: + * should unmount the below vconf key. */ + if ((data->block_type == BLOCK_MMC_DEV || + data->block_type == BLOCK_EXTENDEDSD_DEV) && + data->primary) { + /* At first, notify to other app + * who already access sdcard */ + _I("Notify to other app who already access sdcard."); + vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS, + VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED); + } + + sync(); + if (umount2(data->mount_point, MNT_DETACH) != 0) { + _I("Failed to unmount with lazy option: %m"); + return -errno; + } + + time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER; + + while (retry++ < UNMOUNT_RETRY) { + _I("Kill app with SIGTERM."); + terminate_process(data->devnode, false); nanosleep(&time, NULL); - print_open_files(data->mount_point); + _I("Kill app with SIGKILL."); + terminate_process(data->devnode, true); + nanosleep(&time, NULL); - r = mmc_check_and_unmount(data->mount_point); - if (!r) { - _D("Success to unmount '%s'.", data->mount_point); + if (!is_in_use_partition(data->devnode)) break; - } } + sync(); out: data->state = BLOCK_UNMOUNT; @@ -2701,6 +2693,16 @@ static void booting_done(void) /* if there is the attached device, try to mount */ block_init_from_udev_enumerate(); + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_ADD_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_ADD_POWEROFF_WAIT" method."); + else + add_poweroff_wait = true; + block_boot = true; } @@ -2713,6 +2715,8 @@ static void block_poweroff(GDBusConnection *conn, gpointer data) { static int status = 0; + int ret; + if (status > 0) return; status = 1; @@ -2720,6 +2724,19 @@ static void block_poweroff(GDBusConnection *conn, /* unregister mmc uevent control routine */ unregister_udev_uevent_control(&uh); remove_whole_block_device(); + terminate_threads(); + + if (add_poweroff_wait) { + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_REMOVE_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method."); + else + add_poweroff_wait = false; + } } static void uevent_block_handler(struct udev_device *dev) @@ -3785,6 +3802,18 @@ static void block_exit(void *data) /* exit pipe */ pipe_exit(); + if (add_poweroff_wait) { + ret = dbus_handle_method_sync(DEVICED_BUS_NAME, + DEVICED_PATH_POWEROFF, + DEVICED_INTERFACE_POWEROFF, + METHOD_REMOVE_POWEROFF_WAIT, + NULL, NULL); + if (ret < 0) + _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method."); + else + add_poweroff_wait = false; + } + block_control = false; } diff --git a/src/block/utils.c b/src/block/utils.c index 909c8a4..1c283ba 100644 --- a/src/block/utils.c +++ b/src/block/utils.c @@ -16,7 +16,7 @@ * limitations under the License. */ - +#define _GNU_SOURCE #include #include #include @@ -127,6 +127,38 @@ int terminate_process(const char *partition, bool force) return run_child(argc, argv); } +//If no process accesses the partition, return false +//If at least one process access the partition, return true +bool is_in_use_partition(const char *partition) +{ + FILE *fp; + char *cmd = NULL; + char *line = NULL; + size_t len = 0; + bool ret = false; + + if (asprintf(&cmd, "/usr/bin/fuser -m %s", partition) < 0) { + _E("Failed to call asprintf: %m"); + return false; + } + + _D("cmd=%s\n", cmd); + fp = popen(cmd, "r"); + free(cmd); + if (fp == NULL) + return false; + + if (getline(&line, &len, fp) != -1) { + if (strtok(line, " ") != NULL) + ret = true; + } + + free(line); + pclose(fp); + + return ret; +} + int mount_check(const char *path) { int ret = false; diff --git a/src/block/utils.h b/src/block/utils.h index 23d058a..6c9f45f 100644 --- a/src/block/utils.h +++ b/src/block/utils.h @@ -25,6 +25,7 @@ int print_open_files(const char *mount_point); int terminate_process(const char *partition, bool force); +bool is_in_use_partition(const char *partition); int mount_check(const char *path); int umount_partition(const char *path, const bool force); -- 2.7.4