libsnapshot: resume_point_count

We want to add a resume_point_count in the header to represent how many
resume points we've written. In the case that we've written less than
resume_buffer_size, we only want to read the valid resume points.

without these changes incremental OTA runs into segfault or have faulty
data when trying to FindResumeOp() as our resume points contain invalid
entries

Test: full ota followed by inc ota on cuttlefish
Change-Id: I0a8971955439639f2d0f39d9d518c1145ae15c3d
This commit is contained in:
Daniel Zheng 2023-11-13 11:05:35 -08:00
parent a503453767
commit f897650f6e
4 changed files with 14 additions and 10 deletions

View file

@ -107,8 +107,10 @@ static constexpr uint8_t kNumResumePoints = 4;
struct CowHeaderV3 : public CowHeader {
// Location of sequence buffer in COW.
uint64_t sequence_buffer_offset;
// number of currently written resume points
uint32_t resume_point_count;
// Size, in bytes, of the CowResumePoint buffer.
uint32_t resume_buffer_size;
uint32_t resume_point_max;
// Number of CowOperationV3 structs in the operation buffer, currently and total
// region size.
uint32_t op_count;

View file

@ -75,10 +75,10 @@ bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional
}
bool CowParserV3::ReadResumeBuffer(borrowed_fd fd) {
resume_points_ = std::make_shared<std::vector<ResumePoint>>(header_.resume_buffer_size);
resume_points_ = std::make_shared<std::vector<ResumePoint>>(header_.resume_point_count);
return android::base::ReadFullyAtOffset(fd, resume_points_->data(),
header_.resume_buffer_size * sizeof(ResumePoint),
header_.resume_point_count * sizeof(ResumePoint),
header_.prefix.header_size + header_.buffer_size);
}
@ -96,7 +96,7 @@ std::optional<uint32_t> CowParserV3::FindResumeOp(const uint64_t label) {
off_t CowParserV3::GetDataOffset() const {
return sizeof(CowHeaderV3) + header_.buffer_size +
header_.resume_buffer_size * sizeof(ResumePoint) +
header_.resume_point_max * sizeof(ResumePoint) +
header_.op_count_max * sizeof(CowOperation);
}
@ -105,7 +105,7 @@ bool CowParserV3::ParseOps(borrowed_fd fd, const uint32_t op_index) {
ops_->resize(op_index);
const off_t offset = header_.prefix.header_size + header_.buffer_size +
header_.resume_buffer_size * sizeof(ResumePoint);
header_.resume_point_max * sizeof(ResumePoint);
if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3),
offset)) {
PLOG(ERROR) << "read ops failed";

View file

@ -78,7 +78,8 @@ void CowWriterV3::SetupHeaders() {
// WIP: not quite sure how some of these are calculated yet, assuming buffer_size is determined
// during COW size estimation
header_.sequence_buffer_offset = 0;
header_.resume_buffer_size = kNumResumePoints;
header_.resume_point_count = 0;
header_.resume_point_max = kNumResumePoints;
header_.op_count = 0;
header_.op_count_max = 0;
header_.compression_algorithm = kCowCompressNone;
@ -296,12 +297,13 @@ bool CowWriterV3::EmitLabel(uint64_t label) {
resume_points_->end());
resume_points_->push_back({label, header_.op_count});
header_.resume_point_count++;
// remove the oldest resume point if resume_buffer is full
while (resume_points_->size() > header_.resume_buffer_size) {
while (resume_points_->size() > header_.resume_point_max) {
resume_points_->erase(resume_points_->begin());
}
CHECK_LE(resume_points_->size(), header_.resume_buffer_size);
CHECK_LE(resume_points_->size(), header_.resume_point_max);
if (!android::base::WriteFullyAtOffset(fd_, resume_points_->data(),
resume_points_->size() * sizeof(ResumePoint),

View file

@ -52,12 +52,12 @@ class CowWriterV3 : public CowWriterBase {
off_t GetOpOffset(uint32_t op_index) const {
CHECK_LT(op_index, header_.op_count_max);
return header_.prefix.header_size + header_.buffer_size +
(header_.resume_buffer_size * sizeof(ResumePoint)) +
(header_.resume_point_max * sizeof(ResumePoint)) +
(op_index * sizeof(CowOperationV3));
}
off_t GetDataOffset() const {
return sizeof(CowHeaderV3) + header_.buffer_size +
(header_.resume_buffer_size * sizeof(ResumePoint)) +
(header_.resume_point_max * sizeof(ResumePoint)) +
header_.op_count_max * sizeof(CowOperation);
}
off_t GetResumeOffset() const { return sizeof(CowHeaderV3) + header_.buffer_size; }