• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
26 namespace android {
27 namespace init {
28 
29 using android::base::Timer;
30 using namespace std::chrono_literals;
31 
BlockDevInitializer()32 BlockDevInitializer::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 
InitDeviceMapper()39 bool BlockDevInitializer::InitDeviceMapper() {
40     const std::string dm_path = "/devices/virtual/misc/device-mapper";
41     bool found = false;
42     auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
43         if (uevent.path == dm_path) {
44             device_handler_->HandleUevent(uevent);
45             found = true;
46             return ListenerAction::kStop;
47         }
48         return ListenerAction::kContinue;
49     };
50     uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
51     if (!found) {
52         LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
53         Timer t;
54         uevent_listener_.Poll(dm_callback, 10s);
55         LOG(INFO) << "Wait for device-mapper returned after " << t;
56     }
57     if (!found) {
58         LOG(ERROR) << "device-mapper device not found after polling timeout";
59         return false;
60     }
61     return true;
62 }
63 
HandleUevent(const Uevent & uevent,std::set<std::string> * devices)64 ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
65                                                  std::set<std::string>* devices) {
66     // Ignore everything that is not a block device.
67     if (uevent.subsystem != "block") {
68         return ListenerAction::kContinue;
69     }
70 
71     auto name = uevent.partition_name;
72     if (name.empty()) {
73         size_t base_idx = uevent.path.rfind('/');
74         if (base_idx == std::string::npos) {
75             return ListenerAction::kContinue;
76         }
77         name = uevent.path.substr(base_idx + 1);
78     }
79 
80     auto iter = devices->find(name);
81     if (iter == devices->end()) {
82         return ListenerAction::kContinue;
83     }
84 
85     LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
86 
87     devices->erase(iter);
88     device_handler_->HandleUevent(uevent);
89     return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue;
90 }
91 
InitDevices(std::set<std::string> devices)92 bool BlockDevInitializer::InitDevices(std::set<std::string> devices) {
93     auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction {
94         return HandleUevent(uevent, &devices);
95     };
96     uevent_listener_.RegenerateUevents(uevent_callback);
97 
98     // UeventCallback() will remove found partitions from |devices|. So if it
99     // isn't empty here, it means some partitions are not found.
100     if (!devices.empty()) {
101         LOG(INFO) << __PRETTY_FUNCTION__
102                   << ": partition(s) not found in /sys, waiting for their uevent(s): "
103                   << android::base::Join(devices, ", ");
104         Timer t;
105         uevent_listener_.Poll(uevent_callback, 10s);
106         LOG(INFO) << "Wait for partitions returned after " << t;
107     }
108 
109     if (!devices.empty()) {
110         LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found after polling timeout: "
111                    << android::base::Join(devices, ", ");
112         return false;
113     }
114     return true;
115 }
116 
117 // Creates "/dev/block/dm-XX" for dm nodes by running coldboot on /sys/block/dm-XX.
InitDmDevice(const std::string & device)118 bool BlockDevInitializer::InitDmDevice(const std::string& device) {
119     const std::string device_name(basename(device.c_str()));
120     const std::string syspath = "/sys/block/" + device_name;
121     bool found = false;
122 
123     auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
124         if (uevent.device_name == device_name) {
125             LOG(VERBOSE) << "Creating device-mapper device : " << device;
126             device_handler_->HandleUevent(uevent);
127             found = true;
128             return ListenerAction::kStop;
129         }
130         return ListenerAction::kContinue;
131     };
132 
133     uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
134     if (!found) {
135         LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent";
136         Timer t;
137         uevent_listener_.Poll(uevent_callback, 10s);
138         LOG(INFO) << "wait for dm device '" << device << "' returned after " << t;
139     }
140     if (!found) {
141         LOG(ERROR) << "dm device '" << device << "' not found after polling timeout";
142         return false;
143     }
144     return true;
145 }
146 
147 }  // namespace init
148 }  // namespace android
149