Fix Vold to properly handle full-disk file systems
(full-disk: no partitions)
In Android, Vold recognizes a USB drive having a full-disk file system
and mounts it properly, but when the drive is removed from system Vold
won't unmount the device. This is because Vold only unmounts partitions.
For a FAT32 USB drive (with partitions), kernel will create two devices:
sda (disk device) and sda1 (partition device). When the drive is removed,
Vold will receive two netlink events: one for partition remove (sda1)
and one for disk remove (sda). The unmount occurs only when partition
remove event is received.
For a full-disk FS USB drive, kernel will only create one device: sda
(disk device). When the drive is removed, Vold will only receive one
netlink event for disk remove (sda) and it won't unmount the device.
This patch will verify if there is a currently mounted device when disk
remove event is received and will perform unmount, to properly unmount
the device.
Change-Id: I4866ab2482fddfb40a8fc73083f31df846bbb24f
Signed-off-by: Robert Chiras <robert.chiras@intel.com>
diff --git a/DirectVolume.cpp b/DirectVolume.cpp
index 67f89ea..df06c83 100644
--- a/DirectVolume.cpp
+++ b/DirectVolume.cpp
@@ -289,11 +289,17 @@
char msg[255];
bool enabled;
- if (mVm->shareEnabled(getLabel(), "ums", &enabled) == 0 && enabled) {
+ SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
+ if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
+ /*
+ * Yikes, our mounted disk is going away!
+ */
+
+ doUnmount(major, minor);
+ } else if (mVm->shareEnabled(getLabel(), "ums", &enabled) == 0 && enabled) {
mVm->unshareVolume(getLabel(), "ums");
}
- SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)",
getLabel(), getFuseMountpoint(), major, minor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved,
@@ -320,29 +326,12 @@
if (state != Volume::State_Mounted && state != Volume::State_Shared) {
return;
}
-
+
if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
/*
* Yikes, our mounted partition is going away!
*/
-
- bool providesAsec = (getFlags() & VOL_PROVIDES_ASEC) != 0;
- if (providesAsec && mVm->cleanupAsec(this, true)) {
- SLOGE("Failed to cleanup ASEC - unmount will probably fail!");
- }
-
- snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
- getLabel(), getFuseMountpoint(), major, minor);
- mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
- msg, false);
-
- if (Volume::unmountVol(true, false)) {
- SLOGE("Failed to unmount volume on bad removal (%s)",
- strerror(errno));
- // XXX: At this point we're screwed for now
- } else {
- SLOGD("Crisis averted");
- }
+ doUnmount(major, minor);
} else if (state == Volume::State_Shared) {
/* removed during mass storage */
snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)",
@@ -359,6 +348,27 @@
}
}
+void DirectVolume::doUnmount(int major, int minor) {
+ char msg[255];
+ bool providesAsec = (getFlags() & VOL_PROVIDES_ASEC) != 0;
+ if (providesAsec && mVm->cleanupAsec(this, true)) {
+ SLOGE("Failed to cleanup ASEC - unmount will probably fail!");
+ }
+
+ snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
+ getLabel(), getFuseMountpoint(), major, minor);
+ mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
+ msg, false);
+
+ if (Volume::unmountVol(true, false)) {
+ SLOGE("Failed to unmount volume on bad removal (%s)",
+ strerror(errno));
+ // XXX: At this point we're screwed for now
+ } else {
+ SLOGD("Crisis averted");
+ }
+}
+
/*
* Called from base to get a list of devicenodes for mounting
*/