Merge "zram: support zram_writeback" am: 2fdbdfddac
am: 2c90557d27
Change-Id: I67b48ca58248c564c71ba233dfd3289732de1c42
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 19445c8..70a1045 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -79,6 +79,7 @@
#define ZRAM_CONF_DEV "/sys/block/zram0/disksize"
#define ZRAM_CONF_MCS "/sys/block/zram0/max_comp_streams"
+#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -1373,6 +1374,70 @@
return 0;
}
+static bool InstallZramDevice(const std::string& device) {
+ if (!android::base::WriteStringToFile(device, ZRAM_BACK_DEV)) {
+ PERROR << "Cannot write " << device << " in: " << ZRAM_BACK_DEV;
+ return false;
+ }
+ LINFO << "Success to set " << device << " to " << ZRAM_BACK_DEV;
+ return true;
+}
+
+static bool PrepareZramDevice(const std::string& loop, off64_t size, const std::string& bdev) {
+ if (loop.empty() && bdev.empty()) return true;
+
+ if (bdev.length()) {
+ return InstallZramDevice(bdev);
+ }
+
+ // Get free loopback
+ unique_fd loop_fd(TEMP_FAILURE_RETRY(open("/dev/loop-control", O_RDWR | O_CLOEXEC)));
+ if (loop_fd.get() == -1) {
+ PERROR << "Cannot open loop-control";
+ return false;
+ }
+
+ int num = ioctl(loop_fd.get(), LOOP_CTL_GET_FREE);
+ if (num == -1) {
+ PERROR << "Cannot get free loop slot";
+ return false;
+ }
+
+ // Prepare target path
+ unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0664)));
+ if (target_fd.get() == -1) {
+ PERROR << "Cannot open target path: " << loop;
+ return false;
+ }
+ if (fallocate(target_fd.get(), 0, 0, size) < 0) {
+ PERROR << "Cannot truncate target path: " << loop;
+ return false;
+ }
+
+ // Connect loopback (device_fd) to target path (target_fd)
+ std::string device = android::base::StringPrintf("/dev/block/loop%d", num);
+ unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
+ if (device_fd.get() == -1) {
+ PERROR << "Cannot open /dev/block/loop" << num;
+ return false;
+ }
+
+ if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get())) {
+ PERROR << "Cannot set loopback to target path";
+ return false;
+ }
+
+ // set block size & direct IO
+ if (ioctl(device_fd.get(), LOOP_SET_BLOCK_SIZE, 4096)) {
+ PWARNING << "Cannot set 4KB blocksize to /dev/block/loop" << num;
+ }
+ if (ioctl(device_fd.get(), LOOP_SET_DIRECT_IO, 1)) {
+ PWARNING << "Cannot set direct_io to /dev/block/loop" << num;
+ }
+
+ return InstallZramDevice(device);
+}
+
bool fs_mgr_swapon_all(const Fstab& fstab) {
bool ret = true;
for (const auto& entry : fstab) {
@@ -1381,6 +1446,10 @@
continue;
}
+ if (!PrepareZramDevice(entry.zram_loopback_path, entry.zram_loopback_size, entry.zram_backing_dev_path)) {
+ LERROR << "Skipping losetup for '" << entry.blk_device << "'";
+ }
+
if (entry.zram_size > 0) {
// A zram_size was specified, so we need to configure the
// device. There is no point in having multiple zram devices
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 2576035..c9f34a7 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -28,6 +28,7 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <libgsi/libgsi.h>
@@ -44,6 +45,9 @@
std::string key_dir;
std::string verity_loc;
std::string sysfs_path;
+ std::string zram_loopback_path;
+ uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default
+ std::string zram_backing_dev_path;
off64_t part_length = 0;
std::string label;
int partnum = -1;
@@ -118,6 +122,9 @@
{"checkpoint=block", MF_CHECKPOINT_BLK},
{"checkpoint=fs", MF_CHECKPOINT_FS},
{"slotselect_other", MF_SLOTSELECT_OTHER},
+ {"zram_loopback_path=", MF_ZRAM_LOOPBACK_PATH},
+ {"zram_loopback_size=", MF_ZRAM_LOOPBACK_SIZE},
+ {"zram_backing_dev_path=", MF_ZRAM_BACKING_DEV_PATH},
{0, 0},
};
@@ -345,6 +352,16 @@
} else if (flag == MF_SYSFS) {
/* The path to trigger device gc by idle-maint of vold. */
flag_vals->sysfs_path = arg;
+ } else if (flag == MF_ZRAM_LOOPBACK_PATH) {
+ /* The path to use loopback for zram. */
+ flag_vals->zram_loopback_path = arg;
+ } else if (flag == MF_ZRAM_LOOPBACK_SIZE) {
+ if (!android::base::ParseByteCount(arg, &flag_vals->zram_loopback_size)) {
+ LERROR << "Warning: zram_loopback_size = flag malformed";
+ }
+ } else if (flag == MF_ZRAM_BACKING_DEV_PATH) {
+ /* The path to use loopback for zram. */
+ flag_vals->zram_backing_dev_path = arg;
}
break;
}
@@ -570,6 +587,9 @@
entry.logical_blk_size = flag_vals.logical_blk_size;
entry.sysfs_path = std::move(flag_vals.sysfs_path);
entry.vbmeta_partition = std::move(flag_vals.vbmeta_partition);
+ entry.zram_loopback_path = std::move(flag_vals.zram_loopback_path);
+ entry.zram_loopback_size = std::move(flag_vals.zram_loopback_size);
+ entry.zram_backing_dev_path = std::move(flag_vals.zram_backing_dev_path);
if (entry.fs_mgr_flags.logical) {
entry.logical_partition_name = entry.blk_device;
}
@@ -811,6 +831,8 @@
free(fstab->recs[i].key_dir);
free(fstab->recs[i].label);
free(fstab->recs[i].sysfs_path);
+ free(fstab->recs[i].zram_loopback_path);
+ free(fstab->recs[i].zram_backing_dev_path);
}
/* Free the fstab_recs array created by calloc(3) */
@@ -908,6 +930,9 @@
entry.erase_blk_size = fstab_rec->erase_blk_size;
entry.logical_blk_size = fstab_rec->logical_blk_size;
entry.sysfs_path = fstab_rec->sysfs_path;
+ entry.zram_loopback_path = fstab_rec->zram_loopback_path;
+ entry.zram_loopback_size = fstab_rec->zram_loopback_size;
+ entry.zram_backing_dev_path = fstab_rec->zram_backing_dev_path;
return entry;
}
@@ -951,6 +976,9 @@
legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
+ legacy_fstab->recs[i].zram_loopback_path = strdup(fstab[i].zram_loopback_path.c_str());
+ legacy_fstab->recs[i].zram_loopback_size = fstab[i].zram_loopback_size;
+ legacy_fstab->recs[i].zram_backing_dev_path = strdup(fstab[i].zram_backing_dev_path.c_str());
}
return legacy_fstab;
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7842ca2..39ceff7 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -122,6 +122,12 @@
0x80000000
#define MF_SLOTSELECT_OTHER \
0x100000000
+#define MF_ZRAM_LOOPBACK_PATH \
+ 0x200000000
+#define MF_ZRAM_LOOPBACK_SIZE \
+ 0x400000000
+#define MF_ZRAM_BACKING_DEV_PATH \
+ 0x800000000
// clang-format on
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 6643c0d..5d8496d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -59,6 +59,9 @@
off64_t erase_blk_size;
off64_t logical_blk_size;
char* sysfs_path;
+ char* zram_loopback_path;
+ uint64_t zram_loopback_size;
+ char* zram_backing_dev_path;
};
struct fstab* fs_mgr_read_fstab_default();
@@ -119,6 +122,9 @@
off64_t logical_blk_size = 0;
std::string sysfs_path;
std::string vbmeta_partition;
+ std::string zram_loopback_path;
+ uint64_t zram_loopback_size;
+ std::string zram_backing_dev_path;
// TODO: Remove this union once fstab_rec is deprecated. It only serves as a
// convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 008a868..c11ea10 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,9 +20,11 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <mntent.h>
+#include <linux/loop.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
+#include <sys/swap.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -58,6 +60,7 @@
using android::base::Split;
using android::base::StringPrintf;
using android::base::Timer;
+using android::base::unique_fd;
namespace android {
namespace init {
@@ -285,6 +288,48 @@
return stat;
}
+// zram is able to use backing device on top of a loopback device.
+// In order to unmount /data successfully, we have to kill the loopback device first
+#define ZRAM_DEVICE "/dev/block/zram0"
+#define ZRAM_RESET "/sys/block/zram0/reset"
+#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
+static void KillZramBackingDevice() {
+ std::string backing_dev;
+ if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
+
+ if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
+
+ // cut the last "\n"
+ backing_dev.erase(backing_dev.length() - 1);
+
+ // shutdown zram handle
+ Timer swap_timer;
+ LOG(INFO) << "swapoff() start...";
+ if (swapoff(ZRAM_DEVICE) == -1) {
+ LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
+ return;
+ }
+ LOG(INFO) << "swapoff() took " << swap_timer;;
+
+ if (!android::base::WriteStringToFile("1", ZRAM_RESET)) {
+ LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
+ return;
+ }
+
+ // clear loopback device
+ unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
+ if (loop.get() < 0) {
+ LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
+ return;
+ }
+
+ if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
+ LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
+ return;
+ }
+ LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
+}
+
//* Reboot / shutdown the system.
// cmd ANDROID_RB_* as defined in android_reboot.h
// reason Reason string like "reboot", "shutdown,userrequested"
@@ -427,6 +472,9 @@
sync();
LOG(INFO) << "sync() before umount took" << sync_timer;
}
+ // 5. drop caches and disable zram backing device, if exist
+ KillZramBackingDevice();
+
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
// Follow what linux shutdown is doing: one more sync with little bit delay
{