diff options
Diffstat (limited to 'vold/volmgr.c')
| -rw-r--r-- | vold/volmgr.c | 1247 |
1 files changed, 0 insertions, 1247 deletions
diff --git a/vold/volmgr.c b/vold/volmgr.c deleted file mode 100644 index a635b8e..0000000 --- a/vold/volmgr.c +++ /dev/null @@ -1,1247 +0,0 @@ - -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <dirent.h> -#include <unistd.h> -#include <sched.h> - -#include <sys/mount.h> - -#include <cutils/config_utils.h> -#include <cutils/properties.h> - -#include "vold.h" -#include "volmgr.h" -#include "blkdev.h" -#include "ums.h" -#include "format.h" -#include "devmapper.h" - -#include "volmgr_ext3.h" -#include "volmgr_vfat.h" - -#define DEBUG_VOLMGR 0 - -static volume_t *vol_root = NULL; -static boolean safe_mode = true; - -static struct volmgr_fstable_entry fs_table[] = { -// { "ext3", ext_identify, ext_check, ext_mount , true }, - { "vfat", vfat_identify, vfat_check, vfat_mount , false }, - { NULL, NULL, NULL, NULL , false} -}; - -struct _volume_state_event_map { - volume_state_t state; - char *event; - char *property_val; -}; - -static struct _volume_state_event_map volume_state_strings[] = { - { volstate_unknown, "volstate_unknown:", "unknown" }, - { volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA }, - { volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED }, - { volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING }, - { volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED }, - { volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO }, - { volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL }, - { volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED }, - { volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS }, - { volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS }, - { 0, NULL, NULL } -}; - - -static int volmgr_readconfig(char *cfg_path); -static int volmgr_config_volume(cnode *node); -static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy); -static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev); -static int _volmgr_start(volume_t *vol, blkdev_t *dev); -static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev); -static void *volmgr_start_fs_thread(void *arg); -static void volmgr_start_fs_thread_sighandler(int signo); -static void volume_setstate(volume_t *vol, volume_state_t state); -static char *conv_volstate_to_eventstr(volume_state_t state); -static char *conv_volstate_to_propstr(volume_state_t state); -static int volume_send_state(volume_t *vol); -static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg); -static int _volmgr_enable_ums(volume_t *); -static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg), boolean emit_statechange); -static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange); -static void _cb_volume_stopped_for_eject(volume_t *v, void *arg); -static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg); -static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev); -static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg); -static void volmgr_reaper_thread_sighandler(int signo); -static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path); -static int volmgr_send_eject_request(volume_t *v); -static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked); - -static boolean _mountpoint_mounted(char *mp) -{ - char device[256]; - char mount_path[256]; - char rest[256]; - FILE *fp; - char line[1024]; - - if (!(fp = fopen("/proc/mounts", "r"))) { - LOGE("Error opening /proc/mounts (%s)", strerror(errno)); - return false; - } - - while(fgets(line, sizeof(line), fp)) { - line[strlen(line)-1] = '\0'; - sscanf(line, "%255s %255s %255s\n", device, mount_path, rest); - if (!strcmp(mount_path, mp)) { - fclose(fp); - return true; - } - - } - - fclose(fp); - return false; -} - -/* - * Public functions - */ - -int volmgr_set_volume_key(char *mount_point, unsigned char *key) -{ - volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - - if (!v) - return -ENOENT; - - if (v->media_type != media_devmapper) { - LOGE("Cannot set key on a non devmapper volume"); - pthread_mutex_unlock(&v->lock); - return -EINVAL; - } - - memcpy(v->dm->key, key, sizeof(v->dm->key)); - pthread_mutex_unlock(&v->lock); - return 0; -} - -int volmgr_format_volume(char *mount_point) -{ - int rc; - volume_t *v; - - LOG_VOL("volmgr_format_volume(%s):", mount_point); - - v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - - if (!v) - return -ENOENT; - - if (v->state == volstate_mounted || - v->state == volstate_mounted_ro || - v->state == volstate_ums || - v->state == volstate_checking) { - LOGE("Can't format '%s', currently in state %d", mount_point, v->state); - pthread_mutex_unlock(&v->lock); - return -EBUSY; - } else if (v->state == volstate_nomedia && - v->media_type != media_devmapper) { - LOGE("Can't format '%s', (no media)", mount_point); - pthread_mutex_unlock(&v->lock); - return -ENOMEDIUM; - } - - // XXX:Reject if the underlying source media is not present - - if (v->media_type == media_devmapper) { - if ((rc = devmapper_genesis(v->dm)) < 0) { - LOGE("devmapper genesis failed for %s (%d)", mount_point, rc); - pthread_mutex_unlock(&v->lock); - return rc; - } - } else { - if ((rc = initialize_mbr(v->dev->disk)) < 0) { - LOGE("MBR init failed for %s (%d)", mount_point, rc); - pthread_mutex_unlock(&v->lock); - return rc; - } - } - - volume_setstate(v, volstate_formatting); - pthread_mutex_unlock(&v->lock); - return rc; -} - -int volmgr_bootstrap(void) -{ - int rc; - - if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) { - LOGE("Unable to process config"); - return rc; - } - - /* - * Check to see if any of our volumes is mounted - */ - volume_t *v = vol_root; - while (v) { - if (_mountpoint_mounted(v->mount_point)) { - LOGW("Volume '%s' already mounted at startup", v->mount_point); - v->state = volstate_mounted; - } - v = v->next; - } - - return 0; -} - -int volmgr_safe_mode(boolean enable) -{ - if (enable == safe_mode) - return 0; - - safe_mode = enable; - - volume_t *v = vol_root; - int rc; - - while (v) { - pthread_mutex_lock(&v->lock); - if (v->state == volstate_mounted && v->fs) { - rc = v->fs->mount_fn(v->dev, v, safe_mode); - if (!rc) { - LOGI("Safe mode %s on %s", (enable ? "enabled" : "disabled"), v->mount_point); - } else { - LOGE("Failed to %s safe-mode on %s (%s)", - (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc)); - } - } - - pthread_mutex_unlock(&v->lock); - v = v->next; - } - - return 0; -} - -int volmgr_send_states(void) -{ - volume_t *vol_scan = vol_root; - int rc; - - while (vol_scan) { - pthread_mutex_lock(&vol_scan->lock); - if ((rc = volume_send_state(vol_scan)) < 0) { - LOGE("Error sending state to framework (%d)", rc); - } - pthread_mutex_unlock(&vol_scan->lock); - vol_scan = vol_scan->next; - break; // XXX: - } - - return 0; -} - -/* - * Called when a block device is ready to be - * evaluated by the volume manager. - */ -int volmgr_consider_disk(blkdev_t *dev) -{ - volume_t *vol; - - if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true))) - return 0; - - pthread_mutex_lock(&vol->lock); - - if (vol->state == volstate_mounted) { - LOGE("Volume %s already mounted (did we just crash?)", vol->mount_point); - pthread_mutex_unlock(&vol->lock); - return 0; - } - - int rc = _volmgr_consider_disk_and_vol(vol, dev); - pthread_mutex_unlock(&vol->lock); - return rc; -} - -int volmgr_start_volume_by_mountpoint(char *mount_point) -{ - volume_t *v; - - v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - if (!v) - return -ENOENT; - - if (v->media_type == media_devmapper) { - if (devmapper_start(v->dm) < 0) { - LOGE("volmgr failed to start devmapper volume '%s'", - v->mount_point); - } - } else if (v->media_type == media_mmc) { - if (!v->dev) { - LOGE("Cannot start volume '%s' (volume is not bound)", mount_point); - pthread_mutex_unlock(&v->lock); - return -ENOENT; - } - - if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) { - LOGE("volmgr failed to start volume '%s'", v->mount_point); - } - } - - pthread_mutex_unlock(&v->lock); - return 0; -} - -static void _cb_volstopped_for_devmapper_teardown(volume_t *v, void *arg) -{ - devmapper_stop(v->dm); - volume_setstate(v, volstate_nomedia); - pthread_mutex_unlock(&v->lock); -} - -int volmgr_stop_volume_by_mountpoint(char *mount_point) -{ - int rc; - volume_t *v; - - v = volmgr_lookup_volume_by_mountpoint(mount_point, true); - if (!v) - return -ENOENT; - - if (v->state == volstate_mounted) - volmgr_send_eject_request(v); - - if (v->media_type == media_devmapper) - rc = volmgr_shutdown_volume(v, _cb_volstopped_for_devmapper_teardown, false); - else - rc = volmgr_shutdown_volume(v, NULL, true); - - /* - * If shutdown returns -EINPROGRESS, - * do *not* release the lock as - * it is now owned by the reaper thread - */ - if (rc != -EINPROGRESS) { - if (rc) - LOGE("unable to shutdown volume '%s'", v->mount_point); - pthread_mutex_unlock(&v->lock); - } - return 0; -} - -int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *)) -{ - LOG_VOL("Volmgr notified of %d:%d eject", dev->major, dev->minor); - - volume_t *v; - int rc; - - // XXX: Partitioning support is going to need us to stop *all* - // devices in this volume - if (!(v = volmgr_lookup_volume_by_dev(dev))) { - if (cb) - cb(dev); - return 0; - } - - pthread_mutex_lock(&v->lock); - - volume_state_t old_state = v->state; - - if (v->state == volstate_mounted || - v->state == volstate_ums || - v->state == volstate_checking) { - - volume_setstate(v, volstate_badremoval); - - /* - * Stop any devmapper volumes which - * are using us as a source - * XXX: We may need to enforce stricter - * order here - */ - volume_t *dmvol = vol_root; - while (dmvol) { - if ((dmvol->media_type == media_devmapper) && - (dmvol->dm->src_type == dmsrc_loopback) && - (!strncmp(dmvol->dm->type_data.loop.loop_src, - v->mount_point, strlen(v->mount_point)))) { - - pthread_mutex_lock(&dmvol->lock); - if (dmvol->state != volstate_nomedia) { - rc = volmgr_shutdown_volume(dmvol, _cb_volstopped_for_devmapper_teardown, false); - if (rc != -EINPROGRESS) { - if (rc) - LOGE("unable to shutdown volume '%s'", v->mount_point); - pthread_mutex_unlock(&dmvol->lock); - } - } else - pthread_mutex_unlock(&dmvol->lock); - } - dmvol = dmvol->next; - } - - } else if (v->state == volstate_formatting) { - /* - * The device is being ejected due to - * kernel disk revalidation. - */ - LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)", - dev->major, dev->minor); - if (cb) - cb(dev); - pthread_mutex_unlock(&v->lock); - return 0; - } else - volume_setstate(v, volstate_nomedia); - - if (old_state == volstate_ums) { - ums_disable(v->ums_path); - pthread_mutex_unlock(&v->lock); - } else { - int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false); - if (rc != -EINPROGRESS) { - if (rc) - LOGE("unable to shutdown volume '%s'", v->mount_point); - pthread_mutex_unlock(&v->lock); - } - } - return 0; -} - -static void _cb_volume_stopped_for_eject(volume_t *v, void *arg) -{ - void (* eject_cb) (blkdev_t *) = arg; - -#if DEBUG_VOLMGR - LOG_VOL("Volume %s has been stopped for eject", v->mount_point); -#endif - - if (eject_cb) - eject_cb(v->dev); - v->dev = NULL; // Clear dev because its being ejected -} - -/* - * Instructs the volume manager to enable or disable USB mass storage - * on any volumes configured to use it. - */ -int volmgr_enable_ums(boolean enable) -{ - volume_t *v = vol_root; - - while(v) { - if (v->ums_path) { - int rc; - - if (enable) { - pthread_mutex_lock(&v->lock); - if (v->state == volstate_mounted) - volmgr_send_eject_request(v); - else if (v->state == volstate_ums || v->state == volstate_nomedia) { - pthread_mutex_unlock(&v->lock); - goto next_vol; - } - - // Stop the volume, and enable UMS in the callback - rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false); - if (rc != -EINPROGRESS) { - if (rc) - LOGE("unable to shutdown volume '%s'", v->mount_point); - pthread_mutex_unlock(&v->lock); - } - } else { - // Disable UMS - pthread_mutex_lock(&v->lock); - if (v->state != volstate_ums) { - pthread_mutex_unlock(&v->lock); - goto next_vol; - } - - if ((rc = ums_disable(v->ums_path)) < 0) { - LOGE("unable to disable ums on '%s'", v->mount_point); - pthread_mutex_unlock(&v->lock); - continue; - } - - LOG_VOL("Kick-starting volume %d:%d after UMS disable", - v->dev->disk->major, v->dev->disk->minor); - // Start volume - if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) { - LOGE("volmgr failed to consider disk %d:%d", - v->dev->disk->major, v->dev->disk->minor); - } - pthread_mutex_unlock(&v->lock); - } - } - next_vol: - v = v->next; - } - return 0; -} - -/* - * Static functions - */ - -static int volmgr_send_eject_request(volume_t *v) -{ - return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point); -} - -// vol->lock must be held! -static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev) -{ - int rc = 0; - -#if DEBUG_VOLMGR - LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point, - dev->major, dev->minor); -#endif - - if (vol->state == volstate_unknown || - vol->state == volstate_mounted || - vol->state == volstate_mounted_ro) { - LOGE("Cannot consider volume '%s' because it is in state '%d", - vol->mount_point, vol->state); - return -EADDRINUSE; - } - - if (vol->state == volstate_formatting) { - LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'", - dev->devpath, vol->mount_point); - /* - * Since we only support creating 1 partition (right now), - * we can just lookup the target by devno - */ - blkdev_t *part; - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + 1); - else - part = blkdev_lookup_by_devno(dev->major, 1); - if (!part) { - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor)); - else - part = blkdev_lookup_by_devno(dev->major, 0); - if (!part) { - LOGE("Unable to find device to format"); - return -ENODEV; - } - } - - if ((rc = format_partition(part, - vol->media_type == media_devmapper ? - FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) { - LOGE("format failed (%d)", rc); - return rc; - } - - } - - LOGI("Evaluating dev '%s' for mountable filesystems for '%s'", - dev->devpath, vol->mount_point); - - if (dev->nr_parts == 0) { - rc = _volmgr_start(vol, dev); -#if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point, - dev->major, dev->minor, rc); -#endif - } else { - /* - * Device has multiple partitions - * This is where interesting partition policies could be implemented. - * For now just try them in sequence until one succeeds - */ - - rc = -ENODEV; - int i; - for (i = 0; i < dev->nr_parts; i++) { - blkdev_t *part; - if (vol->media_type == media_mmc) - part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + (i+1)); - else - part = blkdev_lookup_by_devno(dev->major, (i+1)); - if (!part) { - LOGE("Error - unable to lookup partition for blkdev %d:%d", - dev->major, dev->minor); - continue; - } - rc = _volmgr_start(vol, part); -#if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", - vol->mount_point, part->major, part->minor, rc); -#endif - if (!rc || rc == -EBUSY) - break; - } - - if (rc == -ENODEV) { - // Assert to make sure each partition had a backing blkdev - LOGE("Internal consistency error"); - return 0; - } - } - - if (rc == -ENODATA) { - LOGE("Device %d:%d contains no usable filesystems", - dev->major, dev->minor); - rc = 0; - } - - return rc; -} - -static void volmgr_reaper_thread_sighandler(int signo) -{ - LOGE("Volume reaper thread got signal %d", signo); -} - -static void __reaper_cleanup(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - if (vol->worker_args.reaper_args.cb) - vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg); - - vol->worker_running = false; - - // Wake up anyone that was waiting on this thread - pthread_mutex_unlock(&vol->worker_sem); - - // Unlock the volume - pthread_mutex_unlock(&vol->lock); -} - -static void *volmgr_reaper_thread(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - pthread_cleanup_push(__reaper_cleanup, arg); - - vol->worker_running = true; - vol->worker_pid = getpid(); - - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = volmgr_reaper_thread_sighandler; - sigaction(SIGUSR1, &actions, NULL); - - LOGW("Reaper here - working on %s", vol->mount_point); - - boolean send_sig_kill = false; - int i, rc; - - for (i = 0; i < 10; i++) { - errno = 0; - rc = umount(vol->mount_point); - LOGW("volmngr reaper umount(%s) attempt %d (%s)", - vol->mount_point, i + 1, strerror(errno)); - if (!rc) - break; - if (rc && (errno == EINVAL || errno == ENOENT)) { - rc = 0; - break; - } - sleep(1); - if (i >= 4) { - KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0); - if (!send_sig_kill) - send_sig_kill = true; - } - } - - if (!rc) { - LOGI("Reaper sucessfully unmounted %s", vol->mount_point); - vol->fs = NULL; - volume_setstate(vol, volstate_unmounted); - } else { - LOGE("Unable to unmount!! (%d)", rc); - } - - out: - pthread_cleanup_pop(1); - pthread_exit(NULL); - return NULL; -} - -// vol->lock must be held! -static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg) -{ - - if (vol->worker_running) { - LOGE("Worker thread is currently running.. waiting.."); - pthread_mutex_lock(&vol->worker_sem); - LOGI("Worker thread now available"); - } - - vol->worker_args.reaper_args.cb = cb; - vol->worker_args.reaper_args.cb_arg = arg; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol); -} - -static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange) -{ - int i, rc; - - if (v->state == volstate_mounted || v->state == volstate_badremoval) { - // Try to unmount right away (5 retries) - for (i = 0; i < 5; i++) { - rc = umount(v->mount_point); - if (!rc) - break; - - if (rc && (errno == EINVAL || errno == ENOENT)) { - rc = 0; - break; - } - - LOGI("volmngr quick stop umount(%s) attempt %d (%s)", - v->mount_point, i + 1, strerror(errno)); - - if (i == 0) - usleep(1000 * 250); // First failure, sleep for 250 ms - else - sched_yield(); - } - - if (!rc) { - LOGI("volmgr_stop_volume(%s): Volume unmounted sucessfully", - v->mount_point); - if (emit_statechange) - volume_setstate(v, volstate_unmounted); - v->fs = NULL; - goto out_cb_immed; - } - - /* - * Since the volume is still in use, dispatch the stopping to - * a thread - */ - LOGW("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc); - volmgr_uncage_reaper(v, cb, arg); - return -EINPROGRESS; - } else if (v->state == volstate_checking) { - volume_setstate(v, volstate_unmounted); - if (v->worker_running) { - LOG_VOL("Cancelling worker thread"); - pthread_kill(v->worker_thread, SIGUSR1); - } else - LOGE("Strange... we were in checking state but worker thread wasn't running.."); - goto out_cb_immed; - } - - out_cb_immed: - if (cb) - cb(v, arg); - return 0; -} - - -/* - * Gracefully stop a volume - * v->lock must be held! - * if we return -EINPROGRESS, do NOT release the lock as the reaper - * is using the volume - */ -static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange) -{ - return volmgr_stop_volume(v, cb, NULL, emit_statechange); -} - -static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg) -{ - void (* shutdown_cb) (volume_t *) = arg; - -#if DEBUG_VOLMGR - LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point); -#endif - shutdown_cb(v); -} - - -/* - * Called when a volume is sucessfully unmounted for UMS enable - */ -static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg) -{ - int rc; - char *devdir_path; - -#if DEBUG_VOLMGR - LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point); -#endif - devdir_path = blkdev_get_devpath(v->dev->disk); - - if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) { - free(devdir_path); - LOGE("Error enabling ums (%d)", rc); - return; - } - free(devdir_path); - volume_setstate(v, volstate_ums); - pthread_mutex_unlock(&v->lock); -} - -static int volmgr_readconfig(char *cfg_path) -{ - cnode *root = config_node("", ""); - cnode *node; - - config_load_file(root, cfg_path); - node = root->first_child; - - while (node) { - if (!strncmp(node->name, "volume_", 7)) - volmgr_config_volume(node); - else - LOGE("Skipping unknown configuration node '%s'", node->name); - node = node->next; - } - return 0; -} - -static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path) -{ - int i; - -#if DEBUG_VOLMGR - LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path); -#endif - for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { - if (!v->media_paths[i]) { - v->media_paths[i] = strdup(media_path); - return; - } - } - LOGE("Unable to add media path '%s' to volume (out of media slots)", media_path); -} - -static int volmgr_config_volume(cnode *node) -{ - volume_t *new; - int rc = 0, i; - - char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs; - uint32_t dm_size_mb = 0; - - dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL; -#if DEBUG_VOLMGR - LOG_VOL("volmgr_configure_volume(%s):", node->name); -#endif - if (!(new = malloc(sizeof(volume_t)))) - return -ENOMEM; - memset(new, 0, sizeof(volume_t)); - - new->state = volstate_nomedia; - pthread_mutex_init(&new->lock, NULL); - pthread_mutex_init(&new->worker_sem, NULL); - - cnode *child = node->first_child; - - while (child) { - if (!strcmp(child->name, "media_path")) - volmgr_add_mediapath_to_volume(new, child->value); - else if (!strcmp(child->name, "emu_media_path")) - volmgr_add_mediapath_to_volume(new, child->value); - else if (!strcmp(child->name, "media_type")) { - if (!strcmp(child->value, "mmc")) - new->media_type = media_mmc; - else if (!strcmp(child->value, "devmapper")) - new->media_type = media_devmapper; - else { - LOGE("Invalid media type '%s'", child->value); - rc = -EINVAL; - goto out_free; - } - } else if (!strcmp(child->name, "mount_point")) - new->mount_point = strdup(child->value); - else if (!strcmp(child->name, "ums_path")) - new->ums_path = strdup(child->value); - else if (!strcmp(child->name, "dm_src")) - dm_src = strdup(child->value); - else if (!strcmp(child->name, "dm_src_type")) - dm_src_type = strdup(child->value); - else if (!strcmp(child->name, "dm_src_size_mb")) - dm_size_mb = atoi(child->value); - else if (!strcmp(child->name, "dm_target")) - dm_tgt = strdup(child->value); - else if (!strcmp(child->name, "dm_target_params")) - dm_param = strdup(child->value); - else if (!strcmp(child->name, "dm_target_fs")) - dm_tgtfs = strdup(child->value); - else - LOGE("Ignoring unknown config entry '%s'", child->name); - child = child->next; - } - - if (new->media_type == media_mmc) { - if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) { - LOGE("Required configuration parameter missing for mmc volume"); - rc = -EINVAL; - goto out_free; - } - } else if (new->media_type == media_devmapper) { - if (!dm_src || !dm_src_type || !dm_tgt || - !dm_param || !dm_tgtfs || !dm_size_mb) { - LOGE("Required configuration parameter missing for devmapper volume"); - rc = -EINVAL; - goto out_free; - } - - char dm_mediapath[255]; - if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb, - dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) { - LOGE("Unable to initialize devmapping"); - goto out_free; - } - LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath); - volmgr_add_mediapath_to_volume(new, dm_mediapath); - } - - if (!vol_root) - vol_root = new; - else { - volume_t *scan = vol_root; - while (scan->next) - scan = scan->next; - scan->next = new; - } - - if (dm_src) - free(dm_src); - if (dm_src_type) - free(dm_src_type); - if (dm_tgt) - free(dm_tgt); - if (dm_param) - free(dm_param); - if (dm_tgtfs) - free(dm_tgtfs); - - return rc; - - out_free: - - if (dm_src) - free(dm_src); - if (dm_src_type) - free(dm_src_type); - if (dm_tgt) - free(dm_tgt); - if (dm_param) - free(dm_param); - if (dm_tgtfs) - free(dm_tgtfs); - - - for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { - if (new->media_paths[i]) - free(new->media_paths[i]); - } - if (new->mount_point) - free(new->mount_point); - if (new->ums_path) - free(new->ums_path); - return rc; -} - -static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev) -{ - volume_t *scan = vol_root; - while(scan) { - if (scan->dev == dev) - return scan; - scan = scan->next; - } - return NULL; -} - -static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked) -{ - volume_t *v = vol_root; - - while(v) { - pthread_mutex_lock(&v->lock); - if (!strcmp(v->mount_point, mount_point)) { - if (!leave_locked) - pthread_mutex_unlock(&v->lock); - return v; - } - pthread_mutex_unlock(&v->lock); - v = v->next; - } - return NULL; -} - -static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy) -{ - volume_t *scan = vol_root; - int i; - - while (scan) { - - for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) { - if (!scan->media_paths[i]) - continue; - - if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i]))) - return scan; - else if (!fuzzy && !strcmp(media_path, scan->media_paths[i])) - return scan; - } - - scan = scan->next; - } - return NULL; -} - -/* - * Attempt to bring a volume online - * Returns: 0 on success, errno on failure, with the following exceptions: - * - ENODATA - Unsupported filesystem type / blank - * vol->lock MUST be held! - */ -static int _volmgr_start(volume_t *vol, blkdev_t *dev) -{ - struct volmgr_fstable_entry *fs; - int rc = ENODATA; - -#if DEBUG_VOLMGR - LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point, - dev->major, dev->minor); -#endif - - if (vol->state == volstate_mounted) { - LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point); - return -EBUSY; - } - - for (fs = fs_table; fs->name; fs++) { - if (!fs->identify_fn(dev)) - break; - } - - if (!fs->name) { - LOGE("No supported filesystems on %d:%d", dev->major, dev->minor); - volume_setstate(vol, volstate_nofs); - return -ENODATA; - } - - return volmgr_start_fs(fs, vol, dev); -} - -// vol->lock MUST be held! -static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev) -{ - /* - * Spawn a thread to do the actual checking / mounting in - */ - - if (vol->worker_running) { - LOGE("Worker thread is currently running.. waiting.."); - pthread_mutex_lock(&vol->worker_sem); - LOGI("Worker thread now available"); - } - - vol->dev = dev; - - if (bootstrap) { - LOGI("Aborting start of %s (bootstrap = %d)\n", vol->mount_point, - bootstrap); - vol->state = volstate_unmounted; - return -EBUSY; - } - - vol->worker_args.start_args.fs = fs; - vol->worker_args.start_args.dev = dev; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol); - - return 0; -} - -static void __start_fs_thread_lock_cleanup(void *arg) -{ - volume_t *vol = (volume_t *) arg; - -#if DEBUG_VOLMGR - LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point); -#endif - - vol->worker_running = false; - - // Wake up anyone that was waiting on this thread - pthread_mutex_unlock(&vol->worker_sem); - - // Unlock the volume - pthread_mutex_unlock(&vol->lock); -} - -static void *volmgr_start_fs_thread(void *arg) -{ - volume_t *vol = (volume_t *) arg; - - pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg); - pthread_mutex_lock(&vol->lock); - - vol->worker_running = true; - vol->worker_pid = getpid(); - - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = volmgr_start_fs_thread_sighandler; - sigaction(SIGUSR1, &actions, NULL); - - struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs; - blkdev_t *dev = vol->worker_args.start_args.dev; - int rc; - -#if DEBUG_VOLMGR - LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(), - fs->name, dev->major, dev->minor, vol->mount_point); -#endif - - if (fs->check_fn) { -#if DEBUG_VOLMGR - LOG_VOL("Starting %s filesystem check on %d:%d", fs->name, - dev->major, dev->minor); -#endif - volume_setstate(vol, volstate_checking); - pthread_mutex_unlock(&vol->lock); - rc = fs->check_fn(dev); - pthread_mutex_lock(&vol->lock); - if (vol->state != volstate_checking) { - LOGE("filesystem check aborted"); - goto out; - } - - if (rc < 0) { - LOGE("%s filesystem check failed on %d:%d (%s)", fs->name, - dev->major, dev->minor, strerror(-rc)); - if (rc == -ENODATA) { - volume_setstate(vol, volstate_nofs); - goto out; - } - goto out_unmountable; - } -#if DEBUG_VOLMGR - LOGI("%s filesystem check of %d:%d OK", fs->name, - dev->major, dev->minor); -#endif - } - - rc = fs->mount_fn(dev, vol, safe_mode); - if (!rc) { - LOGI("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)", - fs->name, dev->major, dev->minor, vol->mount_point, - (safe_mode ? "on" : "off")); - vol->fs = fs; - volume_setstate(vol, volstate_mounted); - goto out; - } - - LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major, - dev->minor, rc); - - out_unmountable: - volume_setstate(vol, volstate_damaged); - out: - pthread_cleanup_pop(1); - pthread_exit(NULL); - return NULL; -} - -static void volmgr_start_fs_thread_sighandler(int signo) -{ - LOGE("Volume startup thread got signal %d", signo); -} - -static void volume_setstate(volume_t *vol, volume_state_t state) -{ - if (state == vol->state) - return; - -#if DEBUG_VOLMGR - LOG_VOL("Volume %s state change from %d -> %d", vol->mount_point, vol->state, state); -#endif - - vol->state = state; - - char *prop_val = conv_volstate_to_propstr(vol->state); - - if (prop_val) { - property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val); - volume_send_state(vol); - } -} - -static int volume_send_state(volume_t *vol) -{ - char *event = conv_volstate_to_eventstr(vol->state); - - return send_msg_with_data(event, vol->mount_point); -} - -static char *conv_volstate_to_eventstr(volume_state_t state) -{ - int i; - - for (i = 0; volume_state_strings[i].event != NULL; i++) { - if (volume_state_strings[i].state == state) - break; - } - - return volume_state_strings[i].event; -} - -static char *conv_volstate_to_propstr(volume_state_t state) -{ - int i; - - for (i = 0; volume_state_strings[i].event != NULL; i++) { - if (volume_state_strings[i].state == state) - break; - } - - return volume_state_strings[i].property_val; -} - |
