From 852111eea4eaf3c56e4ca9296a42b5b2a10df712 Mon Sep 17 00:00:00 2001 From: Juhyung Park Date: Tue, 15 Feb 2022 18:05:06 +0900 Subject: [PATCH 1/3] init.rc: use /sys/class/block instead of /sys/devices/virtual/block /sys/class/block covers all of dm-[0-9], sd[a-z], mmcblk[0-9]. Use it instead of /sys/devices/virtual/block, which only covers dm devices. This allows f2fs tunings to be applied more reliably regardless of how the userdata partition is set up. Do note that while everything under /sys/devices/virtual/block are expected to have correct SELinux labels by AOSP, some under /sys/class/block are not as it's symlinked to platform-specific paths, and it is up to the vendors to label them correctly. Test: Confirm entries under /dev/sys aren't dangling and cp_interval, gc_urgent_sleep_time, iostat_enable and discard_max_bytes are all set up properly under FBE, FDE and unencrypted. Change-Id: I089af5bc068445f33919df6659671e50456d49f9 Signed-off-by: Juhyung Park --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index c4c9eca1d..224f605ac 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1087,7 +1087,7 @@ on boot # to access dm- sysfs mkdir /dev/sys/block/by-name 0755 system system - symlink /sys/devices/virtual/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata + symlink /sys/class/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs, # to avoid power consumption when system becomes mostly idle. Be careful From 491004bbfb67e58040febda9a396455a9a5c90a4 Mon Sep 17 00:00:00 2001 From: Juhyung Park Date: Tue, 15 Feb 2022 19:18:46 +0900 Subject: [PATCH 2/3] init: mount_handler: detect main block device more reliably Current code is not portable beyond SCSI devices (e.g., UFS). For example, eMMC and NVMe devices fail due to their extra postfix. Change its logic to rewind each character until "queue" directory appears. Test: Confirm md0p1, sda20, nvme0n1p3, mmcblk0p3 are all handled well. Change-Id: I585ccf2d4a72f6ef8ecb203acdd72a1e32d3e749 Signed-off-by: Juhyung Park --- init/mount_handler.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp index f0d8d4569..15ac30590 100644 --- a/init/mount_handler.cpp +++ b/init/mount_handler.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +41,9 @@ #include "epoll.h" +using android::base::Basename; +using android::base::StringPrintf; + namespace android { namespace init { @@ -67,21 +72,30 @@ MountHandlerEntry ParseMount(const std::string& line) { return MountHandlerEntry(fields[0], fields[1], fields[2]); } +// return dm-4 or dm-8 for dm-4, sda for sda25, or mmcblk0 for mmcblk0p24 +std::string GetRootDisk(std::string blockdev) { + if (blockdev.find('/') != std::string::npos) return {}; + + std::error_code ec; + for (const auto& entry : std::filesystem::directory_iterator("/sys/block", ec)) { + const std::string path = entry.path().string(); + if (std::filesystem::exists(StringPrintf("%s/%s", path.c_str(), blockdev.c_str()))) { + return Basename(path); + } + } + if (android::base::StartsWith(blockdev, "dm-")) return blockdev; + return {}; +} + void SetMountProperty(const MountHandlerEntry& entry, bool add) { static constexpr char devblock[] = "/dev/block/"; if (!android::base::StartsWith(entry.blk_device, devblock)) return; + auto target = entry.blk_device.substr(strlen(devblock)); std::string value; if (add) { - value = entry.blk_device.substr(strlen(devblock)); - if (android::base::StartsWith(value, "sd")) { - // All sd partitions inherit their queue characteristics - // from the whole device reference. Strip partition number. - auto it = std::find_if(value.begin(), value.end(), [](char c) { return isdigit(c); }); - if (it != value.end()) value.erase(it, value.end()); - } - auto queue = "/sys/block/" + value + "/queue"; + value = GetRootDisk(target); + struct stat sb; - if (stat(queue.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = ""; if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = ""; // Clear the noise associated with loopback and APEX. if (android::base::StartsWith(value, "loop")) value = ""; @@ -98,7 +112,7 @@ void SetMountProperty(const MountHandlerEntry& entry, bool add) { if (value.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return; android::base::SetProperty(blk_mount_prop, value); if (!value.empty()) { - android::base::SetProperty(dev_mount_prop, entry.blk_device.substr(strlen(devblock))); + android::base::SetProperty(dev_mount_prop, target); } else { android::base::SetProperty(dev_mount_prop, ""); } From 120f6b260c268c677735fcef434f9480223725ed Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 4 Mar 2022 15:06:02 -0800 Subject: [PATCH 3/3] Init: add dev.mnt.blk.bootdevice to access device sysfs This patch adds a new property, 'dev.mnt.root.', which provides, for example of /data, 1. dm-N dev.mnt.dev.data = dm-N dev.mnt.blk.data = sdaN or mmcblk0pN dev.mnt.rootdisk.data = sda or mmcblk0 2. sdaN or mmcblk0pN dev.mnt.dev.data = sdaN or mmcblk0pN dev.mnt.blk.data = sdaN or mmcblk0pN dev.mnt.rootdisk.data = sda or mmcblk0 Signed-off-by: Jaegeuk Kim Change-Id: I0a58a62d416f966f26b5de04112c2f9a7eceb22c --- init/README.md | 15 +++++++---- init/mount_handler.cpp | 58 ++++++++++++++++++++++++++++++++---------- rootdir/init.rc | 7 +++-- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/init/README.md b/init/README.md index c82dbfbfc..13c6ebdfa 100644 --- a/init/README.md +++ b/init/README.md @@ -804,13 +804,18 @@ Init provides state information with the following properties. `init.svc.` > State of a named service ("stopped", "stopping", "running", "restarting") -`dev.mnt.blk.` +`dev.mnt.dev.`, `dev.mnt.blk.`, `dev.mnt.rootdisk.` > Block device base name associated with a *mount_point*. The *mount_point* has / replaced by . and if referencing the root mount point - "/", it will use "/root", specifically `dev.mnt.blk.root`. - Meant for references to `/sys/device/block/${dev.mnt.blk.}/` and - `/sys/fs/ext4/${dev.mnt.blk.}/` to tune the block device - characteristics in a device agnostic manner. + "/", it will use "/root". + `dev.mnt.dev.` indicates a block device attached to filesystems. + (e.g., dm-N or sdaN/mmcblk0pN to access `/sys/fs/ext4/${dev.mnt.dev.}/`) + + `dev.mnt.blk.` indicates the disk partition to the above block device. + (e.g., sdaN / mmcblk0pN to access `/sys/class/block/${dev.mnt.blk.}/`) + + `dev.mnt.rootdisk.` indicates the root disk to contain the above disk partition. + (e.g., sda / mmcblk0 to access `/sys/class/block/${dev.mnt.rootdisk.}/queue`) Init responds to properties that begin with `ctl.`. These properties take the format of `ctl.[_]` and the _value_ of the system property is used as a parameter. The diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp index 15ac30590..227ce2fe4 100644 --- a/init/mount_handler.cpp +++ b/init/mount_handler.cpp @@ -72,8 +72,25 @@ MountHandlerEntry ParseMount(const std::string& line) { return MountHandlerEntry(fields[0], fields[1], fields[2]); } -// return dm-4 or dm-8 for dm-4, sda for sda25, or mmcblk0 for mmcblk0p24 +// return sda25 for dm-4, sda25 for sda25, or mmcblk0p24 for mmcblk0p24 +std::string GetDiskPart(std::string blockdev) { + if (blockdev.find('/') != std::string::npos) return {}; + + while (android::base::StartsWith(blockdev, "dm-")) { + auto& dm = dm::DeviceMapper::Instance(); + std::optional parent = dm.GetParentBlockDeviceByPath("/dev/block/" + blockdev); + if (parent) { + blockdev = android::base::Basename(*parent); + } else { + return {}; + } + } + return blockdev; +} + +// return sda for sda25, or mmcblk0 for mmcblk0p24 std::string GetRootDisk(std::string blockdev) { + if (blockdev.empty()) return {}; if (blockdev.find('/') != std::string::npos) return {}; std::error_code ec; @@ -83,7 +100,6 @@ std::string GetRootDisk(std::string blockdev) { return Basename(path); } } - if (android::base::StartsWith(blockdev, "dm-")) return blockdev; return {}; } @@ -91,31 +107,47 @@ void SetMountProperty(const MountHandlerEntry& entry, bool add) { static constexpr char devblock[] = "/dev/block/"; if (!android::base::StartsWith(entry.blk_device, devblock)) return; auto target = entry.blk_device.substr(strlen(devblock)); - std::string value; + std::string diskpart, rootdisk; if (add) { - value = GetRootDisk(target); + diskpart = GetDiskPart(target); + rootdisk = GetRootDisk(diskpart); struct stat sb; - if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = ""; + if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) rootdisk = ""; // Clear the noise associated with loopback and APEX. - if (android::base::StartsWith(value, "loop")) value = ""; - if (android::base::StartsWith(entry.mount_point, "/apex/")) value = ""; + if (android::base::StartsWith(target, "loop")) rootdisk = ""; + if (android::base::StartsWith(entry.mount_point, "/apex/")) rootdisk = ""; } auto mount_prop = entry.mount_point; if (mount_prop == "/") mount_prop = "/root"; std::replace(mount_prop.begin(), mount_prop.end(), '/', '.'); auto blk_mount_prop = "dev.mnt.blk" + mount_prop; auto dev_mount_prop = "dev.mnt.dev" + mount_prop; - // Set property even if its value does not change to trigger 'on property:' + auto rootdisk_mount_prop = "dev.mnt.rootdisk" + mount_prop; + // Set property even if its rootdisk does not change to trigger 'on property:' // handling, except for clearing non-existent or already clear property. // Goal is reduction of empty properties and associated triggers. - if (value.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return; - android::base::SetProperty(blk_mount_prop, value); - if (!value.empty()) { - android::base::SetProperty(dev_mount_prop, target); - } else { + if (rootdisk.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return; + + if (rootdisk.empty()) { + android::base::SetProperty(blk_mount_prop, ""); android::base::SetProperty(dev_mount_prop, ""); + android::base::SetProperty(rootdisk_mount_prop, ""); + return; } + + // 1. dm-N + // dev.mnt.dev.data = dm-N + // dev.mnt.blk.data = sdaN or mmcblk0pN + // dev.mnt.rootdisk.data = sda or mmcblk0 + // + // 2. sdaN or mmcblk0pN + // dev.mnt.dev.data = sdaN or mmcblk0pN + // dev.mnt.blk.data = sdaN or mmcblk0pN + // dev.mnt.rootdisk.data = sda or mmcblk0 + android::base::SetProperty(dev_mount_prop, target); + android::base::SetProperty(blk_mount_prop, diskpart); + android::base::SetProperty(rootdisk_mount_prop, rootdisk); } } // namespace diff --git a/rootdir/init.rc b/rootdir/init.rc index 224f605ac..404d7aecc 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1085,9 +1085,11 @@ on boot mkdir /dev/sys/fs/by-name 0755 system system symlink /sys/fs/f2fs/${dev.mnt.dev.data} /dev/sys/fs/by-name/userdata - # to access dm- sysfs + # dev.mnt.dev.data=dm-N, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0, or + # dev.mnt.dev.data=sdaN/mmcblk0pN, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0 mkdir /dev/sys/block/by-name 0755 system system symlink /sys/class/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata + symlink /sys/class/block/${dev.mnt.rootdisk.data} /dev/sys/block/by-name/rootdisk # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs, # to avoid power consumption when system becomes mostly idle. Be careful @@ -1099,8 +1101,9 @@ on boot # limit discard size to 128MB in order to avoid long IO latency # for filesystem tuning first (dm or sda) - # Note that, if dm- is used, sda/mmcblk0 should be tuned in vendor/init.rc + # this requires enabling selinux entry for sda/mmcblk0 in vendor side write /dev/sys/block/by-name/userdata/queue/discard_max_bytes 134217728 + write /dev/sys/block/by-name/rootdisk/queue/discard_max_bytes 134217728 # Permissions for System Server and daemons. chown system system /sys/power/autosleep