auto import from //branches/cupcake/...@130745
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 3feee07..32ce0a9 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -292,7 +292,8 @@
                         }
                     }
 
-                    register_device_callback(devname, local_ep_in, local_ep_out, i, serial, zero_mask);
+                    register_device_callback(devname, local_ep_in, local_ep_out,
+                            interface->bInterfaceNumber, serial, zero_mask);
 
                     found_device = 1;
                     break;
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 4079a38..e220dbe 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -195,7 +195,7 @@
             "\n"
             "commands:\n"
             "  update <filename>                        reflash device from update.zip\n"
-            "  flashall                                 'flash boot' + 'flash system'\n"
+            "  flashall                                 flash boot + recovery + system\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
             "  getvar <variable>                        display a bootloader variable\n"
@@ -588,6 +588,9 @@
         } else if(!strcmp(*argv, "reboot-bootloader")) {
             wants_reboot_bootloader = 1;
             skip(1);
+        } else if (!strcmp(*argv, "continue")) {
+            fb_queue_command("continue", "resuming boot");
+            skip(1);
         } else if(!strcmp(*argv, "boot")) {
             char *kname = 0;
             char *rname = 0;
diff --git a/include/pixelflinger/format.h b/include/pixelflinger/format.h
index 308e560..6b2050c 100644
--- a/include/pixelflinger/format.h
+++ b/include/pixelflinger/format.h
@@ -42,8 +42,10 @@
     // YCbCr formats (SP=semi-planar, P=planar)
     GGL_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
     GGL_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
-    GGL_PIXEL_FORMAT_YCbCr_422_P = 0x14,
-    GGL_PIXEL_FORMAT_YCbCr_420_P = 0x15,
+    GGL_PIXEL_FORMAT_YCbCr_422_P = 0x12,
+    GGL_PIXEL_FORMAT_YCbCr_420_P = 0x13,
+    GGL_PIXEL_FORMAT_YCbCr_422_I = 0x14,
+    GGL_PIXEL_FORMAT_YCbCr_420_I = 0x15,
 
     // reserved/special formats
     GGL_PIXEL_FORMAT_Z_16       =  0x18,
@@ -60,7 +62,10 @@
 	GGL_RGBA				= 0x1908,
 	GGL_LUMINANCE			= 0x1909,
 	GGL_LUMINANCE_ALPHA		= 0x190A,
-	GGL_Y_CB_CR             = 0x8000,
+    GGL_Y_CB_CR_SP          = 0x8000,
+    GGL_Y_CB_CR             = GGL_Y_CB_CR_SP,
+    GGL_Y_CB_CR_P           = 0x8001,
+    GGL_Y_CB_CR_I           = 0x8002,
 };
 
 enum GGLFormatComponentIndex {
diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp
index cbbd91a..161e6d6 100644
--- a/libpixelflinger/format.cpp
+++ b/libpixelflinger/format.cpp
@@ -40,12 +40,12 @@
     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
 
-    {  1, 16, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR },// PIXEL_FORMAT_YCbCr_422_SP
-    {  1, 12, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR },// PIXEL_FORMAT_YCbCr_420_SP
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
+    {  1, 16, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_422_SP
+    {  1, 12, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_SP },// PIXEL_FORMAT_YCbCr_420_SP
+    {  1, 16, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_422_P
+    {  1, 12, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_P }, // PIXEL_FORMAT_YCbCr_420_P
+    {  1, 16, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_422_I
+    {  1, 12, {{ 0, 8,   0, 8,   0, 8,   0, 0 }}, GGL_Y_CB_CR_I }, // PIXEL_FORMAT_YCbCr_420_I
     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
     
diff --git a/logcat/event-log-tags b/logcat/event-log-tags
index 3d977a5..4f17040 100644
--- a/logcat/event-log-tags
+++ b/logcat/event-log-tags
@@ -58,6 +58,9 @@
 # This is logged when the partial wake lock (keeping the device awake
 # regardless of whether the screen is off) is acquired or released.
 2729 power_partial_wake_state (releasedorAcquired|1|5),(tag|3)
+# This is logged when battery goes from discharging to charging. 
+# It lets us count the total amount of time between charges and the discharge level
+2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6)
 #
 # Leave IDs through 2739 for more power logs 
 #
@@ -295,19 +298,28 @@
 # PDP Setup failures
 50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5)
 
-# Call drops 
+# Call drops
 50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5)
 
 # Data network registration failed after successful voice registration
 50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5)
 
-# Suspicious status of data connection while radio poweroff 
+# Suspicious status of data connection while radio poweroff
 50108 data_network_status_on_radio_off (dc_state|3), (enable|1|5)
 
+# PDP drop caused by network
+50109 pdp_network_drop (cid|1|5), (network_type|1|5)
+
 # Do not change these names without updating tag in:
 #//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
 51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5)
 
+# db stats.  0 is query, 1 is write (may become more fine grained in the 
+# future)
+52000 db_operation (name|3),(op_type|1|5),(time|2|3)
+
+# http request/response stats
+52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2)
 60000 viewroot_draw (Draw time|1|3)
 60001 viewroot_layout (Layout time|1|3)
 60002 view_build_drawing_cache (View created drawing cache|1|5)
@@ -315,3 +327,4 @@
 
 # 0 for screen off, 1 for screen on, 2 for key-guard done
 70000 screen_toggled (screen_state|1|5)
+
diff --git a/mountd/Android.mk b/mountd/Android.mk
index 2fb7640..16532fa 100644
--- a/mountd/Android.mk
+++ b/mountd/Android.mk
@@ -18,4 +18,5 @@
 
 LOCAL_SHARED_LIBRARIES := libcutils
 
-include $(BUILD_EXECUTABLE)
+# disabled - we are using vold now instead
+# include $(BUILD_EXECUTABLE)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 7ff1a74..b2fe8cf 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -4,7 +4,6 @@
 # files that live under /system/etc/...
 
 copy_from := \
-	etc/mountd.conf \
 	etc/dbus.conf \
 	etc/init.goldfish.sh \
 	etc/hosts
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index b0c241e..5a8dc0b 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -41,6 +41,7 @@
 	printenv \
 	smd \
 	chmod \
+    chown \
 	mkdosfs \
 	netstat \
 	ioctl \
