OSDN Git Service

Progress towards FBE and adoptable storage.
[android-x86/system-vold.git] / VolumeManager.cpp
index e51d204..4ba0c36 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/sysmacros.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -88,7 +89,13 @@ const char *VolumeManager::ASECDIR           = "/mnt/asec";
  */
 const char *VolumeManager::LOOPDIR           = "/mnt/obb";
 
-static const char* kUserMountPath = "/mnt/user";
+static const char* kPathUserMount = "/mnt/user";
+static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
+
+static const char* kPropVirtualDisk = "persist.sys.virtual_disk";
+
+/* 512MiB is large enough for testing purposes */
+static const unsigned int kSizeVirtualDisk = 536870912;
 
 static const unsigned int kMajorBlockMmc = 179;
 static const unsigned int kMajorBlockExperimentalMin = 240;
@@ -174,7 +181,7 @@ static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice
         }
         *createdDMDevice = true;
     } else {
-        strcpy(buffer, loopDevice);
+        strlcpy(buffer, loopDevice, len);
         *createdDMDevice = false;
     }
     return 0;
@@ -249,6 +256,55 @@ char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
     return buffer;
 }
 
+int VolumeManager::updateVirtualDisk() {
+    if (property_get_bool(kPropVirtualDisk, false)) {
+        if (access(kPathVirtualDisk, F_OK) != 0) {
+            Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
+        }
+
+        if (mVirtualDisk == nullptr) {
+            if (Loop::create(kPathVirtualDisk, mVirtualDiskPath) != 0) {
+                LOG(ERROR) << "Failed to create virtual disk";
+                return -1;
+            }
+
+            struct stat buf;
+            if (stat(mVirtualDiskPath.c_str(), &buf) < 0) {
+                PLOG(ERROR) << "Failed to stat " << mVirtualDiskPath;
+                return -1;
+            }
+
+            auto disk = new android::vold::Disk("virtual", buf.st_rdev, "virtual",
+                    android::vold::Disk::Flags::kAdoptable | android::vold::Disk::Flags::kSd);
+            disk->create();
+            mVirtualDisk = std::shared_ptr<android::vold::Disk>(disk);
+            mDisks.push_back(mVirtualDisk);
+        }
+    } else {
+        if (mVirtualDisk != nullptr) {
+            dev_t device = mVirtualDisk->getDevice();
+
+            auto i = mDisks.begin();
+            while (i != mDisks.end()) {
+                if ((*i)->getDevice() == device) {
+                    (*i)->destroy();
+                    i = mDisks.erase(i);
+                } else {
+                    ++i;
+                }
+            }
+
+            Loop::destroyByDevice(mVirtualDiskPath.c_str());
+            mVirtualDisk = nullptr;
+        }
+
+        if (access(kPathVirtualDisk, F_OK) == 0) {
+            unlink(kPathVirtualDisk);
+        }
+    }
+    return 0;
+}
+
 int VolumeManager::setDebug(bool enable) {
     mDebug = enable;
     return 0;
@@ -266,6 +322,9 @@ int VolumeManager::start() {
             new android::vold::EmulatedVolume("/data/media"));
     mInternalEmulated->create();
 
+    // Consider creating a virtual disk
+    updateVirtualDisk();
+
     return 0;
 }
 
@@ -350,6 +409,7 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
 }
 
 void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
+    std::lock_guard<std::mutex> lock(mLock);
     mDiskSources.push_back(diskSource);
 }
 
@@ -454,7 +514,7 @@ int VolumeManager::onUserStarted(userid_t userId) {
     // Note that sometimes the system will spin up processes from Zygote
     // before actually starting the user, so we're okay if Zygote
     // already created this directory.
-    std::string path(StringPrintf("%s/%d", kUserMountPath, userId));
+    std::string path(StringPrintf("%s/%d", kPathUserMount, userId));
     fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
 
     mStartedUsers.insert(userId);
@@ -558,7 +618,7 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
         }
 
         // We purposefully leave the namespace open across the fork
-        nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
+        nsFd = openat(pidFd, "ns/mnt", O_RDONLY); // not O_CLOEXEC
         if (nsFd < 0) {
             PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
             goto next;
@@ -633,13 +693,19 @@ int VolumeManager::reset() {
         disk->destroy();
         disk->create();
     }
+    updateVirtualDisk();
     mAddedUsers.clear();
     mStartedUsers.clear();
     return 0;
 }
 
+// Can be called twice (sequentially) during shutdown. should be safe for that.
 int VolumeManager::shutdown() {
+    if (mInternalEmulated == nullptr) {
+        return 0; // already shutdown
+    }
     mInternalEmulated->destroy();
+    mInternalEmulated = nullptr;
     for (const auto& disk : mDisks) {
         disk->destroy();
     }
@@ -866,7 +932,7 @@ int VolumeManager::createAsec(const char *id, unsigned long numSectors, const ch
         cleanupDm = true;
     } else {
         sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
-        strcpy(dmDevice, loopDevice);
+        strlcpy(dmDevice, loopDevice, sizeof(dmDevice));
     }
 
     /*
@@ -1830,7 +1896,7 @@ int VolumeManager::listMountedObbs(SocketClient* cli) {
     // Create a string to compare against that has a trailing slash
     int loopDirLen = strlen(VolumeManager::LOOPDIR);
     char loopDir[loopDirLen + 2];
-    strcpy(loopDir, VolumeManager::LOOPDIR);
+    strlcpy(loopDir, VolumeManager::LOOPDIR, sizeof(loopDir));
     loopDir[loopDirLen++] = '/';
     loopDir[loopDirLen] = '\0';