Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd9664b5 authored by Wei Wang's avatar Wei Wang
Browse files

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
parent 5c2bc51b
Loading
Loading
Loading
Loading
+51 −31
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <unistd.h>

#include <algorithm>
#include <future>
#include <string>
#include <vector>

@@ -123,11 +124,6 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
    LOG(ERROR) << "Failed to find dm block device for " << partition;
    return false;
  }
  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
  if (fd.get() == -1) {
    PLOG(ERROR) << "Error reading " << dm_block_device << " for partition " << partition;
    return false;
  }

  // For block range string, first integer 'count' equals 2 * total number of valid ranges,
  // followed by 'count' number comma separated integers. Every two integers reprensent a
@@ -142,8 +138,23 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
    return false;
  }

  std::vector<std::future<bool>> threads;
  size_t thread_num = std::thread::hardware_concurrency() ?: 4;
  thread_num = std::min(thread_num, range_count / 2);
  size_t group_range_count = range_count / thread_num;

  for (size_t t = 0; t < thread_num; t++) {
    auto thread_func = [t, group_range_count, &dm_block_device, &ranges, &partition]() {
      size_t blk_count = 0;
  for (size_t i = 1; i < ranges.size(); i += 2) {
      static constexpr size_t kBlockSize = 4096;
      std::vector<uint8_t> buf(1024 * kBlockSize);
      android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
      if (fd.get() == -1) {
        PLOG(ERROR) << "Error reading " << dm_block_device << " for partition " << partition;
        return false;
      }

      for (size_t i = 1 + group_range_count * t; i < group_range_count * (t + 1) + 1; i += 2) {
        unsigned int range_start, range_end;
        bool parse_status = android::base::ParseUint(ranges[i], &range_start);
        parse_status = parse_status && android::base::ParseUint(ranges[i + 1], &range_end);
@@ -152,16 +163,14 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
          return false;
        }

    static constexpr size_t BLOCKSIZE = 4096;
    if (lseek64(fd.get(), static_cast<off64_t>(range_start) * BLOCKSIZE, SEEK_SET) == -1) {
        if (lseek64(fd.get(), static_cast<off64_t>(range_start) * kBlockSize, SEEK_SET) == -1) {
          PLOG(ERROR) << "lseek to " << range_start << " failed";
          return false;
        }

    size_t remain = (range_end - range_start) * BLOCKSIZE;
        size_t remain = (range_end - range_start) * kBlockSize;
        while (remain > 0) {
      size_t to_read = std::min(remain, 1024 * BLOCKSIZE);
      std::vector<uint8_t> buf(to_read);
          size_t to_read = std::min(remain, 1024 * kBlockSize);
          if (!android::base::ReadFully(fd.get(), buf.data(), to_read)) {
            PLOG(ERROR) << "Failed to read blocks " << range_start << " to " << range_end;
            return false;
@@ -170,9 +179,20 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
        }
        blk_count += (range_end - range_start);
      }

      LOG(INFO) << "Finished reading " << blk_count << " blocks on " << dm_block_device;
      return true;
    };

    threads.emplace_back(std::async(std::launch::async, thread_func));
  }

  bool ret = true;
  for (auto& t : threads) {
    ret = t.get() && ret;
  }
  LOG(INFO) << "Finished reading blocks on " << dm_block_device << " with " << thread_num
            << " threads.";
  return ret;
}

// Returns true to indicate a passing verification (or the error should be ignored); Otherwise