diff --git a/toolbox/chown.c b/toolbox/chown.c
new file mode 100644
index 0000000..13617db
--- /dev/null
+++ b/toolbox/chown.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <unistd.h>
+#include <time.h>
+
+int chown_main(int argc, char **argv)
+{
+    int i;
+
+    if (argc < 3) {
+        fprintf(stderr, "Usage: chown <USER>[.GROUP] <FILE1> [FILE2] ...\n");
+        return 10;
+    }
+
+    // Copy argv[1] to 'user' so we can truncate it at the period
+    // if a group id specified.
+    char user[32];
+    char *group = NULL;
+    strncpy(user, argv[1], sizeof(user));
+    if ((group = strchr(user, '.')) != NULL) {
+        *group++ = '\0';
+    }
+
+    // Lookup uid (and gid if specified)
+    struct passwd *pw;
+    struct group *grp = NULL;
+    uid_t uid;
+    gid_t gid = -1; // passing -1 to chown preserves current group
+
+    pw = getpwnam(user);
+    if (pw == NULL) {
+        fprintf(stderr, "No such user '%s'\n", user);
+        return 10;
+    }
+    uid = pw->pw_uid;
+
+    if (group != NULL) {
+        grp = getgrnam(group);
+        if (grp == NULL) {
+            fprintf(stderr, "No such group '%s'\n", group);
+            return 10;
+        }
+        gid = grp->gr_gid; 
+    }
+
+    for (i = 2; i < argc; i++) {
+        if (chown(argv[i], uid, gid) < 0) {
+            fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+            return 10;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
index d084403..44b9847 100644
--- a/toolbox/insmod.c
+++ b/toolbox/insmod.c
@@ -45,10 +45,12 @@
 	return buffer;
 }
 
+#define min(x,y) ((x) < (y) ? (x) : (y))
 int insmod_main(int argc, char **argv)
 {
 	void *file;
-	ssize_t size;
+	ssize_t size = 0;
+	char opts[1024];
 	int ret;
 
 	/* make sure we've got an argument */
@@ -64,9 +66,24 @@
 		return -1;
 	}
 
+	opts[0] = '\0';
+	if (argc > 2) {
+		int i, len;
+		char *end = opts + sizeof(opts) - 1;
+		char *ptr = opts;
+
+		for (i = 2; (i < argc) && (ptr < end); i++) {
+			len = min(strlen(argv[i]), end - ptr);
+			memcpy(ptr, argv[i], len);
+			ptr += len;
+			*ptr++ = ' ';
+			*ptr++ = '\0';
+		}
+		*(ptr - 1) = '\0';
+	}
+
 	/* pass it to the kernel */
-	/* XXX options */
-	ret = init_module(file, size, "");
+	ret = init_module(file, size, opts);
 	if (ret != 0) {
 		fprintf(stderr,
                 "insmod: init_module '%s' failed (%s)\n",
diff --git a/vold/Android.mk b/vold/Android.mk
index 465849f..3dd9f87 100644
--- a/vold/Android.mk
+++ b/vold/Android.mk
@@ -1,7 +1,3 @@
-BUILD_VOLD := false
-
-ifeq ($(BUILD_VOLD),true)
-
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -10,7 +6,6 @@
                   vold.c       \
                   cmd_dispatch.c \
                   uevent.c       \
-                  inotify.c      \
                   mmc.c          \
 		  misc.c         \
                   blkdev.c       \
@@ -22,6 +17,9 @@
                   volmgr_ext3.c  \
                   logwrapper.c   \
                   ProcessKiller.c\
+                  switch.c       \
+                  format.c       \
+                  devmapper.c
 
 LOCAL_MODULE:= vold
 
@@ -32,5 +30,3 @@
 LOCAL_SHARED_LIBRARIES := libcutils
 
 include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/vold/blkdev.c b/vold/blkdev.c
index f7907b2..39f415d 100644
--- a/vold/blkdev.c
+++ b/vold/blkdev.c
@@ -27,6 +27,7 @@
 #include <sys/mman.h>
 
 #include <linux/fs.h>
+#include <linux/msdos_fs.h>
 
 #include "vold.h"
 #include "blkdev.h"
@@ -37,74 +38,37 @@
 static blkdev_list_t *list_root = NULL;
 
 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
-                                int minor, char *type, struct media *media, char *dev_fspath);
-static void blkdev_dev_fspath_set(blkdev_t *blk, char *dev_fspath);
+                                int minor, char *type, struct media *media);
 
-int blkdev_handle_devicefile_removed(blkdev_t *blk, char *dev_fspath)
+static int fat_valid_media(unsigned char media)
+{                       
+        return 0xf8 <= media || media == 0xf0;
+}                               
+
+char *blkdev_get_devpath(blkdev_t *blk)
 {
-#if DEBUG_BLKDEV
-    LOG_VOL("blkdev_handle_devicefile_removed(%s):\n", dev_fspath);
-#endif
-    blkdev_dev_fspath_set(blk, NULL);
-    return 0;
+    char *dp = malloc(256);
+    sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor);
+    return dp;
 }
 
-int blkdev_handle_devicefile_created(blkdev_t *blk, char *dev_fspath)
+int blkdev_refresh(blkdev_t *blk)
 {
-    int rc = 0;
-    blkdev_t *disk;
- 
-#if DEBUG_BLKDEV
-    LOG_VOL("blkdev_handle_devicefile_created(%s):\n", dev_fspath);
-#endif
+    int fd = 0;
+    char *devpath = NULL;
+    unsigned char *block = NULL;
+    int i, rc;
 
-    if (!blk) {
-        /*
-         * This device does not yet have a backing blkdev associated with it.
-         * Create a new one in the pending state and fill in the information
-         * we have.
-         */
-        struct stat sbuf;
-
-        if (stat(dev_fspath, &sbuf) < 0) {
-            LOGE("Unable to stat device '%s' (%s)\n", dev_fspath, strerror(errno));
-            return -errno;
-        }
-
-        int major = (sbuf.st_rdev & 0xfff00) >> 8;
-        int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
-
-        disk = blkdev_lookup_by_devno(major, 0);
-
-        if (!disk) {
-            /*
-             * If there isn't a disk associated with this device, then
-             * its not what we're looking for
-             */
-#if DEBUG_BLKDEV
-            LOG_VOL("Ignoring device file '%s' (no disk found)\n", dev_fspath);
-#endif
-            return 0;
-        }
-
-        if (!(blk = blkdev_create_pending_partition(disk, dev_fspath, major,
-                                                    minor, disk->media))) {
-            LOGE("Unable to create pending blkdev\n");
-            return -1;
-        }
-    } else
-        blkdev_dev_fspath_set(blk, dev_fspath);
+    if (!(block = malloc(512)))
+        goto out;
 
     /*
-     * If we're a disk, then read the partition table. Otherwise we're
-     * a partition so get the partition type
+     * Get the device size
      */
-    disk = blk->disk;
+    devpath = blkdev_get_devpath(blk);
 
-    int fd;
-
-    if ((fd = open(disk->dev_fspath, O_RDWR)) < 0) {
-        LOGE("Unable to open device '%s' (%s)\n", disk->dev_fspath, strerror(errno));
+    if ((fd = open(devpath, O_RDONLY)) < 0) {
+        LOGE("Unable to open device '%s' (%s)\n", devpath, strerror(errno));
         return -errno;
     }
 
@@ -112,77 +76,101 @@
         LOGE("Unable to get device size (%m)\n");
         return -errno;
     }
+    close(fd);
+    free(devpath);
 
-#if DEBUG_BLKDEV
-    LOG_VOL("New device '%s' size = %u sectors\n", dev_fspath, blk->nr_sec);
-#endif
-
-    void *raw_pt;
-    unsigned char *chr_pt;
-    int i;
-
-    raw_pt = chr_pt = mmap(NULL, 512, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (raw_pt == MAP_FAILED) {
-        LOGE("Unable to mmap device paritition table (%m)\n");
-        goto out_nommap;
+    /*
+     * Open the disk partition table
+     */
+    devpath = blkdev_get_devpath(blk->disk);
+    if ((fd = open(devpath, O_RDONLY)) < 0) {
+        LOGE("Unable to open device '%s' (%s)\n", devpath,
+             strerror(errno));
+        free(devpath);
+        return -errno;
     }
 
+    free(devpath);
+
+    if ((rc = read(fd, block, 512)) != 512) {
+        LOGE("Unable to read device partition table (%d, %s)\n",
+             rc, strerror(errno));
+        goto out;
+    }
+
+    /*
+     * If we're a disk, then process the partition table. Otherwise we're
+     * a partition so get the partition type
+     */
+
     if (blk->type == blkdev_disk) {
         blk->nr_parts = 0;
 
-        if ((chr_pt[0x1fe] != 0x55) && (chr_pt[0x1ff] != 0xAA)) {
-            LOG_VOL("Disk '%s' does not contain a partition table\n", dev_fspath);
+        if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) {
+            LOG_VOL("Disk %d:%d does not contain a partition table\n",
+                    blk->major, blk->minor);
             goto out;
         }
 
         for (i = 0; i < 4; i++) {
             struct dos_partition part;
 
-            dos_partition_dec(raw_pt + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
+            dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
+            if (part.dp_flag != 0 && part.dp_flag != 0x80) {
+                struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0];
+             
+                if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) {
+                    LOG_VOL("Detected FAT filesystem in partition table\n");
+                    break;
+                } else {
+                    LOG_VOL("Partition table looks corrupt\n");
+                    break;
+                }
+            }
             if (part.dp_size != 0 && part.dp_typ != 0)
                 blk->nr_parts++;
         }
-        LOG_VOL("Disk device '%s' (blkdev %s) contains %d partitions\n",
-                dev_fspath, blk->devpath, blk->nr_parts);
     } else if (blk->type == blkdev_partition) {
         struct dos_partition part;
         int part_no = blk->minor -1;
 
-        dos_partition_dec(raw_pt + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
-
-        if (!part.dp_typ)
-            LOG_VOL("Warning - Partition device '%s' (blkdev %s) has no partition type set\n",
-                    dev_fspath, blk->devpath);
+        dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
         blk->part_type = part.dp_typ;
-
-        LOG_VOL("Partition device '%s' (blkdev %s) partition type 0x%x\n",
-                 dev_fspath, blk->devpath, blk->part_type);
-    } else {
-        LOGE("Bad blkdev type '%d'\n", blk->type);
-        rc = -EINVAL;
-        goto out;
     }
 
  out:
-    munmap(raw_pt, 512);
- out_nommap:
-    close(fd);
-    return rc;
-}
 
-blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major,
-                                int minor, struct media *media)
-{
-    return _blkdev_create(disk, NULL, major, minor, "partition", media, dev_fspath);
+    if (block)
+        free(block);
+
+    char tmp[255];
+    char tmp2[32];
+    sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)",
+                 (blk->type == blkdev_disk ? "Disk" : "Partition"),
+                 blk->major, blk->minor,
+                 blk->nr_sec,
+                 ((blk->nr_sec * 512) / 1024) / 1024);
+
+    if (blk->type == blkdev_disk) 
+        sprintf(tmp2, " %d partitions\n", blk->nr_parts);
+    else
+        sprintf(tmp2, " type 0x%x\n", blk->part_type);
+
+    strcat(tmp, tmp2);
+    LOG_VOL(tmp);
+
+    close(fd);
+
+    return 0;
 }
 
 blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
 {
-    return _blkdev_create(disk, devpath, major, minor, type, media, NULL);
+    return _blkdev_create(disk, devpath, major, minor, type, media);
 }
 
 static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
