Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c90557d authored by Jaegeuk Kim's avatar Jaegeuk Kim Committed by android-build-merger
Browse files

Merge "zram: support zram_writeback"

am: 2fdbdfdd

Change-Id: I57bb13eb054fcf441485fa380a9f3091864f550f
parents 48ec9e7c 2fdbdfdd
Loading
Loading
Loading
Loading
+69 −0
Original line number Diff line number Diff line
@@ -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
+28 −0
Original line number Diff line number Diff line
@@ -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;
}
+6 −0
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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.
+48 −0
Original line number Diff line number Diff line
@@ -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
    {