Add a new "virtual disk" feature.
It's extremely difficult to test storage related logic on devices
that don't have physical SD card slots. So to support better
debugging and testing, add a new "virtual disk" feature which mounts
a 512MB file through loop device.
It relies on the kernel having the "loop.max_part" value set to
something other than 0 via the boot command line, since that allows
all the existing partition logic to fall into place.
Bug: 34903607
Test: builds, boots, virtual disk works
Change-Id: I04c5b33e37319d867542985a56b7999a9b7cf35d
diff --git a/Loop.cpp b/Loop.cpp
index 1127817..7e243de 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -32,12 +32,19 @@
#include <cutils/log.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+
#include <sysutils/SocketClient.h>
#include "Loop.h"
#include "Asec.h"
#include "VoldUtil.h"
#include "sehandle.h"
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
int Loop::dumpState(SocketClient *c) {
int i;
int fd;
@@ -229,6 +236,40 @@
return 0;
}
+int Loop::create(const std::string& target, std::string& out_device) {
+ unique_fd ctl_fd(open("/dev/loop-control", O_RDWR));
+ if (ctl_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open loop-control";
+ return -errno;
+ }
+
+ int num = ioctl(ctl_fd.get(), LOOP_CTL_GET_FREE);
+ if (num == -1) {
+ PLOG(ERROR) << "Failed LOOP_CTL_GET_FREE";
+ return -errno;
+ }
+
+ out_device = StringPrintf("/dev/block/loop%d", num);
+
+ unique_fd target_fd(open(target.c_str(), O_RDWR));
+ if (target_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open " << target;
+ return -errno;
+ }
+ unique_fd device_fd(open(out_device.c_str(), O_RDWR));
+ if (device_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open " << out_device;
+ return -errno;
+ }
+
+ if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get()) == -1) {
+ PLOG(ERROR) << "Failed to LOOP_SET_FD";
+ return -errno;
+ }
+
+ return 0;
+}
+
int Loop::destroyByDevice(const char *loopDevice) {
int device_fd;
@@ -254,20 +295,37 @@
}
int Loop::createImageFile(const char *file, unsigned long numSectors) {
- int fd;
+ int res = 0;
- if ((fd = creat(file, 0600)) < 0) {
- SLOGE("Error creating imagefile (%s)", strerror(errno));
- return -1;
+ char* secontext = nullptr;
+ if (sehandle) {
+ if (!selabel_lookup(sehandle, &secontext, file, S_IFREG)) {
+ setfscreatecon(secontext);
+ }
}
- if (ftruncate(fd, numSectors * 512) < 0) {
- SLOGE("Error truncating imagefile (%s)", strerror(errno));
- close(fd);
- return -1;
+ unique_fd fd(creat(file, 0600));
+ if (fd.get() == -1) {
+ PLOG(ERROR) << "Failed to create image " << file;
+ res = -errno;
+ goto done;
}
- close(fd);
- return 0;
+
+ if (fallocate(fd.get(), 0, 0, numSectors * 512) == -1) {
+ PLOG(WARNING) << "Failed to fallocate; falling back to ftruncate";
+ if (ftruncate(fd, numSectors * 512) == -1) {
+ PLOG(ERROR) << "Failed to ftruncate";
+ res = -errno;
+ }
+ }
+
+done:
+ if (secontext) {
+ setfscreatecon(nullptr);
+ freecon(secontext);
+ }
+
+ return res;
}
int Loop::resizeImageFile(const char *file, unsigned long numSectors) {