-                                int minor, char *type, struct media *media, char *dev_fspath)
+                                int minor, char *type, struct media *media)
 {
     blkdev_t *new;
     struct blkdev_list *list_entry;
@@ -218,8 +206,6 @@
     new->major = major;
     new->minor = minor;
     new->media = media;
-    if (dev_fspath)
-        new->dev_fspath = strdup(dev_fspath);
     new->nr_sec = 0xffffffff;
 
     if (disk)
@@ -227,6 +213,17 @@
     else 
         new->disk = new; // Note the self disk pointer
 
+    /* Create device nodes */
+    char nodepath[255];
+    mode_t mode = 0666 | S_IFBLK;
+    dev_t dev = (major << 8) | minor;
+
+    sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
+    if (mknod(nodepath, mode, dev) < 0) {
+        LOGE("Error making device nodes for '%s' (%s)\n",
+             nodepath, strerror(errno));
+    }
+
     if (!strcmp(type, "disk"))
         new->type = blkdev_disk;
     else if (!strcmp(type, "partition"))
@@ -258,8 +255,11 @@
 
     if (blkdev->devpath)
         free(blkdev->devpath);
-    if (blkdev->dev_fspath)
-        free(blkdev->dev_fspath);
+
+    char nodepath[255];
+    sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor);
+    unlink(nodepath);
+
     free(blkdev);
 }
 
@@ -272,9 +272,6 @@
             return list_scan->dev;
         list_scan = list_scan->next;
     }
-#if DEBUG_BLKDEV
-    LOG_VOL("blkdev_lookup_by_path(): No blkdev found @ %s\n", devpath);
-#endif
     return NULL;
 }
 
@@ -288,32 +285,12 @@
             return list_scan->dev;
         list_scan = list_scan->next;
     }
-#if DEBUG_BLKDEV
-    LOG_VOL("blkdev_lookup_by_devno(): No blkdev found for %d.%d\n", maj, min);
-#endif
     return NULL;
 }
 
-blkdev_t *blkdev_lookup_by_dev_fspath(char *dev_fspath)
-{
-    struct blkdev_list *list_scan = list_root;
-
-    while (list_scan) {
-        if (list_scan->dev->dev_fspath) {
-            if (!strcmp(list_scan->dev->dev_fspath, dev_fspath)) 
-                return list_scan->dev;
-        }
-
-        list_scan = list_scan->next;
-    }
-//    LOG_VOL("blkdev_lookup_by_devno(): No blkdev found for %d.%d\n", maj, min);
-    return NULL;
-}
-
-
 /*
- * Given a disk device, return the number of partitions yet to be 
- * processed.
+ * Given a disk device, return the number of partitions which 
+ * have yet to be processed.
  */
 int blkdev_get_num_pending_partitions(blkdev_t *blk)
 {
@@ -330,25 +307,13 @@
         if (list_scan->dev->major != blk->major)
             goto next;
 
-        if (list_scan->dev->nr_sec != 0xffffffff)
+        if (list_scan->dev->nr_sec != 0xffffffff &&
+            list_scan->dev->devpath) {
             num--;
+        }
  next:
         list_scan = list_scan->next;
     }
     return num;
 }
 
-void blkdev_devpath_set(blkdev_t *blk, char *devpath)
-{
-    blk->devpath = strdup(devpath);
-}
-
-static void blkdev_dev_fspath_set(blkdev_t *blk, char *dev_fspath)
-{
-    if (dev_fspath)
-        blk->dev_fspath = strdup(dev_fspath);
-    else {
-        free(blk->dev_fspath);
-        blk->dev_fspath = NULL;
-    }
-}
diff --git a/vold/blkdev.h b/vold/blkdev.h
index 7818419..e789739 100644
--- a/vold/blkdev.h
+++ b/vold/blkdev.h
@@ -41,7 +41,6 @@
 
     int           major;
     int           minor;
-    char          *dev_fspath;
 };
 
 struct blkdev_list {
@@ -56,11 +55,10 @@
 blkdev_t *blkdev_create_pending_partition(blkdev_t *disk, char *dev_fspath, int major, int minor, struct media *media);
 blkdev_t *blkdev_lookup_by_path(char *devpath);
 blkdev_t *blkdev_lookup_by_devno(int maj, int min);
-blkdev_t *blkdev_lookup_by_dev_fspath(char *dev_fspath);
+char *blkdev_get_devpath(blkdev_t *blk);
+
 void blkdev_destroy(blkdev_t *blk);
 
-int blkdev_handle_devicefile_created(blkdev_t *blk, char *dev_fspath);
-int blkdev_handle_devicefile_removed(blkdev_t *blk, char *dev_fspath);
 int blkdev_get_num_pending_partitions(blkdev_t *blk);
-void blkdev_devpath_set(blkdev_t *blk, char *dev_fspath);
+int blkdev_refresh(blkdev_t *blk);
 #endif
diff --git a/vold/cmd_dispatch.c b/vold/cmd_dispatch.c
index 1f48cfc..2ffb3f7 100644
--- a/vold/cmd_dispatch.c
+++ b/vold/cmd_dispatch.c
@@ -33,13 +33,15 @@
 static int do_set_ums_enable(char *cmd);
 static int do_mount_volume(char *cmd);
 static int do_eject_media(char *cmd);
+static int do_format_media(char *cmd);
 
 static struct cmd_dispatch dispatch_table[] = {
     { VOLD_CMD_ENABLE_UMS,      do_set_ums_enable },
     { VOLD_CMD_DISABLE_UMS,     do_set_ums_enable },
     { VOLD_CMD_SEND_UMS_STATUS, do_send_ums_status },
-    { VOLD_CMD_MOUNT_VOLUME,     do_mount_volume },
+    { VOLD_CMD_MOUNT_VOLUME,    do_mount_volume },
     { VOLD_CMD_EJECT_MEDIA,     do_eject_media },
+    { VOLD_CMD_FORMAT_MEDIA,    do_format_media },
     { NULL, NULL }
 };
 
@@ -51,7 +53,8 @@
     if ((rc = read(socket, buffer, sizeof(buffer) -1)) < 0) {
         LOGE("Unable to read framework command (%s)\n", strerror(errno));
         return -errno;
-    }
+    } else if (!rc)
+        return -ECONNRESET;
 
     int start = 0;
     int i;
@@ -101,6 +104,11 @@
     return volmgr_start_volume_by_mountpoint(&cmd[strlen("mount_volume:")]);
 }
 
