auto import from //branches/cupcake/...@130745
diff --git a/vold/volmgr.c b/vold/volmgr.c
index b162ff5..8e79b38 100644
--- a/vold/volmgr.c
+++ b/vold/volmgr.c
@@ -31,18 +31,21 @@
 #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 volume_t *vol_root = NULL;
+static boolean safe_mode = true;
 
 static struct volmgr_fstable_entry fs_table[] = {
-    { "ext3", ext3_identify, ext3_check, ext3_mount },
-    { "vfat", vfat_identify, vfat_check, vfat_mount },
-    { NULL, NULL, NULL, NULL }
+    { "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 {
@@ -80,17 +83,105 @@
 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));
-static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, int emit_statechange);
+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);
+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)\n", 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, unsigned int keysize)
+{
+    volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
+ 
+    if (!v)
+        return -ENOENT;
+
+    if (v->key)
+        free(v->key);
+
+    if (!(v->key = malloc(keysize))) {
+        pthread_mutex_unlock(&v->lock);
+        return -ENOMEM;
+    }
+
+    memcpy(v->key, key, keysize);
+    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):\n", 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\n", mount_point, v->state);
+            pthread_mutex_unlock(&v->lock);
+            return -EBUSY;
+        } else if (v->state == volstate_nomedia) {
+            LOGE("Can't format '%s', (no media)\n", mount_point);
+            pthread_mutex_unlock(&v->lock);
+            return -ENOMEDIUM;
+        }
+
+    if ((rc = initialize_mbr(v->dev->disk)) < 0) {
+        LOGE("MBR init failed for %s (%d)\n", 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;
@@ -100,6 +191,47 @@
         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)) {
+            LOG_VOL("Volume '%s' already mounted at startup\n", 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) {
+                LOG_VOL("Safe mode %s on %s\n", (enable ? "enabled" : "disabled"), v->mount_point);
+            } else {
+                LOGE("Failed to %s safe-mode on %s (%s)\n",
+                     (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc));
+            }
+        }
+
+        pthread_mutex_unlock(&v->lock);
+        v = v->next;
+    }
+        
     return 0;
 }
 
@@ -115,6 +247,7 @@
         }
         pthread_mutex_unlock(&vol_scan->lock);
         vol_scan = vol_scan->next;
+        break; // XXX:
     }
 
     return 0;
@@ -128,65 +261,83 @@
 {
     volume_t *vol;
 
-    if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true))) {
-        LOG_VOL("volmgr ignoring '%s' - no matching volume found\n", dev->media->devpath);
+    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?)\n", vol->mount_point);
+        pthread_mutex_unlock(&vol->lock);
         return 0;
     }
 
-    pthread_mutex_lock(&vol->lock);
     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 = vol_root;
+{ 
+    volume_t *v;
 
-    while(v) {
-        if (!strcmp(v->mount_point, mount_point)) {
-            pthread_mutex_lock(&v->lock);
-            if (!v->dev) {
-                LOGE("Cannot start volume '%s' (volume is not bound to a blkdev)\n", mount_point);
-                pthread_mutex_unlock(&v->lock);
-                return -ENOENT;
-            }
+LOG_VOL("volmgr_start_volume_by_mountpoint(%s):", mount_point);
+    v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
+    if (!v)
+        return -ENOENT;
 
-            if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
-                LOGE("volmgr failed to start volume '%s'\n", v->mount_point);
-            }
-            pthread_mutex_unlock(&v->lock);
-            return 0;
+LOG_VOL("volmgr_start_volume_by_mountpoint(%s): got %p", mount_point, v);
+    if (v->media_type == media_devmapper) {
+        if (devmapper_start(v->dm) < 0)  {
+            LOGE("volmgr failed to start devmapper volume '%s'\n",
+                 v->mount_point);
         }
-        v = v->next;
+    } else if (v->media_type == media_mmc) {
+        if (!v->dev) {
+            LOGE("Cannot start volume '%s' (volume is not bound)\n", 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'\n", v->mount_point);
+        }
     }
 
-    return -ENOENT;
+    pthread_mutex_unlock(&v->lock);
+    return 0;
 }
 
 int volmgr_stop_volume_by_mountpoint(char *mount_point)
 {
-    volume_t *v = vol_root;
+    int rc;
+    volume_t *v;
 
-    while(v) {
-        if (!strcmp(v->mount_point, mount_point)) {
-            pthread_mutex_lock(&v->lock);
-            if (volmgr_shutdown_volume(v, NULL) < 0)
-                LOGE("unable to shutdown volume '%s'\n", v->mount_point);
-            pthread_mutex_unlock(&v->lock);
-            return 0;
-        }
-        v = v->next;
+    v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
+    if (!v)
+        return -ENOENT;
+
+    if (v->state == volstate_mounted)
+        volmgr_send_eject_request(v);
+
+    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'\n", v->mount_point);
+        pthread_mutex_unlock(&v->lock);
     }
-
-    return -ENOENT;
+    return 0;
 }
 
 int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
 {
-#if DEBUG_VOLMGR
-    LOG_VOL("volmgr_notify_eject(%s)\n", dev->dev_fspath);
-#endif
+    LOG_VOL("Volmgr notified of %d:%d eject\n", dev->major, dev->minor);
 
     volume_t *v;
 
@@ -199,19 +350,48 @@
     }
     
     pthread_mutex_lock(&v->lock);
-    if (v->state == volstate_mounted) 
+
+    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);
-
-    int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
-
-    pthread_mutex_unlock(&v->lock);
-    return rc;
+    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)\n",
+                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'\n", 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\n", v->mount_point);
+#endif
 
     eject_cb(v->dev);
     v->dev = NULL; // Clear dev because its being ejected
