OSDN Git Service

Progress towards FBE and adoptable storage.
[android-x86/system-vold.git] / VolumeManager.cpp
index 2c39240..4ba0c36 100644 (file)
@@ -89,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;
@@ -175,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;
@@ -250,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;
@@ -267,6 +322,9 @@ int VolumeManager::start() {
             new android::vold::EmulatedVolume("/data/media"));
     mInternalEmulated->create();
 
+    // Consider creating a virtual disk
+    updateVirtualDisk();
+
     return 0;
 }
 
@@ -456,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);
@@ -560,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;
@@ -586,11 +644,17 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
                 _exit(0);
             }
             if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
-                    NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+                    NULL, MS_BIND | MS_REC, NULL)) == -1) {
                 PLOG(ERROR) << "Failed to mount " << storageSource << " for "
                         << de->d_name;
                 _exit(1);
             }
+            if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL,
+                    MS_REC | MS_SLAVE, NULL)) == -1) {
+                PLOG(ERROR) << "Failed to set MS_SLAVE to /storage for "
+                        << de->d_name;
+                _exit(1);
+            }
 
             // Mount user-specific symlink helper into place
             userid_t user_id = multiuser_get_user_id(uid);
@@ -629,6 +693,7 @@ int VolumeManager::reset() {
         disk->destroy();
         disk->create();
     }
+    updateVirtualDisk();
     mAddedUsers.clear();
     mStartedUsers.clear();
     return 0;
@@ -867,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));
     }
 
     /*
@@ -1008,24 +1073,6 @@ int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const ch
 
     oldNumSec = info.st_size / 512;
 
-    unsigned long numImgSectors;
-    if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
-        numImgSectors = adjustSectorNumExt4(numSectors);
-    else
-        numImgSectors = adjustSectorNumFAT(numSectors);
-    /*
-     *  add one block for the superblock
-     */
-    SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
-    if (oldNumSec == numImgSectors + 1) {
-        SLOGW("Size unchanged; ignoring resize request");
-        return 0;
-    } else if (oldNumSec > numImgSectors + 1) {
-        SLOGE("Only growing is currently supported.");
-        close(fd);
-        return -1;
-    }
-
     /*
      * Try to read superblock.
      */
@@ -1051,10 +1098,26 @@ int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const ch
         return -1;
     }
 
+    unsigned long numImgSectors;
     if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
         SLOGE("Only ext4 partitions are supported for resize");
         errno = EINVAL;
         return -1;
+    } else {
+        numImgSectors = adjustSectorNumExt4(numSectors);
+    }
+
+    /*
+     *  add one block for the superblock
+     */
+    SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
+    if (oldNumSec == numImgSectors + 1) {
+        SLOGW("Size unchanged; ignoring resize request");
+        return 0;
+    } else if (oldNumSec > numImgSectors + 1) {
+        SLOGE("Only growing is currently supported.");
+        close(fd);
+        return -1;
     }
 
     if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
@@ -1833,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';