+static int do_format_media(char *cmd)
+{
+    return volmgr_format_volume(&cmd[strlen("format_media:")]);
+}
+
 static int do_eject_media(char *cmd)
 {
     return volmgr_stop_volume_by_mountpoint(&cmd[strlen("eject_media:")]);
diff --git a/vold/cmd_dispatch.h b/vold/cmd_dispatch.h
index e88874e..f8ba6b3 100644
--- a/vold/cmd_dispatch.h
+++ b/vold/cmd_dispatch.h
@@ -26,5 +26,6 @@
 // these commands should contain a volume mount point after the colon
 #define VOLD_CMD_MOUNT_VOLUME       "mount_volume:"
 #define VOLD_CMD_EJECT_MEDIA        "eject_media:"
+#define VOLD_CMD_FORMAT_MEDIA       "format_media:"
 
 #endif
diff --git a/vold/devmapper.c b/vold/devmapper.c
new file mode 100644
index 0000000..c7fd167
--- /dev/null
+++ b/vold/devmapper.c
@@ -0,0 +1,168 @@
+
+/*
+ * 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 <fcntl.h>
+
+#include <sys/mount.h>
+
+#include <linux/loop.h>
+
+#include <cutils/config_utils.h>
+#include <cutils/properties.h>
+
+#include "vold.h"
+#include "devmapper.h"
+
+#define DEBUG_DEVMAPPER 1
+
+static int loopback_start(struct devmapping *dm)
+{
+    int i;
+    int fd;
+    char filename[255];
+    int rc;
+
+#if DEBUG_DEVMAPPER
+    LOG_VOL("loopback_start(%s):", dm->type_data.loop.loop_src);
+#endif
+
+    for (i = 0; i < MAX_LOOP; i++) {
+        struct loop_info info;
+
+        sprintf(filename, "/dev/block/loop%d", i);
+
+        if ((fd = open(filename, O_RDWR)) < 0) {
+            LOGE("Unable to open %s (%s)\n", filename, strerror(errno));
+            return -errno;
+        }
+
+        rc = ioctl(fd, LOOP_GET_STATUS, &info);
+        if (rc < 0 && errno == ENXIO)
+            break;
+
+        close(fd);
+
+        if (rc < 0) {
+            LOGE("Unable to get loop status for %s (%s)\n", filename,
+                 strerror(errno));
+            return -errno;
+        }
+    }
+
+    if (i == MAX_LOOP) {
+        LOGE("Out of loop devices\n");
+        return -ENOSPC;
+    }
+
+    int file_fd;
+
+    if ((file_fd = open(dm->type_data.loop.loop_src, O_RDWR)) < 0) {
+        LOGE("Unable to open %s (%s)\n", dm->type_data.loop.loop_src,
+             strerror(errno));
+        return -errno;
+    }
+
+    if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
+        LOGE("Error setting up loopback interface (%s)\n", strerror(errno));
+        return -errno;
+    }
+
+    dm->type_data.loop.loop_dev = strdup(filename);
+    dm->type_data.loop.loop_no  = i;
+
+    close(fd);
+    close(file_fd);
+
+#if DEBUG_DEVMAPPER
+    LOG_VOL("Loop setup on %s for %s\n", dm->type_data.loop.loop_dev,
+            dm->type_data.loop.loop_src);
+#endif
+
+    return 0;
+}
+
+int devmapper_start(struct devmapping *dm)
+{
+    int rc;
+    char src_blkdev_path[255];
+
+#if DEBUG_DEVMAPPER
+    LOG_VOL("devmapper_start()");
+#endif
+
+    if (dm->src_type == dmsrc_loopback) {
+       if ((rc = loopback_start(dm)) < 0)
+           return rc;
+    } else if (dm->src_type == dmsrc_partition) {
+        LOGE("partition maps not yet supported");
+        return -ENOSYS;
+    } else {
+        LOGE("devmapper_start(): Unsupported source type '%d'", dm->src_type);
+        return -ENOENT;
+    }
+
+    /*
+     * Configure the device mapper
+     */
+
+    return 0;
+}
+
+struct devmapping *devmapper_init(char *src, char *src_type, uint32_t size_mb,
+                  char *target, char *params, char *tgt_fs)
+{
+    struct devmapping *dm;
+
+    if (!(dm = malloc(sizeof(struct devmapping)))) {
+        LOGE("devmapper_init(): out of memory");
+        return NULL;
+    }
+
+    memset(dm, 0, sizeof(struct devmapping));
+
+    if (!strcmp(src_type, "loopback_file")) {
+        dm->src_type = dmsrc_loopback;
+        dm->type_data.loop.loop_src = strdup(src);
+    } else if (!strncmp(src_type, "partition ", strlen("partition "))) {
+        dm->src_type = dmsrc_partition;
+        char *p = strtok(src_type, " ");
+        if (!p) {
+            LOGE("Invalid partition specifier");
+            goto out_free;
+        }
+        dm->type_data.part.part_type = strtoul(p, NULL, 0);
+    } else {
+        LOGE("Invalid src_type defined (%s)", src_type);
+        goto out_free;
+    }
+    
+    // XXX: Validate these
+    dm->size_mb = size_mb;
+    dm->target = strdup(target);
+    dm->params = strdup(params);
+    dm->tgt_fs = strdup(tgt_fs);
+
+    return dm;
+ out_free:
+    return NULL;
+}
diff --git a/vold/devmapper.h b/vold/devmapper.h
new file mode 100644
index 0000000..bea8521
--- /dev/null
+++ b/vold/devmapper.h
@@ -0,0 +1,64 @@
+
+/*
+ * 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.
+ */
+
+#ifndef _DEVMAPPER_H
+#define _DEVMAPPER_H
+
+#include <pthread.h>
+
+#include "vold.h"
+#include "blkdev.h"
+#include "media.h"
+
+#define MAX_LOOP 8
+
+enum dm_src_type {
+    dmsrc_unknown,
+    dmsrc_loopback,
+    dmsrc_partition,
+};
+
+struct loop_data {
+    char *loop_src;
+
+    char *loop_dev;
+    int  loop_no;
+};
+
+struct part_data {
+    char part_type;
+    
+    char *part_dev;
+};
+
+struct devmapping {
+        enum dm_src_type src_type;
+        union {
+            struct loop_data loop;
+            struct part_data part;
+        } type_data;
+        
+        uint32_t         size_mb;
+	char             *target;
+        char             *params;
+        char             *tgt_fs;
+};
+
+struct devmapping *devmapper_init(char *, char *, unsigned int, char *, char *, char*);
+int devmapper_start(struct devmapping *);
+int devmapper_stop(struct devmapping *);
+#endif
diff --git a/vold/format.c b/vold/format.c
new file mode 100755
index 0000000..b413cc7
--- /dev/null
+++ b/vold/format.c
@@ -0,0 +1,100 @@
+
+/*
+ * 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 <fcntl.h>
+#include <errno.h>
+
+#include <linux/fs.h>
+
+#include "vold.h"
+#include "blkdev.h"
+#include "format.h"
+#include "diskmbr.h"
+#include "logwrapper.h"
+
+static char MKDOSFS_PATH[] = "/system/bin/mkdosfs";
+
+int format_partition(blkdev_t *part)
+{
+    char *devpath;
+    char *args[7];
+
+    devpath = blkdev_get_devpath(part);
+
+    args[0] = MKDOSFS_PATH;
+    args[1] = "-F 32";
+    args[2] = "-c 32";
+    args[3] = "-n 2";
+    args[4] = "-O android";
+    args[5] = devpath;
+    args[6] = NULL;
+
+    int rc = logwrap(6, args);
+ 
+    free(devpath);
+
+    if (rc == 0) {
+        LOG_VOL("Filesystem formatted OK\n");
+        return 0;
+    } else {
+        LOGE("Format failed (unknokwn exit code %d)\n", rc);
+        return -EIO;
+    }
+    return 0;
+}
+
+int initialize_mbr(blkdev_t *disk)
+{
+    int fd, rc;
+    unsigned char block[512];
+    struct dos_partition part;
+    char *devpath;
+
+    devpath = blkdev_get_devpath(disk);
+
+    memset(&part, 0, sizeof(part));
+    part.dp_flag = 0x80;
+    part.dp_typ = 0xc;
+    part.dp_start = ((1024 * 64) / 512) + 1;
+    part.dp_size = disk->nr_sec - part.dp_start;
+
+    memset(block, 0, sizeof(block));
+    block[0x1fe] = 0x55;
+    block[0x1ff] = 0xaa;
+
+    dos_partition_enc(block + DOSPARTOFF, &part);
+
+    if ((fd = open(devpath, O_RDWR)) < 0) {
+        LOGE("Error opening disk file (%s)\n", strerror(errno));
+        return -errno;
+    }
+    free(devpath);
+
+    if (write(fd, block, sizeof(block)) < 0) {
+        LOGE("Error writing MBR (%s)\n", strerror(errno));
+        close(fd);
+        return -errno;
+    }
+
+    if (ioctl(fd, BLKRRPART, NULL) < 0) {
+        LOGE("Error re-reading partition table (%s)\n", strerror(errno));
+        close(fd);
+        return -errno;
+    }
+    close(fd);
+    return 0;
+}
diff --git a/vold/inotify.h b/vold/format.h
similarity index 84%
copy from vold/inotify.h
copy to vold/format.h
index ada42a8..3000b10 100644
--- a/vold/inotify.h
+++ b/vold/format.h
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 
-#ifndef _INOTIFY_EVT_H
-#define _INOTIFY_EVT_H
+#ifndef _FORMAT_H
+#define _FORMAT_H
 
-
+int format_partition(blkdev_t *part);
+int initialize_mbr(blkdev_t *disk);
 #endif
diff --git a/vold/geom_mbr_enc.c b/vold/geom_mbr_enc.c
index 755fbba..f1f8339 100644
--- a/vold/geom_mbr_enc.c
+++ b/vold/geom_mbr_enc.c
@@ -44,6 +44,17 @@
         return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
 }
 
+static __inline void
+le32enc(void *pp, uint32_t u)
+{
+        unsigned char *p = (unsigned char *)pp;
+
+        p[0] = u & 0xff;
+        p[1] = (u >> 8) & 0xff;
+        p[2] = (u >> 16) & 0xff;
+        p[3] = (u >> 24) & 0xff;
+}
+
 void
 dos_partition_dec(void const *pp, struct dos_partition *d)
 {
@@ -60,3 +71,20 @@
         d->dp_start = le32dec(p + 8);
         d->dp_size = le32dec(p + 12);
 }
+
+void
+dos_partition_enc(void *pp, struct dos_partition *d)
+{
+        unsigned char *p = pp;
+
+        p[0] = d->dp_flag;
+        p[1] = d->dp_shd;
+        p[2] = d->dp_ssect;
+        p[3] = d->dp_scyl;
+        p[4] = d->dp_typ;
+        p[5] = d->dp_ehd;
+        p[6] = d->dp_esect;
+        p[7] = d->dp_ecyl;
+        le32enc(p + 8, d->dp_start);
+        le32enc(p + 12, d->dp_size);
+}
diff --git a/vold/inotify.c b/vold/inotify.c
deleted file mode 100644
index a7b789c..0000000
--- a/vold/inotify.c
+++ /dev/null
@@ -1,270 +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 <sys/types.h>
-#include <sys/inotify.h>
-#include <sys/stat.h>
-
-#include "vold.h"
-#include "inotify.h"
-#include "blkdev.h"
-#include "volmgr.h"
-
-#define DEBUG_INOTIFY 0
-
-static int handle_inotify_event(struct inotify_event *evt);
-
-int process_inotify_event(int fd)
-{
-    char buffer[512];
-    int len;
-    int offset = 0;
-  
-    if ((len = read(fd, buffer, sizeof(buffer))) < 0) {
-        LOGE("Unable to read inotify event (%m)\n");
-        return -errno;
-    }
-
-    while (len >= (int) sizeof(struct inotify_event)) {
-        struct inotify_event *evt = (struct inotify_event *) &buffer[offset];
-   
-        if (handle_inotify_event(evt) < 0)
-            LOGE("Error handling inotify event (%m)\n");
-      
-        len -= sizeof(struct inotify_event) + evt->len;
-        offset += sizeof(struct inotify_event) + evt->len;
-         
-    }
-    return 0;
-}
-
-struct blk_dev_entry {
-    int minor;
-    char *name;
-    struct blk_dev_entry *next;
-};
-
-int inotify_bootstrap(void)
-{
-    DIR *d;
-    struct dirent *de;
-
-    if (!(d = opendir(DEVPATH))) {
-        LOGE("Unable to open directory '%s' (%m)\n", DEVPATH);
-        return -errno;
-    }
-
-    struct blk_dev_entry *blkdevs[255];
-
-    memset(blkdevs, 0, sizeof(blkdevs));
-
-    while((de = readdir(d))) {
-        char filename[255];
-        struct stat sbuf;
-
-        if (de->d_name[0] == '.')
-            continue;
-
-        sprintf(filename, "%s/%s", DEVPATH, de->d_name);
-
-        if (stat(filename, &sbuf) < 0) {
-            LOGE("Unable to stat '%s' (%m)\n", filename);
-            continue;
-        }
-
-        if (!S_ISBLK(sbuf.st_mode))
-            continue;
-
-
-        int major = (sbuf.st_rdev & 0xfff00) >> 8;
-        int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
-
-        struct blk_dev_entry *entry;
-
-        if (!(entry = malloc(sizeof(struct blk_dev_entry)))) {
-            LOGE("Out of memory\n");
-            break;
-        }
-        entry->minor = minor;
-        entry->name = strdup(de->d_name);
-        entry->next = NULL;
-
-        if (!blkdevs[major])
-            blkdevs[major] = entry;
-        else {
-            struct blk_dev_entry *scan = blkdevs[major];
-
-            /*
-             * Insert the entry in minor number ascending order
-             */
-            while(scan) {
-                if (minor < scan->minor) {
-                    entry->next = scan;
-
-                    if (scan == blkdevs[major])
-                        blkdevs[major] = entry;
-                    else
-                        scan->next = entry;
-                    break;
-                }
-                scan = scan->next;
-            }
-            if (!scan) {
-                scan = blkdevs[major];
-                while(scan->next)
-                    scan = scan->next;
-                scan->next = entry;
-            }
-        }
-
-    }
-
-    closedir(d);
-
-    int i = 0;
-
-    for (i = 0; i < 255; i++) {
-        if (!blkdevs[i])
-            continue;
-        struct blk_dev_entry *scan = blkdevs[i];
-
-        while(scan) {
-            struct inotify_event *evt;
-            int len;
-
-            len = sizeof(struct inotify_event) + strlen(scan->name);
-
-            if (!(evt = malloc(len))) {
-                LOGE("Out of memory\n");
-                break;
-            }
-            memset(evt, 0, len);
-            strcpy(evt->name, scan->name);
-            evt->mask = IN_CREATE;
-
-            if (handle_inotify_event(evt) < 0)
-                LOGE("Error handling bootstrapped inotify event (%m)\n");
-            free(evt);
-
-            scan = scan->next;
-        }
-    }
-
-    for (i = 0; i < 255; i++) {
-        if (!blkdevs[i])
-            continue;
-
-        if (!blkdevs[i]->next) {
-            free(blkdevs[i]->name);
-            free(blkdevs[i]);
-            blkdevs[i] = NULL;
-            continue;
-        } 
-
-        struct blk_dev_entry *scan = blkdevs[i];
-        while(scan) {
-            struct blk_dev_entry *next = scan->next->next;
-              
-            free(scan->next->name);
-            free(scan->next);
-
-            scan->next = next;
-            scan = next;
-        }
-
-    } // for
-
-
-    return 0;
-}
-
-static int handle_inotify_event(struct inotify_event *evt)
-{
-    char filename[255];
-    int rc;
-
-#if DEBUG_INOTIFY
-    LOG_VOL("Inotify '%s' %s\n", evt->name, (evt->mask == IN_CREATE ? "created" : "deleted"));
-#endif
-
-    sprintf(filename, "%s%s", DEVPATH, evt->name);
-
-    if (evt->mask == IN_CREATE) {
-        struct stat sbuf;
-
-        if (stat(filename, &sbuf) < 0) {
-            LOGE("Unable to stat '%s' (%m)\n", filename);
-            return -errno;
-        }
-
-        if (!S_ISBLK(sbuf.st_mode)) {
-#if DEBUG_INOTIFY
-            LOG_VOL("Ignoring inotify on '%s' (not a block device)\n", evt->name);
-#endif
-            return 0;
-        }
-
-        int major = (sbuf.st_rdev & 0xfff00) >> 8;
-        int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
-
-        blkdev_t *blkdev = blkdev_lookup_by_devno(major, minor);
-
-        if ((rc = blkdev_handle_devicefile_created(blkdev, filename)) < 0) {
-            LOGE("Error handling device file '%s' creation (%s)\n", filename, strerror(rc));
-            return rc;
-        }
-     
-        if (!blkdev) {
-#if DEBUG_INOTIFY
-            LOG_VOL("No backing blkdev for '%s' available (yet) - pending volmgr dispatch\n", filename);
-#endif
-            return 0;
-        }
- 
-#if DEBUG_INOTIFY
-        LOG_VOL("NUM_PENDING_PARTITIONS = %d\n", blkdev_get_num_pending_partitions(blkdev));
-#endif
-        if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
-            if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
-                LOGE("Error from volmgr - %d\n", rc);
-                return rc;
-            }
-        }
-    } else {
-        blkdev_t *blkdev;
-
-        if (!(blkdev = blkdev_lookup_by_dev_fspath(filename))) {
-#if DEBUG_INOTIFY
-            LOG_VOL("Ignoring removal of '%s' (no backend blkdev)\n", filename);
-#endif
-            return 0;
-        }
-
-        if ((rc = blkdev_handle_devicefile_removed(blkdev, filename)) < 0) {
-            LOGE("Error handling device file '%s' removal (%s)\n", filename, strerror(rc));
-            return rc;
-        }
-    }
-
-    return 0;
-}
diff --git a/vold/media.c b/vold/media.c
index f385586..58eef82 100644
--- a/vold/media.c
+++ b/vold/media.c
@@ -85,8 +85,8 @@
     free(media->devpath);
     free(media->name);
 
