diff options
Diffstat (limited to 'fs_mgr/libsnapshot/snapuserd.cpp')
-rw-r--r-- | fs_mgr/libsnapshot/snapuserd.cpp | 769 |
1 files changed, 0 insertions, 769 deletions
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp deleted file mode 100644 index 57a61a791..000000000 --- a/fs_mgr/libsnapshot/snapuserd.cpp +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "snapuserd.h" - -#include <csignal> -#include <optional> -#include <set> - -#include <libsnapshot/snapuserd_client.h> - -namespace android { -namespace snapshot { - -using namespace android; -using namespace android::dm; -using android::base::unique_fd; - -#define SNAP_LOG(level) LOG(level) << misc_name_ << ": " -#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": " - -Snapuserd::Snapuserd(const std::string& misc_name, const std::string& cow_device, - const std::string& backing_device) { - misc_name_ = misc_name; - cow_device_ = cow_device; - backing_store_device_ = backing_device; - control_device_ = "/dev/dm-user/" + misc_name; -} - -bool Snapuserd::InitializeWorkers() { - for (int i = 0; i < NUM_THREADS_PER_PARTITION; i++) { - std::unique_ptr<WorkerThread> wt = std::make_unique<WorkerThread>( - cow_device_, backing_store_device_, control_device_, misc_name_, GetSharedPtr()); - - worker_threads_.push_back(std::move(wt)); - } - - read_ahead_thread_ = std::make_unique<ReadAheadThread>(cow_device_, backing_store_device_, - misc_name_, GetSharedPtr()); - return true; -} - -bool Snapuserd::CommitMerge(int num_merge_ops) { - struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_); - ch->num_merge_ops += num_merge_ops; - - if (read_ahead_feature_ && read_ahead_ops_.size() > 0) { - struct BufferState* ra_state = GetBufferState(); - ra_state->read_ahead_state = kCowReadAheadInProgress; - } - - int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC); - if (ret < 0) { - PLOG(ERROR) << "msync header failed: " << ret; - return false; - } - - merge_initiated_ = true; - - return true; -} - -void Snapuserd::PrepareReadAhead() { - if (!read_ahead_feature_) { - return; - } - - struct BufferState* ra_state = GetBufferState(); - // Check if the data has to be re-constructed from COW device - if (ra_state->read_ahead_state == kCowReadAheadDone) { - populate_data_from_cow_ = true; - } else { - populate_data_from_cow_ = false; - } - - StartReadAhead(); -} - -bool Snapuserd::GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block, void* buffer) { - if (!lock->owns_lock()) { - SNAP_LOG(ERROR) << "GetRABuffer - Lock not held"; - return false; - } - std::unordered_map<uint64_t, void*>::iterator it = read_ahead_buffer_map_.find(block); - - // This will be true only for IO's generated as part of reading a root - // filesystem. IO's related to merge should always be in read-ahead cache. - if (it == read_ahead_buffer_map_.end()) { - return false; - } - - // Theoretically, we can send the data back from the read-ahead buffer - // all the way to the kernel without memcpy. However, if the IO is - // un-aligned, the wrapper function will need to touch the read-ahead - // buffers and transitions will be bit more complicated. - memcpy(buffer, it->second, BLOCK_SZ); - return true; -} - -// ========== State transition functions for read-ahead operations =========== - -bool Snapuserd::GetReadAheadPopulatedBuffer(uint64_t block, void* buffer) { - if (!read_ahead_feature_) { - return false; - } - - { - std::unique_lock<std::mutex> lock(lock_); - if (io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE) { - return false; - } - - if (io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS) { - return GetRABuffer(&lock, block, buffer); - } - } - - { - // Read-ahead thread IO is in-progress. Wait for it to complete - std::unique_lock<std::mutex> lock(lock_); - while (!(io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE || - io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS)) { - cv.wait(lock); - } - - return GetRABuffer(&lock, block, buffer); - } -} - -// This is invoked by read-ahead thread waiting for merge IO's -// to complete -bool Snapuserd::WaitForMergeToComplete() { - { - std::unique_lock<std::mutex> lock(lock_); - while (!(io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_BEGIN || - io_state_ == READ_AHEAD_IO_TRANSITION::IO_TERMINATED)) { - cv.wait(lock); - } - - if (io_state_ == READ_AHEAD_IO_TRANSITION::IO_TERMINATED) { - return false; - } - - io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_IN_PROGRESS; - return true; - } -} - -// This is invoked during the launch of worker threads. We wait -// for read-ahead thread to by fully up before worker threads -// are launched; else we will have a race between worker threads -// and read-ahead thread specifically during re-construction. -bool Snapuserd::WaitForReadAheadToStart() { - { - std::unique_lock<std::mutex> lock(lock_); - while (!(io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS || - io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE)) { - cv.wait(lock); - } - - if (io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE) { - return false; - } - - return true; - } -} - -// Invoked by worker threads when a sequence of merge operation -// is complete notifying read-ahead thread to make forward -// progress. -void Snapuserd::StartReadAhead() { - { - std::lock_guard<std::mutex> lock(lock_); - io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_BEGIN; - } - - cv.notify_one(); -} - -void Snapuserd::MergeCompleted() { - { - std::lock_guard<std::mutex> lock(lock_); - io_state_ = READ_AHEAD_IO_TRANSITION::IO_TERMINATED; - } - - cv.notify_one(); -} - -bool Snapuserd::ReadAheadIOCompleted(bool sync) { - if (sync) { - // Flush the entire buffer region - int ret = msync(mapped_addr_, total_mapped_addr_length_, MS_SYNC); - if (ret < 0) { - PLOG(ERROR) << "msync failed after ReadAheadIOCompleted: " << ret; - return false; - } - - // Metadata and data are synced. Now, update the state. - // We need to update the state after flushing data; if there is a crash - // when read-ahead IO is in progress, the state of data in the COW file - // is unknown. kCowReadAheadDone acts as a checkpoint wherein the data - // in the scratch space is good and during next reboot, read-ahead thread - // can safely re-construct the data. - struct BufferState* ra_state = GetBufferState(); - ra_state->read_ahead_state = kCowReadAheadDone; - - ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC); - if (ret < 0) { - PLOG(ERROR) << "msync failed to flush Readahead completion state..."; - return false; - } - } - - // Notify the worker threads - { - std::lock_guard<std::mutex> lock(lock_); - io_state_ = READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS; - } - - cv.notify_all(); - return true; -} - -void Snapuserd::ReadAheadIOFailed() { - { - std::lock_guard<std::mutex> lock(lock_); - io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE; - } - - cv.notify_all(); -} - -//========== End of state transition functions ==================== - -bool Snapuserd::IsChunkIdMetadata(chunk_t chunk) { - uint32_t stride = exceptions_per_area_ + 1; - lldiv_t divresult = lldiv(chunk, stride); - - return (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS); -} - -// Find the next free chunk-id to be assigned. Check if the next free -// chunk-id represents a metadata page. If so, skip it. -chunk_t Snapuserd::GetNextAllocatableChunkId(chunk_t chunk) { - chunk_t next_chunk = chunk + 1; - - if (IsChunkIdMetadata(next_chunk)) { - next_chunk += 1; - } - return next_chunk; -} - -void Snapuserd::CheckMergeCompletionStatus() { - if (!merge_initiated_) { - SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: " << reader_->total_data_ops(); - return; - } - - struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_); - - SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops - << " Total-data-ops: " << reader_->total_data_ops(); -} - -/* - * Read the metadata from COW device and - * construct the metadata as required by the kernel. - * - * Please see design on kernel COW format - * - * 1: Read the metadata from internal COW device - * 2: There are 3 COW operations: - * a: Replace op - * b: Copy op - * c: Zero op - * 3: For each of the 3 operations, op->new_block - * represents the block number in the base device - * for which one of the 3 operations have to be applied. - * This represents the old_chunk in the kernel COW format - * 4: We need to assign new_chunk for a corresponding old_chunk - * 5: The algorithm is similar to how kernel assigns chunk number - * while creating exceptions. However, there are few cases - * which needs to be addressed here: - * a: During merge process, kernel scans the metadata page - * from backwards when merge is initiated. Since, we need - * to make sure that the merge ordering follows our COW format, - * we read the COW operation from backwards and populate the - * metadata so that when kernel starts the merging from backwards, - * those ops correspond to the beginning of our COW format. - * b: Kernel can merge successive operations if the two chunk IDs - * are contiguous. This can be problematic when there is a crash - * during merge; specifically when the merge operation has dependency. - * These dependencies can only happen during copy operations. - * - * To avoid this problem, we make sure overlap copy operations - * are not batch merged. - * 6: Use a monotonically increasing chunk number to assign the - * new_chunk - * 7: Each chunk-id represents either - * a: Metadata page or - * b: Data page - * 8: Chunk-id representing a data page is stored in a map. - * 9: Chunk-id representing a metadata page is converted into a vector - * index. We store this in vector as kernel requests metadata during - * two stage: - * a: When initial dm-snapshot device is created, kernel requests - * all the metadata and stores it in its internal data-structures. - * b: During merge, kernel once again requests the same metadata - * once-again. - * In both these cases, a quick lookup based on chunk-id is done. - * 10: When chunk number is incremented, we need to make sure that - * if the chunk is representing a metadata page and skip. - * 11: Each 4k page will contain 256 disk exceptions. We call this - * exceptions_per_area_ - * 12: Kernel will stop issuing metadata IO request when new-chunk ID is 0. - */ -bool Snapuserd::ReadMetadata() { - reader_ = std::make_unique<CowReader>(); - CowHeader header; - CowOptions options; - bool metadata_found = false; - int replace_ops = 0, zero_ops = 0, copy_ops = 0; - - SNAP_LOG(DEBUG) << "ReadMetadata: Parsing cow file"; - - if (!reader_->Parse(cow_fd_)) { - SNAP_LOG(ERROR) << "Failed to parse"; - return false; - } - - if (!reader_->GetHeader(&header)) { - SNAP_LOG(ERROR) << "Failed to get header"; - return false; - } - - if (!(header.block_size == BLOCK_SZ)) { - SNAP_LOG(ERROR) << "Invalid header block size found: " << header.block_size; - return false; - } - - reader_->InitializeMerge(); - SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops; - - if (!MmapMetadata()) { - SNAP_LOG(ERROR) << "mmap failed"; - return false; - } - - // Initialize the iterator for reading metadata - cowop_riter_ = reader_->GetRevOpIter(); - - exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception); - - // Start from chunk number 2. Chunk 0 represents header and chunk 1 - // represents first metadata page. - chunk_t data_chunk_id = NUM_SNAPSHOT_HDR_CHUNKS + 1; - size_t num_ops = 0; - - loff_t offset = 0; - std::unique_ptr<uint8_t[]> de_ptr = - std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception)); - - // This memset is important. Kernel will stop issuing IO when new-chunk ID - // is 0. When Area is not filled completely with all 256 exceptions, - // this memset will ensure that metadata read is completed. - memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); - - while (!cowop_riter_->Done()) { - const CowOperation* cow_op = &cowop_riter_->Get(); - struct disk_exception* de = - reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset); - - if (IsMetadataOp(*cow_op)) { - cowop_riter_->Next(); - continue; - } - - metadata_found = true; - // This loop will handle all the replace and zero ops. - // We will handle the copy ops later as it requires special - // handling of assigning chunk-id's. Furthermore, we make - // sure that replace/zero and copy ops are not batch merged; hence, - // the bump in the chunk_id before break of this loop - if (cow_op->type == kCowCopyOp) { - data_chunk_id = GetNextAllocatableChunkId(data_chunk_id); - break; - } - - if (cow_op->type == kCowReplaceOp) { - replace_ops++; - } else if (cow_op->type == kCowZeroOp) { - zero_ops++; - } - - // Construct the disk-exception - de->old_chunk = cow_op->new_block; - de->new_chunk = data_chunk_id; - - - // Store operation pointer. - chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op)); - num_ops += 1; - offset += sizeof(struct disk_exception); - cowop_riter_->Next(); - - SNAP_LOG(DEBUG) << num_ops << ":" - << " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk; - - if (num_ops == exceptions_per_area_) { - // Store it in vector at the right index. This maps the chunk-id to - // vector index. - vec_.push_back(std::move(de_ptr)); - offset = 0; - num_ops = 0; - - // Create buffer for next area - de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * - sizeof(struct disk_exception)); - memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); - - if (cowop_riter_->Done()) { - vec_.push_back(std::move(de_ptr)); - } - } - - data_chunk_id = GetNextAllocatableChunkId(data_chunk_id); - } - - int num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ); - std::optional<chunk_t> prev_id = {}; - std::vector<const CowOperation*> vec; - std::set<uint64_t> dest_blocks; - std::set<uint64_t> source_blocks; - size_t pending_copy_ops = exceptions_per_area_ - num_ops; - uint64_t total_copy_ops = reader_->total_copy_ops(); - - SNAP_LOG(DEBUG) << " Processing copy-ops at Area: " << vec_.size() - << " Number of replace/zero ops completed in this area: " << num_ops - << " Pending copy ops for this area: " << pending_copy_ops; - while (!cowop_riter_->Done()) { - do { - const CowOperation* cow_op = &cowop_riter_->Get(); - if (IsMetadataOp(*cow_op)) { - cowop_riter_->Next(); - continue; - } - - // We have two cases specific cases: - // - // ===================================================== - // Case 1: Overlapping copy regions - // - // Ex: - // - // Source -> Destination - // - // 1: 15 -> 18 - // 2: 16 -> 19 - // 3: 17 -> 20 - // 4: 18 -> 21 - // 5: 19 -> 22 - // 6: 20 -> 23 - // - // We have 6 copy operations to be executed in OTA and there is a overlap. Update-engine - // will write to COW file as follows: - // - // Op-1: 20 -> 23 - // Op-2: 19 -> 22 - // Op-3: 18 -> 21 - // Op-4: 17 -> 20 - // Op-5: 16 -> 19 - // Op-6: 15 -> 18 - // - // Note that the blocks numbers are contiguous. Hence, all 6 copy - // operations can be batch merged. However, that will be - // problematic if we have a crash as block 20, 19, 18 would have - // been overwritten and hence subsequent recovery may end up with - // a silent data corruption when op-1, op-2 and op-3 are - // re-executed. - // - // To address the above problem, read-ahead thread will - // read all the 6 source blocks, cache them in the scratch - // space of the COW file. During merge, read-ahead - // thread will serve the blocks from the read-ahead cache. - // If there is a crash during merge; on subsequent reboot, - // read-ahead thread will recover the data from the - // scratch space and re-construct it thereby there - // is no loss of data. - // - // Note that we will follow the same order of COW operations - // as present in the COW file. This will make sure that\ - // the merge of operations are done based on the ops present - // in the file. - //=========================================================== - if (prev_id.has_value()) { - if (dest_blocks.count(cow_op->new_block) || source_blocks.count(cow_op->source)) { - break; - } - } - metadata_found = true; - pending_copy_ops -= 1; - vec.push_back(cow_op); - dest_blocks.insert(cow_op->source); - source_blocks.insert(cow_op->new_block); - prev_id = cow_op->new_block; - cowop_riter_->Next(); - } while (!cowop_riter_->Done() && pending_copy_ops); - - data_chunk_id = GetNextAllocatableChunkId(data_chunk_id); - SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << vec.size() - << " Area: " << vec_.size() << " Area offset: " << offset - << " Pending-copy-ops in this area: " << pending_copy_ops; - - for (size_t i = 0; i < vec.size(); i++) { - struct disk_exception* de = - reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset); - const CowOperation* cow_op = vec[i]; - - de->old_chunk = cow_op->new_block; - de->new_chunk = data_chunk_id; - - // Store operation pointer. - chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op)); - offset += sizeof(struct disk_exception); - num_ops += 1; - copy_ops++; - if (read_ahead_feature_) { - read_ahead_ops_.push_back(cow_op); - } - - SNAP_LOG(DEBUG) << num_ops << ":" - << " Copy-op: " - << " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk; - - if (num_ops == exceptions_per_area_) { - // Store it in vector at the right index. This maps the chunk-id to - // vector index. - vec_.push_back(std::move(de_ptr)); - num_ops = 0; - offset = 0; - - // Create buffer for next area - de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ * - sizeof(struct disk_exception)); - memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception))); - - if (cowop_riter_->Done()) { - vec_.push_back(std::move(de_ptr)); - SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size(); - } - - if (!(pending_copy_ops == 0)) { - SNAP_LOG(ERROR) - << "Invalid pending_copy_ops: expected: 0 found: " << pending_copy_ops; - return false; - } - pending_copy_ops = exceptions_per_area_; - } - - data_chunk_id = GetNextAllocatableChunkId(data_chunk_id); - total_copy_ops -= 1; - /* - * Split the number of ops based on the size of read-ahead buffer - * region. We need to ensure that kernel doesn't issue IO on blocks - * which are not read by the read-ahead thread. - */ - if (read_ahead_feature_ && (total_copy_ops % num_ra_ops_per_iter == 0)) { - data_chunk_id = GetNextAllocatableChunkId(data_chunk_id); - } - } - vec.clear(); - dest_blocks.clear(); - source_blocks.clear(); - prev_id.reset(); - } - - // Partially filled area or there is no metadata - // If there is no metadata, fill with zero so that kernel - // is aware that merge is completed. - if (num_ops || !metadata_found) { - vec_.push_back(std::move(de_ptr)); - SNAP_LOG(DEBUG) << "ReadMetadata() completed. Partially filled area num_ops: " << num_ops - << "Areas : " << vec_.size(); - } - - chunk_vec_.shrink_to_fit(); - vec_.shrink_to_fit(); - read_ahead_ops_.shrink_to_fit(); - - // Sort the vector based on sectors as we need this during un-aligned access - std::sort(chunk_vec_.begin(), chunk_vec_.end(), compare); - - SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id - << " Num Sector: " << ChunkToSector(data_chunk_id) - << " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops - << " Copy-ops: " << copy_ops << " Areas: " << vec_.size() - << " Num-ops-merged: " << header.num_merge_ops - << " Total-data-ops: " << reader_->total_data_ops(); - - // Total number of sectors required for creating dm-user device - num_sectors_ = ChunkToSector(data_chunk_id); - merge_initiated_ = false; - PrepareReadAhead(); - - return true; -} - -bool Snapuserd::MmapMetadata() { - CowHeader header; - reader_->GetHeader(&header); - - if (header.major_version >= 2 && header.buffer_size > 0) { - total_mapped_addr_length_ = header.header_size + BUFFER_REGION_DEFAULT_SIZE; - read_ahead_feature_ = true; - } else { - // mmap the first 4k page - older COW format - total_mapped_addr_length_ = BLOCK_SZ; - read_ahead_feature_ = false; - } - - mapped_addr_ = mmap(NULL, total_mapped_addr_length_, PROT_READ | PROT_WRITE, MAP_SHARED, - cow_fd_.get(), 0); - if (mapped_addr_ == MAP_FAILED) { - SNAP_LOG(ERROR) << "mmap metadata failed"; - return false; - } - - return true; -} - -void Snapuserd::UnmapBufferRegion() { - int ret = munmap(mapped_addr_, total_mapped_addr_length_); - if (ret < 0) { - SNAP_PLOG(ERROR) << "munmap failed"; - } -} - -void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*, - unsigned int, const char* message) { - if (severity == android::base::ERROR) { - fprintf(stderr, "%s\n", message); - } else { - fprintf(stdout, "%s\n", message); - } -} - -bool Snapuserd::InitCowDevice() { - cow_fd_.reset(open(cow_device_.c_str(), O_RDWR)); - if (cow_fd_ < 0) { - SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_; - return false; - } - - return ReadMetadata(); -} - -/* - * Entry point to launch threads - */ -bool Snapuserd::Start() { - std::vector<std::future<bool>> threads; - std::future<bool> ra_thread; - bool rathread = (read_ahead_feature_ && (read_ahead_ops_.size() > 0)); - - // Start the read-ahead thread and wait - // for it as the data has to be re-constructed - // from COW device. - if (rathread) { - ra_thread = std::async(std::launch::async, &ReadAheadThread::RunThread, - read_ahead_thread_.get()); - if (!WaitForReadAheadToStart()) { - SNAP_LOG(ERROR) << "Failed to start Read-ahead thread..."; - return false; - } - - SNAP_LOG(INFO) << "Read-ahead thread started..."; - } - - // Launch worker threads - for (int i = 0; i < worker_threads_.size(); i++) { - threads.emplace_back( - std::async(std::launch::async, &WorkerThread::RunThread, worker_threads_[i].get())); - } - - bool ret = true; - for (auto& t : threads) { - ret = t.get() && ret; - } - - if (rathread) { - // Notify the read-ahead thread that all worker threads - // are done. We need this explicit notification when - // there is an IO failure or there was a switch - // of dm-user table; thus, forcing the read-ahead - // thread to wake up. - MergeCompleted(); - ret = ret && ra_thread.get(); - } - - return ret; -} - -uint64_t Snapuserd::GetBufferMetadataOffset() { - CowHeader header; - reader_->GetHeader(&header); - - size_t size = header.header_size + sizeof(BufferState); - return size; -} - -/* - * Metadata for read-ahead is 16 bytes. For a 2 MB region, we will - * end up with 8k (2 PAGE) worth of metadata. Thus, a 2MB buffer - * region is split into: - * - * 1: 8k metadata - * - */ -size_t Snapuserd::GetBufferMetadataSize() { - CowHeader header; - reader_->GetHeader(&header); - - size_t metadata_bytes = (header.buffer_size * sizeof(struct ScratchMetadata)) / BLOCK_SZ; - return metadata_bytes; -} - -size_t Snapuserd::GetBufferDataOffset() { - CowHeader header; - reader_->GetHeader(&header); - - return (header.header_size + GetBufferMetadataSize()); -} - -/* - * (2MB - 8K = 2088960 bytes) will be the buffer region to hold the data. - */ -size_t Snapuserd::GetBufferDataSize() { - CowHeader header; - reader_->GetHeader(&header); - - size_t size = header.buffer_size - GetBufferMetadataSize(); - return size; -} - -struct BufferState* Snapuserd::GetBufferState() { - CowHeader header; - reader_->GetHeader(&header); - - struct BufferState* ra_state = - reinterpret_cast<struct BufferState*>((char*)mapped_addr_ + header.header_size); - return ra_state; -} - -} // namespace snapshot -} // namespace android |