blob: 05e00edfda22df7c1dfa4c488c083dacf1dbb26c [file] [log] [blame]
David Anderson41175592020-03-20 19:38:28 -07001// Copyright (C) 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <chrono>
16#include <string_view>
17#include <vector>
18
19#include <android-base/chrono_utils.h>
20#include <android-base/logging.h>
21#include <android-base/strings.h>
22#include <fs_mgr.h>
23
24#include "block_dev_initializer.h"
25
26namespace android {
27namespace init {
28
29using android::base::Timer;
30using namespace std::chrono_literals;
31
32BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) {
33 auto boot_devices = android::fs_mgr::GetBootDevices();
34 device_handler_ = std::make_unique<DeviceHandler>(
35 std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
36 std::move(boot_devices), false);
37}
38
39bool BlockDevInitializer::InitDeviceMapper() {
David Anderson67cd9f02020-07-08 13:46:50 -070040 return InitMiscDevice("device-mapper");
41}
42
David Anderson32f281d2020-11-21 13:43:47 -080043bool BlockDevInitializer::InitDmUser(const std::string& name) {
44 return InitMiscDevice("dm-user!" + name);
David Anderson67cd9f02020-07-08 13:46:50 -070045}
46
47bool BlockDevInitializer::InitMiscDevice(const std::string& name) {
48 const std::string dm_path = "/devices/virtual/misc/" + name;
David Anderson41175592020-03-20 19:38:28 -070049 bool found = false;
50 auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
51 if (uevent.path == dm_path) {
52 device_handler_->HandleUevent(uevent);
53 found = true;
54 return ListenerAction::kStop;
55 }
56 return ListenerAction::kContinue;
57 };
58 uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
59 if (!found) {
David Anderson67cd9f02020-07-08 13:46:50 -070060 LOG(INFO) << name << " device not found in /sys, waiting for its uevent";
David Anderson41175592020-03-20 19:38:28 -070061 Timer t;
62 uevent_listener_.Poll(dm_callback, 10s);
David Anderson67cd9f02020-07-08 13:46:50 -070063 LOG(INFO) << "Wait for " << name << " returned after " << t;
David Anderson41175592020-03-20 19:38:28 -070064 }
65 if (!found) {
David Anderson67cd9f02020-07-08 13:46:50 -070066 LOG(ERROR) << name << " device not found after polling timeout";
David Anderson41175592020-03-20 19:38:28 -070067 return false;
68 }
69 return true;
70}
71
72ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
73 std::set<std::string>* devices) {
74 // Ignore everything that is not a block device.
75 if (uevent.subsystem != "block") {
76 return ListenerAction::kContinue;
77 }
78
79 auto name = uevent.partition_name;
80 if (name.empty()) {
81 size_t base_idx = uevent.path.rfind('/');
82 if (base_idx == std::string::npos) {
83 return ListenerAction::kContinue;
84 }
85 name = uevent.path.substr(base_idx + 1);
86 }
87
88 auto iter = devices->find(name);
89 if (iter == devices->end()) {
Tom Cherry96e5f9b2021-07-30 09:54:36 -070090 auto partition_name = DeviceHandler::GetPartitionNameForDevice(uevent.device_name);
91 if (!partition_name.empty()) {
92 iter = devices->find(partition_name);
93 }
94 if (iter == devices->end()) {
95 return ListenerAction::kContinue;
96 }
David Anderson41175592020-03-20 19:38:28 -070097 }
98
99 LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
100
101 devices->erase(iter);
102 device_handler_->HandleUevent(uevent);
103 return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue;
104}
105
106bool BlockDevInitializer::InitDevices(std::set<std::string> devices) {
107 auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction {
108 return HandleUevent(uevent, &devices);
109 };
110 uevent_listener_.RegenerateUevents(uevent_callback);
111
112 // UeventCallback() will remove found partitions from |devices|. So if it
113 // isn't empty here, it means some partitions are not found.
114 if (!devices.empty()) {
115 LOG(INFO) << __PRETTY_FUNCTION__
116 << ": partition(s) not found in /sys, waiting for their uevent(s): "
117 << android::base::Join(devices, ", ");
118 Timer t;
119 uevent_listener_.Poll(uevent_callback, 10s);
120 LOG(INFO) << "Wait for partitions returned after " << t;
121 }
122
123 if (!devices.empty()) {
124 LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
125 << android::base::Join(devices, ", ");
126 return false;
127 }
128 return true;
129}
130
131// Creates "/dev/block/dm-XX" for dm nodes by running coldboot on /sys/block/dm-XX.
132bool BlockDevInitializer::InitDmDevice(const std::string& device) {
133 const std::string device_name(basename(device.c_str()));
134 const std::string syspath = "/sys/block/" + device_name;
135 bool found = false;
136
137 auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
138 if (uevent.device_name == device_name) {
139 LOG(VERBOSE) << "Creating device-mapper device : " << device;
140 device_handler_->HandleUevent(uevent);
141 found = true;
142 return ListenerAction::kStop;
143 }
144 return ListenerAction::kContinue;
145 };
146
147 uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
148 if (!found) {
149 LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent";
150 Timer t;
151 uevent_listener_.Poll(uevent_callback, 10s);
152 LOG(INFO) << "wait for dm device '" << device << "' returned after " << t;
153 }
154 if (!found) {
155 LOG(ERROR) << "dm device '" << device << "' not found after polling timeout";
156 return false;
157 }
158 return true;
159}
160
161} // namespace init
162} // namespace android