-    if (media->devs)
-        LOGE("media_destroy(): media still has blkdevs associated with it! Possible leak\n");
+    while(media->devs)
+        media_remove_blkdev(media, media->devs->dev);
     free(media);
 }
 
diff --git a/vold/media.h b/vold/media.h
index 84c3947..567ce04 100644
--- a/vold/media.h
+++ b/vold/media.h
@@ -25,7 +25,7 @@
 typedef enum media_type {
     media_unknown,
     media_mmc,
-    media_dm
+    media_devmapper,
 } media_type_t;
 
 typedef struct media {
diff --git a/vold/mmc.c b/vold/mmc.c
index a4c93c5..dc19994 100644
--- a/vold/mmc.c
+++ b/vold/mmc.c
@@ -118,7 +118,7 @@
      * sysfs_path is based on /sys/class, but we want the actual device class
      */
     if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
-        LOGE("Buffer too small for working dir path\n");
+        LOGE("Error getting working dir path\n");
         return -errno;
     }
     
diff --git a/vold/switch.c b/vold/switch.c
new file mode 100644
index 0000000..72121d9
--- /dev/null
+++ b/vold/switch.c
@@ -0,0 +1,121 @@
+
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+
+#include <sys/types.h>
+
+#include "vold.h"
+#include "switch.h"
+
+#define DEBUG_BOOTSTRAP 0
+
+static int mmc_bootstrap_switch(char *sysfs_path);
+
+int switch_bootstrap()
+{
+    DIR *d;
+    struct dirent *de;
+
+    if (!(d = opendir(SYSFS_CLASS_SWITCH_PATH))) {
+        LOG_ERROR("Unable to open '%s' (%m)\n", SYSFS_CLASS_SWITCH_PATH);
+        return -errno;
+    }
+
+    while ((de = readdir(d))) {
+        char tmp[255];
+
+        if (de->d_name[0] == '.')
+            continue;
+
+        sprintf(tmp, "%s/%s", SYSFS_CLASS_SWITCH_PATH, de->d_name);
+        if (mmc_bootstrap_switch(tmp))
+            LOG_ERROR("Error bootstrapping switch '%s' (%m)\n", tmp);
+    }
+
+    closedir(d);
+
+    return 0;
+}
+
+static int mmc_bootstrap_switch(char *sysfs_path)
+{
+#if DEBUG_BOOTSTRAP
+    LOG_VOL("bootstrap_switch(%s):\n", sysfs_path);
+#endif
+
+    char filename[255];
+    char name[255];
+    char state[255];
+    char tmp[255];
+    char *uevent_params[3];
+    char devpath[255];
+    FILE *fp;
+
+    /*
+     * Read switch name
+     */
+    sprintf(filename, "%s/name", sysfs_path);
+    if (!(fp = fopen(filename, "r"))) {
+        LOGE("Error opening switch name path '%s' (%s)\n",
+             sysfs_path, strerror(errno));
+       return -errno;
+    }
+    if (!fgets(name, sizeof(name), fp)) {
+        LOGE("Unable to read switch name\n");
+        fclose(fp);
+        return -EIO;
+    }
+    fclose(fp);
+
+    name[strlen(name) -1] = '\0';
+    sprintf(devpath, "/devices/virtual/switch/%s", name);
+    sprintf(tmp, "SWITCH_NAME=%s", name);
+    uevent_params[0] = (char *) strdup(tmp);
+
+    /*
+     * Read switch state
+     */
+    sprintf(filename, "%s/state", sysfs_path);
+    if (!(fp = fopen(filename, "r"))) {
+        LOGE("Error opening switch state path '%s' (%s)\n",
+             sysfs_path, strerror(errno));
+       return -errno;
+    }
+    if (!fgets(state, sizeof(state), fp)) {
+        LOGE("Unable to read switch state\n");
+        fclose(fp);
+        return -EIO;
+    }
+    fclose(fp);
+
+    state[strlen(state) -1] = '\0';
+    sprintf(tmp, "SWITCH_STATE=%s", state);
+    uevent_params[1] = (char *) strdup(tmp);
+
+    uevent_params[2] = (char *) NULL;
+
+    if (simulate_uevent("switch", devpath, "add", uevent_params) < 0) {
+        LOGE("Error simulating uevent (%s)\n", strerror(errno));
+        return -errno;
+    }
+
+    return 0;   
+}
diff --git a/vold/inotify.h b/vold/switch.h
similarity index 85%
rename from vold/inotify.h
rename to vold/switch.h
index ada42a8..6729f2d 100644
--- a/vold/inotify.h
+++ b/vold/switch.h
@@ -15,8 +15,11 @@
  * limitations under the License.
  */
 
