diff --git a/Checkpoint.cpp b/Checkpoint.cpp index 0a64395..9761ca9 100644 --- a/Checkpoint.cpp +++ b/Checkpoint.cpp @@ -233,7 +233,6 @@ Status cp_prepareCheckpoint() { } namespace { -const int kBlockSize = 4096; const int kSectorSize = 512; typedef uint64_t sector_t; @@ -247,6 +246,7 @@ struct log_entry { struct log_sector { uint32_t magic; + uint32_t block_size; uint32_t count; uint32_t sequence; uint64_t sector0; @@ -308,20 +308,21 @@ void crc32(const void* data, size_t n_bytes, uint32_t* crc) { } } -} // namespace - -static void read(std::fstream& device, std::vector const& logs, sector_t sector, - char* buffer) { +void read(std::fstream& device, std::vector const& logs, sector_t sector, char* buffer, + uint32_t block_size) { + // Crude approach at first where we do this sector by sector and just scan + // the entire logs for remappings each time for (auto l = logs.rbegin(); l != logs.rend(); l++) if (sector >= l->source && (sector - l->source) * kSectorSize < l->size) sector = sector - l->source + l->dest; device.seekg(sector * kSectorSize); - device.read(buffer, kBlockSize); + device.read(buffer, block_size); } -static std::vector read(std::fstream& device, std::vector const& logs, - bool validating, sector_t sector, uint32_t size) { +// Read from the device as though we were restoring, even if we are validating +std::vector read(std::fstream& device, std::vector const& logs, bool validating, + sector_t sector, uint32_t size, uint32_t block_size) { if (!validating) { std::vector buffer(size); device.seekg(sector * kSectorSize); @@ -329,16 +330,15 @@ static std::vector read(std::fstream& device, std::vector const return buffer; } - // Crude approach at first where we do this sector by sector and just scan - // the entire logs for remappings each time std::vector buffer(size); - - for (uint32_t i = 0; i < size; i += kBlockSize, sector += kBlockSize / kSectorSize) - read(device, logs, sector, &buffer[i]); + for (uint32_t i = 0; i < size; i += block_size, sector += block_size / kSectorSize) + read(device, logs, sector, &buffer[i], block_size); return buffer; } +} // namespace + Status cp_restoreCheckpoint(const std::string& blockDevice) { bool validating = true; std::string action = "Validating"; @@ -353,17 +353,19 @@ Status cp_restoreCheckpoint(const std::string& blockDevice) { PLOG(ERROR) << "Cannot open " << blockDevice; return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str()); } - auto buffer = read(device, logs, validating, 0, kBlockSize); - log_sector& ls = *reinterpret_cast(&buffer[0]); - if (ls.magic != kMagic) { + + log_sector original_ls; + device.read(reinterpret_cast(&original_ls), sizeof(original_ls)); + if (original_ls.magic != kMagic) { LOG(ERROR) << "No magic"; return Status::fromExceptionCode(EINVAL, "No magic"); } - LOG(INFO) << action << " " << ls.sequence << " log sectors"; + LOG(INFO) << action << " " << original_ls.sequence << " log sectors"; - for (int sequence = ls.sequence; sequence >= 0 && status.isOk(); sequence--) { - auto buffer = read(device, logs, validating, 0, kBlockSize); + for (int sequence = original_ls.sequence; sequence >= 0 && status.isOk(); sequence--) { + auto buffer = + read(device, logs, validating, 0, original_ls.block_size, original_ls.block_size); log_sector& ls = *reinterpret_cast(&buffer[0]); if (ls.magic != kMagic) { LOG(ERROR) << "No magic!"; @@ -371,6 +373,12 @@ Status cp_restoreCheckpoint(const std::string& blockDevice) { break; } + if (ls.block_size != original_ls.block_size) { + LOG(ERROR) << "Block size mismatch!"; + status = Status::fromExceptionCode(EINVAL, "Block size mismatch"); + break; + } + if ((int)ls.sequence != sequence) { LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence; status = Status::fromExceptionCode( @@ -385,10 +393,10 @@ Status cp_restoreCheckpoint(const std::string& blockDevice) { for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) { LOG(INFO) << action << " " << le->size << " bytes from sector " << le->dest << " to " << le->source << " with checksum " << std::hex << le->checksum; - auto buffer = read(device, logs, validating, le->dest, le->size); - uint32_t checksum = le->source / (kBlockSize / kSectorSize); - for (size_t i = 0; i < le->size; i += kBlockSize) { - crc32(&buffer[i], kBlockSize, &checksum); + auto buffer = read(device, logs, validating, le->dest, le->size, ls.block_size); + uint32_t checksum = le->source / (ls.block_size / kSectorSize); + for (size_t i = 0; i < le->size; i += ls.block_size) { + crc32(&buffer[i], ls.block_size, &checksum); } if (le->checksum && checksum != le->checksum) { @@ -413,9 +421,10 @@ Status cp_restoreCheckpoint(const std::string& blockDevice) { } LOG(WARNING) << "Checkpoint validation failed - attempting to roll forward"; - auto buffer = read(device, logs, false, ls.sector0, kBlockSize); + auto buffer = read(device, logs, false, original_ls.sector0, original_ls.block_size, + original_ls.block_size); device.seekg(0); - device.write(&buffer[0], kBlockSize); + device.write(&buffer[0], original_ls.block_size); return Status::ok(); }