fs_mgr: add readahead_size_kb in fstab

This patch adds an option, readahead_size_kb in fstab entry option. It supports
to set a proper readahead_size per block/dm devices before using them by mount,
which is useful for low/high-end devices when addressing memory pressure issue.

Bug: 181567573
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: I549962e68f8488417d76bcfb283958bc33fd5d7a
This commit is contained in:
Jaegeuk Kim 2021-04-02 21:28:51 -07:00
parent ce61fb390a
commit 05ca915431
4 changed files with 109 additions and 0 deletions

View file

@ -647,6 +647,46 @@ bool fs_mgr_is_f2fs(const std::string& blk_device) {
return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
}
static void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb) {
std::string block_device;
if (!Realpath(entry_block_device, &block_device)) {
PERROR << "Failed to realpath " << entry_block_device;
return;
}
static constexpr std::string_view kDevBlockPrefix("/dev/block/");
if (!android::base::StartsWith(block_device, kDevBlockPrefix)) {
LWARNING << block_device << " is not a block device";
return;
}
DeviceMapper& dm = DeviceMapper::Instance();
while (true) {
std::string block_name = block_device;
if (android::base::StartsWith(block_device, kDevBlockPrefix)) {
block_name = block_device.substr(kDevBlockPrefix.length());
}
std::string sys_partition =
android::base::StringPrintf("/sys/class/block/%s/partition", block_name.c_str());
struct stat info;
if (lstat(sys_partition.c_str(), &info) == 0) {
// it has a partition like "sda12".
block_name += "/..";
}
std::string sys_ra = android::base::StringPrintf("/sys/class/block/%s/queue/read_ahead_kb",
block_name.c_str());
std::string size = android::base::StringPrintf("%llu", (long long)size_kb);
android::base::WriteStringToFile(size, sys_ra.c_str());
LINFO << "Set readahead_kb: " << size << " on " << sys_ra;
auto parent = dm.GetParentBlockDeviceByPath(block_device);
if (!parent) {
return;
}
block_device = *parent;
}
}
//
// Prepare the filesystem on the given block device to be mounted.
//
@ -667,6 +707,11 @@ static int prepare_fs_for_mount(const std::string& blk_device, const FstabEntry&
}
mkdir(mount_point.c_str(), 0755);
// Don't need to return error, since it's a salt
if (entry.readahead_size_kb != -1) {
SetReadAheadSize(blk_device, entry.readahead_size_kb);
}
int fs_stat = 0;
if (is_extfs(entry.fs_type)) {

View file

@ -255,6 +255,13 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
} else {
entry->reserved_size = static_cast<off64_t>(size);
}
} else if (StartsWith(flag, "readahead_size_kb=")) {
int val;
if (ParseInt(arg, &val, 0, 16 * 1024)) {
entry->readahead_size_kb = val;
} else {
LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
}
} else if (StartsWith(flag, "eraseblk=")) {
// The erase block size flag is followed by an = and the flash erase block size. Get it,
// check that it is a power of 2 and at least 4096, and return it.

View file

@ -47,6 +47,7 @@ struct FstabEntry {
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
off64_t readahead_size_kb = -1;
std::string encryption_options;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;

View file

@ -1097,3 +1097,59 @@ TEST(fs_mgr, UserdataMountedFromDefaultFstab) {
ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
source none0 swap defaults readahead_size_kb=blah
source none1 swap defaults readahead_size_kb=128
source none2 swap defaults readahead_size_kb=5%
source none3 swap defaults readahead_size_kb=5kb
source none4 swap defaults readahead_size_kb=16385
source none5 swap defaults readahead_size_kb=-128
source none6 swap defaults readahead_size_kb=0
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
ASSERT_EQ(7U, fstab.size());
FstabEntry::FsMgrFlags flags = {};
auto entry = fstab.begin();
EXPECT_EQ("none0", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none1", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(128, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none2", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none3", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none4", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none5", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(-1, entry->readahead_size_kb);
entry++;
EXPECT_EQ("none6", entry->mount_point);
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
EXPECT_EQ(0, entry->readahead_size_kb);
}