-#ifndef _INOTIFY_EVT_H
-#define _INOTIFY_EVT_H
+#ifndef _SWITCH_H
+#define _SWITCH_H
 
+#include "vold.h"
+
+#define SYSFS_CLASS_SWITCH_PATH "/sys/class/switch"
 
 #endif
diff --git a/vold/uevent.c b/vold/uevent.c
index 6b724d0..e195066 100644
--- a/vold/uevent.c
+++ b/vold/uevent.c
@@ -71,6 +71,9 @@
     { NULL, NULL }
 };
 
+static boolean low_batt = false;
+static boolean door_open = false;
+
 int process_uevent_message(int socket)
 {
     char buffer[64 * 1024]; // Thank god we're not in the kernel :)
@@ -120,7 +123,7 @@
             else
                 event->param[param_idx++] = strdup(s);
         }
-        s+= (strlen(s) + 1);
+        s+= strlen(s) + 1;
     }
 
     rc = dispatch_uevent(event);
@@ -172,6 +175,9 @@
 {
     int i;
 
+#if DEBUG_UEVENT
+    dump_uevent(event);
+#endif
     for (i = 0; dispatch_table[i].subsystem != NULL; i++) {
         if (!strcmp(dispatch_table[i].subsystem, event->subsystem))
             return dispatch_table[i].dispatch(event);
@@ -232,7 +238,19 @@
 
 static int handle_powersupply_event(struct uevent *event)
 {
-    dump_uevent(event);
+    char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE");
+    char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY");
+
+    if (!strcasecmp(ps_type, "battery")) {
+        int capacity = atoi(ps_cap);
+  
+        if (capacity < 5)
+            low_batt = true;
+        else
+            low_batt = false;
+LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d\n", low_batt, door_open);
+        volmgr_safe_mode(low_batt || door_open);
+    }
     return 0;
 }
 
@@ -241,12 +259,21 @@
     char *name = get_uevent_param(event, "SWITCH_NAME");
     char *state = get_uevent_param(event, "SWITCH_STATE");
 
+
     if (!strcmp(name, "usb_mass_storage")) {
         if (!strcmp(state, "online")) {
             ums_hostconnected_set(true);
         } else {
             ums_hostconnected_set(false);
+            volmgr_enable_ums(false);
         }
+    } else if (!strcmp(name, "sd-door")) {
+        if (!strcmp(state, "open"))
+            door_open = true;
+        else
+            door_open = false;
+LOG_VOL("handle_powersupply_event(): low_batt = %d, door_open = %d\n", low_batt, door_open);
+        volmgr_safe_mode(low_batt || door_open);
     } else
         LOG_VOL("handle_switch_event(): Ignoring switch '%s'\n", name);
 
@@ -255,7 +282,6 @@
 
 static int handle_battery_event(struct uevent *event)
 {
-    dump_uevent(event);
     return 0;
 }
 
@@ -293,7 +319,6 @@
 
     if (event->action == action_add) {
         blkdev_t *disk;
-        boolean pending = false;
 
         /*
          * If there isn't a disk already its because *we*
@@ -301,26 +326,18 @@
          */
         disk = blkdev_lookup_by_devno(maj, 0);
 
-        /*
-         * It is possible that there is already a blkdev
-         * for this device (created by blkdev_create_pending_partition())
-         */
-
-        if ((blkdev = blkdev_lookup_by_devno(maj, min))) {
-            blkdev_devpath_set(blkdev, event->path);
-            pending = true;
-        } else {
-            if (!(blkdev = blkdev_create(disk,
-                                         event->path,
-                                         maj,
-                                         min,
-                                         media,
-                                         get_uevent_param(event, "DEVTYPE")))) {
-                LOGE("Unable to allocate new blkdev (%m)\n");
-                return -1;
-            }
+        if (!(blkdev = blkdev_create(disk,
+                                     event->path,
+                                     maj,
+                                     min,
+                                     media,
+                                     get_uevent_param(event, "DEVTYPE")))) {
+            LOGE("Unable to allocate new blkdev (%m)\n");
+            return -1;
         }
 
+        blkdev_refresh(blkdev);
+
         /*
          * Add the blkdev to media
          */
@@ -330,39 +347,33 @@
             return rc;
         }
 
-        LOG_VOL("New blkdev %d.%d on media %s, media path %s\n", blkdev->major, blkdev->minor, media->name, mediapath);
+        LOG_VOL("New blkdev %d.%d on media %s, media path %s, Dpp %d\n",
+                blkdev->major, blkdev->minor, media->name, mediapath,
+                blkdev_get_num_pending_partitions(blkdev->disk));
 
-        if (pending) {
-            /*
-             * This blkdev already has its dev_fspath set so 
-             * if all partitions are read, pass it off to
-             * the volume manager
-             */
-            LOG_VOL("Pending disk '%d.%d' has %d pending partitions\n",
-                    blkdev->disk->major, blkdev->disk->minor, 
-                    blkdev_get_num_pending_partitions(blkdev->disk));
-
-            if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
-                if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
-                    LOGE("Volmgr failed to handle pending device (%d)\n", rc);
-                    return rc;
-                }
+        if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
+            if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
+                LOGE("Volmgr failed to handle device (%d)\n", rc);
+                return rc;
             }
         }
     } else if (event->action == action_remove) {
-        int rc;
-
-        if (!(blkdev = blkdev_lookup_by_devno(maj, min))) {
-#if DEBUG_UEVENT
-            LOG_VOL("We aren't handling blkdev @ %s\n", event->path);
-#endif
+        if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
             return 0;
-        }
 
-        LOG_VOL("Destroying blkdev %d.%d @ %s on media %s\n", blkdev->major, blkdev->minor, blkdev->devpath, media->name);
-        if ((rc = volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy)) < 0)
-            LOGE("Error notifying volmgr of eject\n");
-    } else {
+        LOG_VOL("Destroying blkdev %d.%d @ %s on media %s\n", blkdev->major,
+                blkdev->minor, blkdev->devpath, media->name);
+        volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy);
+
+    } else if (event->action == action_change) {
+        if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
+            return 0;
+
+        LOG_VOL("Modified blkdev %d.%d @ %s on media %s\n", blkdev->major,
+                blkdev->minor, blkdev->devpath, media->name);
+        
+        blkdev_refresh(blkdev);
+    } else  {
 #if DEBUG_UEVENT
         LOG_VOL("No handler implemented for action %d\n", event->action);
 #endif
@@ -417,9 +428,6 @@
 
         LOG_VOL("MMC card '%s' (serial %u) @ %s removed\n", media->name, 
                   media->serial, media->devpath);
-        /*
-         * If this media is still mounted, then we have an unsafe removal
-         */
         media_destroy(media);
     } else {
 #if DEBUG_UEVENT
diff --git a/vold/ums.c b/vold/ums.c
index a6468fc..2686b6f 100644
--- a/vold/ums.c
+++ b/vold/ums.c
@@ -21,6 +21,8 @@
 #include "vold.h"
 #include "ums.h"
 
+#define DEBUG_UMS 0
+
 static boolean host_connected = false;
 static boolean ums_enabled = false;
 
@@ -42,7 +44,9 @@
 
 void ums_hostconnected_set(boolean connected)
 {
+#if DEBUG_UMS
     LOG_VOL("ums_hostconnected_set(%d):\n", connected);
+#endif
     host_connected = connected;
 
     if (!connected)
@@ -75,7 +79,9 @@
 
 int ums_disable(char *lun_syspath)
 {
+#if DEBUG_UMS
     LOG_VOL("ums_disable(%s):\n", lun_syspath);
+#endif
 
     int fd;
     char filename[255];
@@ -107,7 +113,9 @@
 {
     int rc;
 
+#if DEBUG_UMS
     LOG_VOL("ums_send_status():\n");
+#endif
 
     rc = send_msg(ums_enabled_get() ? VOLD_EVT_UMS_ENABLED :
                                       VOLD_EVT_UMS_DISABLED);
diff --git a/vold/vold.c b/vold/vold.c
index b2c8eb2..4c74136 100644
--- a/vold/vold.c
+++ b/vold/vold.c
@@ -27,7 +27,6 @@
 #include <sys/select.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#include <sys/inotify.h>
 #include <sys/un.h>
 
 #include <cutils/config_utils.h>
@@ -57,7 +56,6 @@
 int main(int argc, char **argv)
 {
     int door_sock = -1;
-    int inotify_sock = -1;
     int uevent_sock = -1;
     struct sockaddr_nl nladdr;
     int uevent_sz = 64 * 1024;
@@ -81,18 +79,7 @@
         exit(1);
     }
 
-    // Socket to listen on for changes to /dev/block
-    if ((inotify_sock = inotify_init()) < 0) {
-        LOGE("Unable to initialize inotify interface (%s)\n", strerror(errno));
-        exit(1);
-    }
-
-    fcntl(inotify_sock, F_SETFL, O_NONBLOCK | fcntl(inotify_sock, F_GETFL));
-    
-    if (inotify_add_watch(inotify_sock, DEVPATH, IN_CREATE | IN_DELETE) < 0) {
-        LOGE("Unable to add inotify watch (%s)\n", strerror(errno));
-        exit(1);
-    }
+    mkdir("/dev/block/vold", 0755);
 
     // Socket to listen on for uevent changes
     memset(&nladdr, 0, sizeof(nladdr));
@@ -121,22 +108,22 @@
      * Bootstrap 
      */
 
+    // Volume Manager
+    volmgr_bootstrap();
+
     // SD Card system
     mmc_bootstrap();
 
     // USB Mass Storage
     ums_bootstrap();
 
-    // Volume Manager
-    volmgr_bootstrap();
-
-    // Block device system
-    inotify_bootstrap();
+    // Switch
+    switch_bootstrap();
 
     /*
      * Main loop
      */
-
+    LOG_VOL("Bootstrapping complete\n");
     while(1) {
         fd_set read_fds;
         struct timeval to;
@@ -146,12 +133,10 @@
         to.tv_sec = (60 * 60);
         to.tv_usec = 0;
 
+        FD_ZERO(&read_fds);
         FD_SET(door_sock, &read_fds);
         if (door_sock > max)
             max = door_sock;
-        FD_SET(inotify_sock, &read_fds);
-        if (inotify_sock > max)
-            max = inotify_sock;
         FD_SET(uevent_sock, &read_fds);
         if (uevent_sock > max)
             max = uevent_sock;
@@ -178,6 +163,13 @@
 
             alen = sizeof(addr);
 
+            if (fw_sock != -1) {
+                LOGE("Dropping duplicate framework connection\n");
+                int tmp = accept(door_sock, &addr, &alen);
+                close(tmp);
+                continue;
+            }
+
             if ((fw_sock = accept(door_sock, &addr, &alen)) < 0) {
                 LOGE("Unable to accept framework connection (%s)\n",
                      strerror(errno));
@@ -201,19 +193,11 @@
             }
         }
 
-        if (FD_ISSET(inotify_sock, &read_fds)) {
-            if ((rc = process_inotify_event(inotify_sock)) < 0) {
-                LOGE("Error processing inotify msg (%s)\n", strerror(errno));
-            }
-        }
-
         if (FD_ISSET(uevent_sock, &read_fds)) {
             if ((rc = process_uevent_message(uevent_sock)) < 0) {
                 LOGE("Error processing uevent msg (%s)\n", strerror(errno));
             }
         }
-      
-
     } // while
 
 }
diff --git a/vold/vold.h b/vold/vold.h
index f25fcff..0876bec 100644
--- a/vold/vold.h
+++ b/vold/vold.h
@@ -86,6 +86,8 @@
 
 int volmgr_bootstrap(void);
 
+int switch_bootstrap(void);
+
 void *read_file(char *filename, ssize_t *_size);
 char *truncate_sysfs_path(char *path, int num_elements_to_remove, char *buffer);
 char *read_sysfs_var(char *buffer, size_t maxlen, char *devpath, char *var);
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;
 }
 
diff --git a/vold/volmgr.h b/vold/volmgr.h
index a7f5701..98c1561 100644
--- a/vold/volmgr.h
+++ b/vold/volmgr.h
@@ -23,6 +23,7 @@
 #include "vold.h"
 #include "blkdev.h"
 #include "media.h"
+#include "devmapper.h"
 
 #define PROP_EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
 
@@ -70,15 +71,18 @@
     volstate_ejecting,
 #define VOLD_EVT_EJECTING        "volume_ejecting:"
 #define VOLD_ES_PVAL_EJECTING    "ejecting"
+
+    volstate_formatting,
 } volume_state_t;
 
 struct volume;
 
 struct volmgr_fstable_entry {
     char *name;
-    int (*identify_fn) (blkdev_t *dev);
-    int (*check_fn) (blkdev_t *dev);
-    int (*mount_fn) (blkdev_t *dev, struct volume *vol);
+    int     (*identify_fn) (blkdev_t *dev);
+    int     (*check_fn) (blkdev_t *dev);
+    int     (*mount_fn) (blkdev_t *dev, struct volume *vol, boolean safe_mode);
+    boolean case_sensitive_paths;
 };
 
 struct volmgr_start_args {
@@ -86,21 +90,38 @@
     blkdev_t                    *dev;
 };
 
