Set the I/O scheduler of loop devices to 'none'

The user interface of Android devices becomes very slow under memory
pressure. This is because Android uses the zram driver on top of the loop
driver for swapping, because under memory pressure the swap code alternates
reads and writes quickly, because mq-deadline is the default scheduler for
loop devices and because mq-deadline delays writes by five seconds for such
a workload with default settings. Fix this by selecting I/O scheduler 'none'
for loop devices.

Bug: 194450129
Test: Built Android images, installed these and verified that the I/O scheduler of all loop devices is 'none' instead of 'mq-deadline'.
Change-Id: Ia5f606504b663948ab56955cad5a71885a356430
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
This commit is contained in:
Bart Van Assche 2021-07-29 13:50:43 -07:00 committed by Bart Van Assche
parent 06b95de973
commit ec5f635270

View file

@ -34,11 +34,13 @@
#include <time.h>
#include <unistd.h>
#include <array>
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>
@ -101,6 +103,7 @@ using android::base::GetUintProperty;
using android::base::Realpath;
using android::base::SetProperty;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::Timer;
using android::base::unique_fd;
using android::dm::DeviceMapper;
@ -2044,6 +2047,35 @@ int fs_mgr_do_tmpfs_mount(const char *n_name)
return 0;
}
static bool ConfigureIoScheduler(const std::string& device_path) {
if (!StartsWith(device_path, "/dev/")) {
LERROR << __func__ << ": invalid argument " << device_path;
return false;
}
const std::string iosched_path =
StringPrintf("/sys/block/%s/queue/scheduler", Basename(device_path).c_str());
unique_fd iosched_fd(open(iosched_path.c_str(), O_RDWR | O_CLOEXEC));
if (iosched_fd.get() == -1) {
PERROR << __func__ << ": failed to open " << iosched_path;
return false;
}
// Kernels before v4.1 only support 'noop'. Kernels [v4.1, v5.0) support
// 'noop' and 'none'. Kernels v5.0 and later only support 'none'.
static constexpr const std::array<std::string_view, 2> kNoScheduler = {"none", "noop"};
for (const std::string_view& scheduler : kNoScheduler) {
int ret = write(iosched_fd.get(), scheduler.data(), scheduler.size());
if (ret > 0) {
return true;
}
}
PERROR << __func__ << ": failed to write to " << iosched_path;
return false;
}
static bool InstallZramDevice(const std::string& device) {
if (!android::base::WriteStringToFile(device, ZRAM_BACK_DEV)) {
PERROR << "Cannot write " << device << " in: " << ZRAM_BACK_DEV;
@ -2076,6 +2108,8 @@ static bool PrepareZramBackingDevice(off64_t size) {
return false;
}
ConfigureIoScheduler(loop_device);
// set block size & direct IO
unique_fd loop_fd(TEMP_FAILURE_RETRY(open(loop_device.c_str(), O_RDWR | O_CLOEXEC)));
if (loop_fd.get() == -1) {