Merge "zram: support zram_writeback"

This commit is contained in:
Jaegeuk Kim 2019-01-17 21:03:15 +00:00 committed by Gerrit Code Review
commit 2fdbdfddac
5 changed files with 157 additions and 0 deletions

View file

@ -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 @@ int fs_mgr_do_tmpfs_mount(const char *n_name)
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 @@ bool fs_mgr_swapon_all(const Fstab& fstab) {
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

View file

@ -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 @@ struct fs_mgr_flag_values {
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 @@ static struct flag_list fs_mgr_flags[] = {
{"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 @@ static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_fla
} 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 @@ static bool fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts, Fstab* fs
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 @@ void fs_mgr_free_fstab(struct fstab *fstab)
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 @@ FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec) {
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 @@ fstab* FstabToLegacyFstab(const Fstab& fstab) {
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;
}

View file

@ -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

View file

@ -59,6 +59,9 @@ struct fstab_rec {
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 @@ struct FstabEntry {
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.

View file

@ -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 @@ static UmountStat TryUmountAndFsck(bool runFsck, std::chrono::milliseconds timeo
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 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
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
{