@@ -231,27 +411,45 @@
 
             if (enable) {
                 pthread_mutex_lock(&v->lock);
+                if (v->state == volstate_mounted)
+                    volmgr_send_eject_request(v);
+                else if (v->state == volstate_ums) {
+                    pthread_mutex_unlock(&v->lock);
+                    goto next_vol;
+                }
+
                 // Stop the volume, and enable UMS in the callback
-                if ((rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable)) < 0)
-                    LOGE("unable to shutdown volume '%s'\n", v->mount_point);
+                rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
+                if (rc != -EINPROGRESS) {
+                    if (rc)
+                        LOGE("unable to shutdown volume '%s'\n", 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'\n", v->mount_point);
                     pthread_mutex_unlock(&v->lock);
                     continue;
                 }
-                volume_setstate(v, volstate_unmounted);
 
-                LOG_VOL("Kick-starting volume '%s' after UMS disable\n", v->dev->disk->dev_fspath);
+                LOG_VOL("Kick-starting volume %d:%d after UMS disable\n",
+                        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 '%s'\n", v->dev->disk->dev_fspath);
+                    LOGE("volmgr failed to consider disk %d:%d\n",
+                         v->dev->disk->major, v->dev->disk->minor);
                 }
                 pthread_mutex_unlock(&v->lock);
             }
         }
+ next_vol:
         v = v->next;
     }
     return 0;
@@ -261,30 +459,58 @@
  * 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, %s):\n", vol->mount_point, dev->dev_fspath);
+    LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):\n", vol->mount_point,
+            dev->major, dev->minor); 
 #endif
 
