diff options
author | Wei Wang | 2017-08-02 12:27:31 -0500 |
---|---|---|
committer | Tao Bao | 2017-08-10 00:59:16 -0500 |
commit | 5226f4715d6c961311249552f7e41d68ae2e80e6 (patch) | |
tree | cb295bf1e1f06f911b9ab4ab57d88928f3241b9c /update_verifier/update_verifier.cpp | |
parent | 05b2e982adcf0afeaedf6c9d785ac1432d84dabd (diff) | |
download | platform-bootable-recovery-5226f4715d6c961311249552f7e41d68ae2e80e6.tar.gz platform-bootable-recovery-5226f4715d6c961311249552f7e41d68ae2e80e6.tar.xz platform-bootable-recovery-5226f4715d6c961311249552f7e41d68ae2e80e6.zip |
update_verifier: verify blocks in parallel
This CL is to change update_verifier to verify blocks in parallel to
maximize storage bandwidth, it also preallocate the buffer to avoid
vector allocation within reading loop.
Test:
care_map.txt:
system
16,0,517,556,32770,33084,98306,98620,163842,164156,229378,229692,294914,295228,483544,524288,524296
vendor
8,0,119,135,32770,32831,96150,98304,98306
With CL:
init: Service 'update_verifier_nonencrypted' (pid 711) exited with status 0 waiting took 2.978424 seconds
Without CL:
init: Service 'update_verifier_nonencrypted' (pid 695) exited with status 0 waiting took 4.466320 seconds
Bug: 63686531
Test: reboot with manual insert care_map.txt
Change-Id: Idf791865f15f6ff6cad89bf7ff230ee46c6adccc
(cherry picked from commit bd9664b5a01c8941949212973ca12be4df1b5d54)
Diffstat (limited to 'update_verifier/update_verifier.cpp')
-rw-r--r-- | update_verifier/update_verifier.cpp | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp index 4c3cc46c..faebbede 100644 --- a/update_verifier/update_verifier.cpp +++ b/update_verifier/update_verifier.cpp | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <unistd.h> | 45 | #include <unistd.h> |
46 | 46 | ||
47 | #include <algorithm> | 47 | #include <algorithm> |
48 | #include <future> | ||
48 | #include <string> | 49 | #include <string> |
49 | #include <vector> | 50 | #include <vector> |
50 | 51 | ||
@@ -123,11 +124,6 @@ static bool read_blocks(const std::string& partition, const std::string& range_s | |||
123 | LOG(ERROR) << "Failed to find dm block device for " << partition; | 124 | LOG(ERROR) << "Failed to find dm block device for " << partition; |
124 | return false; | 125 | return false; |
125 | } | 126 | } |
126 | android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); | ||
127 | if (fd.get() == -1) { | ||
128 | PLOG(ERROR) << "Error reading " << dm_block_device << " for partition " << partition; | ||
129 | return false; | ||
130 | } | ||
131 | 127 | ||
132 | // For block range string, first integer 'count' equals 2 * total number of valid ranges, | 128 | // For block range string, first integer 'count' equals 2 * total number of valid ranges, |
133 | // followed by 'count' number comma separated integers. Every two integers reprensent a | 129 | // followed by 'count' number comma separated integers. Every two integers reprensent a |
@@ -142,37 +138,61 @@ static bool read_blocks(const std::string& partition, const std::string& range_s | |||
142 | return false; | 138 | return false; |
143 | } | 139 | } |
144 | 140 | ||
145 | size_t blk_count = 0; | 141 | std::vector<std::future<bool>> threads; |
146 | for (size_t i = 1; i < ranges.size(); i += 2) { | 142 | size_t thread_num = std::thread::hardware_concurrency() ?: 4; |
147 | unsigned int range_start, range_end; | 143 | thread_num = std::min(thread_num, range_count / 2); |
148 | bool parse_status = android::base::ParseUint(ranges[i], &range_start); | 144 | size_t group_range_count = range_count / thread_num; |
149 | parse_status = parse_status && android::base::ParseUint(ranges[i + 1], &range_end); | ||
150 | if (!parse_status || range_start >= range_end) { | ||
151 | LOG(ERROR) << "Invalid range pair " << ranges[i] << ", " << ranges[i + 1]; | ||
152 | return false; | ||
153 | } | ||
154 | |||
155 | static constexpr size_t BLOCKSIZE = 4096; | ||
156 | if (lseek64(fd.get(), static_cast<off64_t>(range_start) * BLOCKSIZE, SEEK_SET) == -1) { | ||
157 | PLOG(ERROR) << "lseek to " << range_start << " failed"; | ||
158 | return false; | ||
159 | } | ||
160 | 145 | ||
161 | size_t remain = (range_end - range_start) * BLOCKSIZE; | 146 | for (size_t t = 0; t < thread_num; t++) { |
162 | while (remain > 0) { | 147 | auto thread_func = [t, group_range_count, &dm_block_device, &ranges, &partition]() { |
163 | size_t to_read = std::min(remain, 1024 * BLOCKSIZE); | 148 | size_t blk_count = 0; |
164 | std::vector<uint8_t> buf(to_read); | 149 | static constexpr size_t kBlockSize = 4096; |
165 | if (!android::base::ReadFully(fd.get(), buf.data(), to_read)) { | 150 | std::vector<uint8_t> buf(1024 * kBlockSize); |
166 | PLOG(ERROR) << "Failed to read blocks " << range_start << " to " << range_end; | 151 | android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY))); |
152 | if (fd.get() == -1) { | ||
153 | PLOG(ERROR) << "Error reading " << dm_block_device << " for partition " << partition; | ||
167 | return false; | 154 | return false; |
168 | } | 155 | } |
169 | remain -= to_read; | 156 | |
170 | } | 157 | for (size_t i = 1 + group_range_count * t; i < group_range_count * (t + 1) + 1; i += 2) { |
171 | blk_count += (range_end - range_start); | 158 | unsigned int range_start, range_end; |
159 | bool parse_status = android::base::ParseUint(ranges[i], &range_start); | ||
160 | parse_status = parse_status && android::base::ParseUint(ranges[i + 1], &range_end); | ||
161 | if (!parse_status || range_start >= range_end) { | ||
162 | LOG(ERROR) << "Invalid range pair " << ranges[i] << ", " << ranges[i + 1]; | ||
163 | return false; | ||
164 | } | ||
165 | |||
166 | if (lseek64(fd.get(), static_cast<off64_t>(range_start) * kBlockSize, SEEK_SET) == -1) { | ||
167 | PLOG(ERROR) << "lseek to " << range_start << " failed"; | ||
168 | return false; | ||
169 | } | ||
170 | |||
171 | size_t remain = (range_end - range_start) * kBlockSize; | ||
172 | while (remain > 0) { | ||
173 | size_t to_read = std::min(remain, 1024 * kBlockSize); | ||
174 | if (!android::base::ReadFully(fd.get(), buf.data(), to_read)) { | ||
175 | PLOG(ERROR) << "Failed to read blocks " << range_start << " to " << range_end; | ||
176 | return false; | ||
177 | } | ||
178 | remain -= to_read; | ||
179 | } | ||
180 | blk_count += (range_end - range_start); | ||
181 | } | ||
182 | LOG(INFO) << "Finished reading " << blk_count << " blocks on " << dm_block_device; | ||
183 | return true; | ||
184 | }; | ||
185 | |||
186 | threads.emplace_back(std::async(std::launch::async, thread_func)); | ||
172 | } | 187 | } |
173 | 188 | ||
174 | LOG(INFO) << "Finished reading " << blk_count << " blocks on " << dm_block_device; | 189 | bool ret = true; |
175 | return true; | 190 | for (auto& t : threads) { |
191 | ret = t.get() && ret; | ||
192 | } | ||
193 | LOG(INFO) << "Finished reading blocks on " << dm_block_device << " with " << thread_num | ||
194 | << " threads."; | ||
195 | return ret; | ||
176 | } | 196 | } |
177 | 197 | ||
178 | // Returns true to indicate a passing verification (or the error should be ignored); Otherwise | 198 | // Returns true to indicate a passing verification (or the error should be ignored); Otherwise |