+struct volmgr_reaper_args {
+    void (*cb) (struct volume *, void *);
+    void *cb_arg;
+};
+
+#define VOLMGR_MAX_MEDIAPATHS_PER_VOLUME 8
+
 typedef struct volume {
-    char            *media_path;
-    media_type_t    media_type;
-    char            *mount_point;
-    char            *ums_path;
+    char            *media_paths[VOLMGR_MAX_MEDIAPATHS_PER_VOLUME];
+
+    media_type_t      media_type;
+    char              *mount_point;
+    char              *ums_path;
+    struct devmapping *dm;
 
     pthread_mutex_t          lock;
     volume_state_t           state;
     blkdev_t                 *dev;
     pid_t                    worker_pid;
     pthread_t                worker_thread;
-    struct volmgr_start_args worker_args;
+    union {
+        struct volmgr_start_args  start_args;
+        struct volmgr_reaper_args reaper_args;
+    } worker_args;
     boolean                  worker_running;
     pthread_mutex_t          worker_sem;
 
+    struct volmgr_fstable_entry *fs;
+
+    unsigned char            *key;
+    unsigned int             keysize;
+
     struct volume            *next;
 } volume_t;
 
@@ -110,6 +131,8 @@
 int volmgr_enable_ums(boolean enable);
 int volmgr_stop_volume_by_mountpoint(char *mount_point);
 int volmgr_start_volume_by_mountpoint(char *mount_point);
-
+int volmgr_safe_mode(boolean enable);
+int volmgr_format_volume(char *mount_point);
+int volmgr_set_volume_key(char *mount_point, unsigned char *key, unsigned int keysize);
 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded);
 #endif
diff --git a/vold/volmgr_ext3.c b/vold/volmgr_ext3.c
index 2be07fb..3af113f 100644
--- a/vold/volmgr_ext3.c
+++ b/vold/volmgr_ext3.c
@@ -15,34 +15,170 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <errno.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <linux/ext2_fs.h>
+#include <linux/ext3_fs.h>
+
 #include "vold.h"
 #include "volmgr.h"
 #include "volmgr_ext3.h"
+#include "logwrapper.h"
 
-#define EXT3_DEBUG 0
 
-int ext3_identify(blkdev_t *dev)
+#define EXT_DEBUG 0
+
+static char E2FSCK_PATH[] = "/system/bin/e2fsck";
+
+int ext_identify(blkdev_t *dev)
 {
-#if EXT3_DEBUG
-    LOG_VOL("ext3_identify(%s):\n", dev->dev_fspath);
+    int rc = -1;
+    int fd;
+    struct ext3_super_block sb;
+    char *devpath;
+
+#if EXT_DEBUG
+    LOG_VOL("ext_identify(%d:%d):\n", dev-major, dev->minor);
 #endif
-    return -ENOSYS;
+
+    devpath = blkdev_get_devpath(dev);
+
+    if ((fd = open(devpath, O_RDWR)) < 0) {
+        LOGE("Unable to open device '%s' (%s)\n", devpath,
+             strerror(errno));
+        free(devpath);
+        return -errno;
+    }
+
+    if (lseek(fd, 1024, SEEK_SET) < 0) {
+        LOGE("Unable to lseek to get superblock (%s)\n", strerror(errno));
+        rc =  -errno;
+        goto out;
+    }
+
+    if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
+        LOGE("Unable to read superblock (%s)\n", strerror(errno));
+        rc =  -errno;
+        goto out;
+    }
+
+    if (sb.s_magic == EXT2_SUPER_MAGIC ||
+        sb.s_magic == EXT3_SUPER_MAGIC)
+        rc = 0;
+    else
+        rc = -ENODATA;
+
+ out:
+#if EXT_DEBUG
+    LOG_VOL("ext_identify(%s): rc = %d\n", devpath, rc);
+#endif
+    free(devpath);
+    close(fd);
+    return rc;
 }
 