-    if (vol->state != volstate_nomedia &&
-        vol->state != volstate_unmounted &&
-        vol->state != volstate_badremoval) {
-        LOGE("Volume manager is already handling volume '%s' (currently in state %d)\n", vol->mount_point, vol->state);
+    if (vol->state == volstate_unknown ||
+        vol->state == volstate_mounted ||
+        vol->state == volstate_mounted_ro ||
+        vol->state == volstate_damaged) {
+        LOGE("Cannot consider volume '%s' because it is in state '%d\n", 
+             vol->mount_point, vol->state);
         return -EADDRINUSE;
     }
 
-    volume_setstate(vol, volstate_unmounted);
+    if (vol->state == volstate_formatting) {
+        LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'\n",
+                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 = blkdev_lookup_by_devno(dev->major, 1);
+        if (!part) {
+            LOGE("Can't find partition to format!\n");
+            return -ENOENT;
+        }
 
-    LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'\n", dev->devpath, vol->mount_point);
+        if ((rc = format_partition(part)) < 0) {
+            LOGE("format failed (%d)\n", rc);
+            return rc;
+        }
+        
+    }
+
+    LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'\n",
+            dev->devpath, vol->mount_point);
 
     if (dev->nr_parts == 0) {
         rc = _volmgr_start(vol, dev);
 #if DEBUG_VOLMGR
-        LOG_VOL("_volmgr_start(%s, %s) rc = %d\n", vol->mount_point, dev->dev_fspath ,rc);
+        LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d\n", vol->mount_point,
+                dev->major, dev->minor, rc);
 #endif
     } else {
         /*
@@ -303,7 +529,8 @@
             }
             rc = _volmgr_start(vol, part);
 #if DEBUG_VOLMGR
-            LOG_VOL("_volmgr_start(%s, %s) rc = %d\n", vol->mount_point, part->dev_fspath, rc);
+            LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d\n",
+                    vol->mount_point, part->major, part->minor, rc);
 #endif
             if (!rc) 
                 break;
@@ -317,7 +544,8 @@
     }
 
     if (rc == -ENODATA) {
-        LOGE("Device %s contains no usable filesystems\n", dev->dev_fspath);
+        LOGE("Device %d:%d contains no usable filesystems\n",
+             dev->major, dev->minor);
         rc = 0;
     }
 
@@ -326,14 +554,15 @@
 
 static void volmgr_reaper_thread_sighandler(int signo)
 {
-    LOGE("volmgr reaper thread got signal %d\n", signo);
+    LOGE("Volume reaper thread got signal %d\n", signo);
 }
 
 static void __reaper_cleanup(void *arg)
 {
     volume_t *vol = (volume_t *) arg;
 
-    LOG_VOL("__reaper_cleanup(%s):\n", vol->mount_point);
+    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;
 
@@ -349,7 +578,6 @@
     volume_t *vol = (volume_t *) arg;
 
     pthread_cleanup_push(__reaper_cleanup, arg);
-    pthread_mutex_lock(&vol->lock);
 
     vol->worker_running = true;
     vol->worker_pid = getpid();
@@ -362,29 +590,33 @@
     actions.sa_handler = volmgr_reaper_thread_sighandler;
     sigaction(SIGUSR1, &actions, NULL);
 
-    LOG_VOL("Worker thread pid %d reaping %s\n", getpid(), vol->mount_point);
+    LOG_VOL("Reaper here - working on %s\n", vol->mount_point);
 
     boolean send_sig_kill = false;
     int i, rc;
 
     for (i = 0; i < 10; i++) {
+        errno = 0;
         rc = umount(vol->mount_point);
-        LOG_VOL("volmngr reaper umount(%s) attempt %d rc = %d\n",
-                vol->mount_point, i + 1, rc);
+        LOG_VOL("volmngr reaper umount(%s) attempt %d (%s)\n",
+                vol->mount_point, i + 1, strerror(errno));
         if (!rc)
             break;
         if (rc && (errno == EINVAL || errno == ENOENT)) {
             rc = 0;
             break;
         }
-        KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
         sleep(1);
-        if (!send_sig_kill)
-            send_sig_kill = true;
+        if (i >= 4) {
+            KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
+            if (!send_sig_kill)
+                send_sig_kill = true;
+        }
     }
 
     if (!rc) {
         LOG_VOL("Reaper sucessfully unmounted %s\n", vol->mount_point);
+        vol->fs = NULL;
         volume_setstate(vol, volstate_unmounted);
     } else {
         LOGE("Unable to unmount!! (%d)\n", rc);
@@ -396,16 +628,18 @@
     return NULL;
 }
 
-static void volmgr_uncage_reaper(volume_t *vol)
+// 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..\n");
         pthread_mutex_lock(&vol->worker_sem);
         LOG_VOL("Worker thread now available\n");
     }
 
-    vol->worker_args.fs = NULL;
-    vol->worker_args.dev = NULL;
+    vol->worker_args.reaper_args.cb = cb;
+    vol->worker_args.reaper_args.cb_arg = arg;
 
     pthread_attr_t attr;
     pthread_attr_init(&attr);
@@ -422,15 +656,21 @@
         // Try to unmount right away (5 retries)
         for (i = 0; i < 5; i++) {
             rc = umount(v->mount_point);
-            LOG_VOL("volmngr quick stop umount(%s) attempt %d rc = %d\n",
-                    v->mount_point, i + 1, rc);
             if (!rc)
                 break;
+
             if (rc && (errno == EINVAL || errno == ENOENT)) {
                 rc = 0;
                 break;
             }
-            sched_yield();
+
+            LOG_VOL("volmngr quick stop umount(%s) attempt %d (%s)\n",
+                    v->mount_point, i + 1, strerror(errno));
+
+            if (i == 0)
+                usleep(1000 * 250); // First failure, sleep for 250 ms 
+            else
+                sched_yield();
         }
 
         if (!rc) {
@@ -438,6 +678,7 @@
                     v->mount_point);
             if (emit_statechange)
                 volume_setstate(v, volstate_unmounted);
+            v->fs = NULL;
             goto out_cb_immed;
         }
 
@@ -446,7 +687,7 @@
          * a thread
          */
         LOG_VOL("Volume %s is busy (%d) - uncaging the reaper\n", v->mount_point, rc);
-        volmgr_uncage_reaper(v);
+        volmgr_uncage_reaper(v, cb, arg);
         return -EINPROGRESS;
     } else if (v->state == volstate_checking) {
         volume_setstate(v, volstate_unmounted);
@@ -458,8 +699,6 @@
         goto out_cb_immed;
     }
 