-int ext3_check(blkdev_t *dev)
+int ext_check(blkdev_t *dev)
 {
-#if EXT3_DEBUG
-    LOG_VOL("ext3_check(%s):\n", dev->dev_fspath);
+    char *devpath;
+
+#if EXT_DEBUG
+    LOG_VOL("ext_check(%s):\n", dev->dev_fspath);
 #endif
-    return -ENOSYS;
+
+    devpath = blkdev_get_devpath(dev);
+
+    if (access(E2FSCK_PATH, X_OK)) {
+        LOGE("ext_check(%s): %s not found (skipping checks)\n",
+             devpath, E2FSCK_PATH);
+        free(devpath);
+        return 0;
+    }
+
+    char *args[5];
+
+    args[0] = E2FSCK_PATH;
+    args[1] = "-v";
+    args[2] = "-p";
+    args[3] = devpath;
+    args[4] = NULL;
+
+    int rc = logwrap(4, args);
+
+    if (rc == 0) {
+        LOG_VOL("filesystem '%s' had no errors\n", devpath);
+    } else if (rc == 1) {
+        LOG_VOL("filesystem '%s' had corrected errors\n", devpath);
+        rc = 0;
+    } else if (rc == 2) {
+        LOGE("VOL volume '%s' had corrected errors (system should be rebooted)\n", devpath);
+        rc = -EIO;
+    } else if (rc == 4) {
+        LOGE("VOL volume '%s' had uncorrectable errors\n", devpath);
+        rc = -EIO;
+    } else if (rc == 8) {
+        LOGE("Operational error while checking volume '%s'\n", devpath);
+        rc = -EIO;
+    } else {
+        LOGE("Unknown e2fsck exit code (%d)\n", rc);
+        rc = -EIO;
+    }
+    free(devpath);
+    return rc;
 }
 
-int ext3_mount(blkdev_t *dev, volume_t *vol)
+int ext_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode)
 {
-#if EXT3_DEBUG
-    LOG_VOL("ext3_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point);
+#if EXT_DEBUG
+    LOG_VOL("ext_mount(%s, %s, %d):\n", dev->dev_fspath, vol->mount_point, safe_mode);
 #endif
-    return -ENOSYS;
+
+    char *fs[] = { "ext3", "ext2", NULL };
+    char *devpath;
+
+    devpath = blkdev_get_devpath(dev);
+
+    int flags, rc = 0;
+
+    flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
+
+    if (safe_mode)
+        flags |= MS_SYNCHRONOUS;
+
+    if (vol->state == volstate_mounted) {
+        LOG_VOL("Remounting %s on %s, safe mode %d\n", devpath,
+                vol->mount_point, safe_mode);
+        flags |= MS_REMOUNT;
+    }
+ 
+    char **f;
+    for (f = fs; *f != NULL; f++) {
+        rc = mount(devpath, vol->mount_point, *f, flags, NULL);
+        if (rc && errno == EROFS) {
+            LOGE("ext_mount(%s, %s): Read only filesystem - retrying mount RO\n",
+                 devpath, vol->mount_point);
+            flags |= MS_RDONLY;
+            rc = mount(devpath, vol->mount_point, *f, flags, NULL);
+        }
+#if EXT_DEBUG
+        LOG_VOL("ext_mount(%s, %s): %s mount rc = %d\n", devpath, *f,
+                vol->mount_point, rc);
+#endif
+        if (!rc)
+            break;
+    }
+    free(devpath);
+
+    // Chmod the mount point so that its a free-for-all.
+    // (required for consistency with VFAT.. sigh)
+    if (chmod(vol->mount_point, 0777) < 0) {
+        LOGE("Failed to chmod %s (%s)\n", vol->mount_point, strerror(errno));
+        return -errno;
+    }
+    
+    return rc;
 }
diff --git a/vold/volmgr_ext3.h b/vold/volmgr_ext3.h
index a8bac19..bfe882a 100644
--- a/vold/volmgr_ext3.h
+++ b/vold/volmgr_ext3.h
@@ -21,9 +21,7 @@
 #include "volmgr.h"
 #include "blkdev.h"
 
-
-
-int ext3_identify(blkdev_t *blkdev);
-int ext3_check(blkdev_t *blkdev);
-int ext3_mount(blkdev_t *blkdev, volume_t *vol);
+int ext_identify(blkdev_t *blkdev);
+int ext_check(blkdev_t *blkdev);
+int ext_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode);
 #endif
diff --git a/vold/volmgr_vfat.c b/vold/volmgr_vfat.c
index 661f714..7a1cf81 100644
--- a/vold/volmgr_vfat.c
+++ b/vold/volmgr_vfat.c
@@ -31,7 +31,7 @@
 int vfat_identify(blkdev_t *dev)
 {
 #if VFAT_DEBUG
-    LOG_VOL("vfat_identify(%s):\n", dev->dev_fspath);
+    LOG_VOL("vfat_identify(%d:%d):\n", dev->major, dev->minor);
 #endif
     return 0; // XXX: Implement
 }
@@ -41,12 +41,12 @@
     int rc;
 
 #if VFAT_DEBUG
-    LOG_VOL("vfat_check(%s):\n", dev->dev_fspath);
+    LOG_VOL("vfat_check(%d:%d):\n", dev->major, dev->minor);
 #endif
 
     if (access(FSCK_MSDOS_PATH, X_OK)) {
-        LOGE("vfat_check(%s): %s not found (skipping checks)\n",
-             FSCK_MSDOS_PATH, dev->dev_fspath);
+        LOGE("vfat_check(%d:%d): %s not found (skipping checks)\n",
+             dev->major, dev->minor, FSCK_MSDOS_PATH);
         return 0;
     }
 
@@ -57,18 +57,20 @@
     args[2] = "-V";
     args[3] = "-w";
     args[4] = "-p";
-    args[5] = dev->dev_fspath;
+    args[5] = blkdev_get_devpath(dev);
     args[6] = NULL;
     rc = logwrap(6, args);
+    free(args[5]);
 #else
     char *args[6];
     args[0] = FSCK_MSDOS_PATH;
     args[1] = "-v";
     args[2] = "-w";
     args[3] = "-p";
-    args[4] = dev->dev_fspath;
+    args[4] = blkdev_get_devpath(dev);
     args[5] = NULL;
     rc = logwrap(5, args);
+    free(args[4]);
 #endif
 
     if (rc == 0) {
@@ -82,6 +84,9 @@
         return -EIO;
     } else if (rc == 4) {
         LOG_VOL("Filesystem check completed (errors fixed)\n");
+    } else if (rc == 8) {
+        LOG_VOL("Filesystem check failed (not a FAT filesystem)\n");
+        return -ENODATA;
     } else {
         LOG_VOL("Filesystem check failed (unknown exit code %d)\n", rc);
         return -EIO;
@@ -89,29 +94,42 @@
     return 0;
 }
 
-int vfat_mount(blkdev_t *dev, volume_t *vol)
+int vfat_mount(blkdev_t *dev, volume_t *vol, boolean safe_mode)
 {
     int flags, rc;
+    char *devpath;
+
+    devpath = blkdev_get_devpath(dev);
 
 #if VFAT_DEBUG
-    LOG_VOL("vfat_mount(%s, %s):\n", dev->dev_fspath, vol->mount_point);
+    LOG_VOL("vfat_mount(%d:%d, %s, %d):\n", dev->major, dev->minor, vol->mount_point, safe_mode);
 #endif
 
     flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
-    rc = mount(dev->dev_fspath, vol->mount_point, "vfat", flags,
+
+    if (safe_mode)
+        flags |= MS_SYNCHRONOUS;
+    if (vol->state == volstate_mounted) {
+        LOG_VOL("Remounting %d:%d on %s, safe mode %d\n", dev->major,
+                dev->minor, vol->mount_point, safe_mode);
+        flags |= MS_REMOUNT;
+    }
+
+    rc = mount(devpath, vol->mount_point, "vfat", flags,
                "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
 
     if (rc && errno == EROFS) {
-        LOGE("vfat_mount(%s, %s): Read only filesystem - retrying mount RO\n",
-             dev->dev_fspath, vol->mount_point);
+        LOGE("vfat_mount(%d:%d, %s): Read only filesystem - retrying mount RO\n",
+             dev->major, dev->minor, vol->mount_point);
         flags |= MS_RDONLY;
-        rc = mount(dev->dev_fspath, vol->mount_point, "vfat", flags,
+        rc = mount(devpath, vol->mount_point, "vfat", flags,
                    "utf8,uid=1000,gid=1000,fmask=711,dmask=700");
     }
 
 #if VFAT_DEBUG
-    LOG_VOL("vfat_mount(%s, %s): mount rc = %d\n", dev->dev_fspath,
+    LOG_VOL("vfat_mount(%s, %d:%d): mount rc = %d\n", dev->major,k dev->minor,
             vol->mount_point, rc);
 #endif
+    free (devpath);
     return rc;
 }
diff --git a/vold/volmgr_vfat.h b/vold/volmgr_vfat.h
index 2bd9fed..d9cf04d 100644
--- a/vold/volmgr_vfat.h
+++ b/vold/volmgr_vfat.h
@@ -25,5 +25,5 @@
 
 int vfat_identify(blkdev_t *blkdev);
 int vfat_check(blkdev_t *blkdev);
-int vfat_mount(blkdev_t *blkdev, volume_t *vol);
+int vfat_mount(blkdev_t *blkdev, volume_t *vol, boolean safe_mode);
 #endif