-    LOGE("volmgr: nothing to do to stop vol '%s' (in state %d)\n",
-             v->mount_point, v->state);
  out_cb_immed:
     if (cb)
         cb(v, arg);
@@ -469,17 +708,22 @@
 
 /*
  * 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 *))
+static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange)
 {
-    return volmgr_stop_volume(v, cb, NULL, true);
+    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\n", v->mount_point);
+#endif
     shutdown_cb(v);
 }
 
@@ -489,12 +733,19 @@
 static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
 {
     int rc;
+    char *devdir_path;
 
-    LOG_VOL("_cb_volstopped_for_ums_enable(%s):\n", v->dev->dev_fspath);
-    if ((rc = ums_enable(v->dev->disk->dev_fspath, v->ums_path)) < 0) {
+#if DEBUG_VOLMGR
+    LOG_VOL("_cb_volstopped_for_ums_enable(%s):\n", 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)\n", rc);
         return;
     }
+    free(devdir_path);
     volume_setstate(v, volstate_ums);
     pthread_mutex_unlock(&v->lock);
 }
@@ -508,7 +759,7 @@
     node = root->first_child;
 
     while (node) {
-        if (!strcmp(node->name, "volume"))
+        if (!strncmp(node->name, "volume_", 7))
             volmgr_config_volume(node);
         else
             LOGE("Skipping unknown configuration node '%s'\n", node->name);
@@ -517,11 +768,34 @@
     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):\n", 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)\n", media_path);
+}
+
 static int volmgr_config_volume(cnode *node)
 {
     volume_t *new;
-    int rc = 0;
+    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):\n", node->name);
+#endif
     if (!(new = malloc(sizeof(volume_t))))
         return -ENOMEM;
     memset(new, 0, sizeof(volume_t));
@@ -534,10 +808,14 @@
 
     while (child) {
         if (!strcmp(child->name, "media_path"))
-            new->media_path = strdup(child->value);
+            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'\n", child->value);
                 rc = -EINVAL;
@@ -547,15 +825,42 @@
             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'\n", child->name);
         child = child->next;
     }
 
-    if (!new->media_path || !new->mount_point || new->media_type == media_unknown) {
-        LOGE("Required configuration parameter missing for volume\n");
-        rc = -EINVAL;
-        goto out_free;
+    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\n");
+            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\n");
+            rc = -EINVAL;
+            goto out_free;
+        }
+        if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
+                                       dm_tgt, dm_param, dm_tgtfs))) {
+            LOGE("Unable to initialize devmapping");
+           goto out_free;
+        }
+        
     }
 
     if (!vol_root)
@@ -567,11 +872,37 @@
         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 (new->media_path)
-        free(new->media_path);
+
+    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)
@@ -590,27 +921,42 @@
     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;
+        }
+        v = v->next;
+    }
+    return NULL;
+}
+
 static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
 {
     volume_t *scan = vol_root;
-    volume_t *res = NULL;
+    int i;
 
     while (scan) {
-        if (fuzzy) {
-            if (!strncmp(media_path, scan->media_path, strlen(scan->media_path))) {
-                if (!res)
-                    res = scan;
-                else {
-                    LOGE("Warning - multiple matching volumes for media '%s' - using first\n", media_path);
-                    break;
-                }
-            }
-        } else if (!strcmp(media_path, scan->media_path))
-            return 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 res;
+    return NULL;
 }
 
 /*
@@ -625,16 +971,22 @@
     int rc = ENODATA;
 
 #if DEBUG_VOLMGR
-    LOG_VOL("_volmgr_start(%s, %s):\n", vol->mount_point, dev->dev_fspath);
+    LOG_VOL("_volmgr_start(%s, %d:%d):\n", vol->mount_point,
+            dev->major, dev->minor);
 #endif
 
+    if (vol->state == volstate_mounted) {
+        LOGE("Unable to start volume '%s' (already mounted)\n", vol->mount_point);
+        return -EBUSY;
+    }
+
     for (fs = fs_table; fs->name; fs++) {
         if (!fs->identify_fn(dev))
             break;
     }
 
     if (!fs) {
-        LOGE("No supported filesystems on %s\n", dev->dev_fspath);
+        LOGE("No supported filesystems on %d:%d\n", dev->major, dev->minor);
         volume_setstate(vol, volstate_nofs);
         return -ENODATA;
     }
@@ -657,8 +1009,8 @@
 
     vol->dev = dev; 
 
-    vol->worker_args.fs = fs;
-    vol->worker_args.dev = dev;
+    vol->worker_args.start_args.fs = fs;
+    vol->worker_args.start_args.dev = dev;
 
     pthread_attr_t attr;
     pthread_attr_init(&attr);
@@ -673,7 +1025,9 @@
 {
     volume_t *vol = (volume_t *) arg;
 
+#if DEBUG_VOLMGR
     LOG_VOL("__start_fs_thread_lock_cleanup(%s):\n", vol->mount_point);
+#endif
 
     vol->worker_running = false;
 
@@ -702,14 +1056,20 @@
     actions.sa_handler = volmgr_start_fs_thread_sighandler;
     sigaction(SIGUSR1, &actions, NULL);
 
-    struct volmgr_fstable_entry *fs = vol->worker_args.fs;
-    blkdev_t                    *dev = vol->worker_args.dev;
+    struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
+    blkdev_t                    *dev = vol->worker_args.start_args.dev;
     int                          rc;
   
-    LOG_VOL("Worker thread pid %d starting %s fs %s on %s\n", getpid(), fs->name, dev->dev_fspath, vol->mount_point);
+#if DEBUG_VOLMGR
+    LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s\n", getpid(),
+             fs->name, dev->major, dev->minor, vol->mount_point);
+#endif
 
     if (fs->check_fn) {
-        LOG_VOL("Starting %s filesystem check on %s\n", fs->name, dev->dev_fspath);
+#if DEBUG_VOLMGR
+        LOG_VOL("Starting %s filesystem check on %d:%d\n", fs->name,
+                dev->major, dev->minor);
+#endif
         volume_setstate(vol, volstate_checking);
         pthread_mutex_unlock(&vol->lock);
         rc = fs->check_fn(dev);
@@ -720,20 +1080,32 @@
         }
         
         if (rc < 0) {
-            LOG_VOL("%s filesystem check failed on %s\n", fs->name, dev->dev_fspath);
+            LOGE("%s filesystem check failed on %d:%d (%s)\n", fs->name,
+                    dev->major, dev->minor, strerror(-rc));
+            if (rc == -ENODATA) {
+               volume_setstate(vol, volstate_nofs);
+               goto out;
+            }
             goto out_unmountable;
         }
-        LOG_VOL("%s filesystem check of %s OK\n", fs->name, dev->dev_fspath);
+#if DEBUG_VOLMGR
+        LOG_VOL("%s filesystem check of %d:%d OK\n", fs->name,
+                dev->major, dev->minor);
+#endif
     }
 
-    rc = fs->mount_fn(dev, vol);
+    rc = fs->mount_fn(dev, vol, safe_mode);
     if (!rc) {
-        LOG_VOL("Sucessfully mounted %s filesystem %s on %s\n", fs->name, dev->devpath, vol->mount_point);
+        LOG_VOL("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)\n",
+                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 %s failed (%d)\n", fs->name, dev->devpath, rc);
+    LOGE("%s filesystem mount of %d:%d failed (%d)\n", fs->name, dev->major,
+         dev->minor, rc);
 
  out_unmountable:
     volume_setstate(vol, volstate_damaged);
@@ -745,19 +1117,26 @@
 
 static void volmgr_start_fs_thread_sighandler(int signo)
 {
-    LOGE("volmgr thread got signal %d\n", signo);
+    LOGE("Volume startup thread got signal %d\n", 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\n", vol->mount_point, vol->state, state);
+#endif
     
     vol->state = state;
     
     char *prop_val = conv_volstate_to_propstr(vol->state);
 
-    property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
-    volume_send_state(vol);
+    if (prop_val) {
+        property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
+        volume_send_state(vol);
+    }
 }
 
 static int volume_send_state(volume_t *vol)
@@ -776,8 +1155,6 @@
             break;
     }
 
-    if (!volume_state_strings[i].event)
-        LOGE("conv_volstate_to_eventstr(%d): Invalid state\n", state);
     return volume_state_strings[i].event;
 }
 
@@ -790,8 +1167,6 @@
             break;
     }
 
-    if (!volume_state_strings[i].event)
-        LOGE("conv_volstate_to_propval(%d): Invalid state\n", state);
     return volume_state_strings[i].property_val;
 }