|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // This file describes a utility for storing pending allocation state for a Minfs vnode. | 
|  |  | 
|  | #ifndef SRC_STORAGE_MINFS_VNODE_ALLOCATION_H_ | 
|  | #define SRC_STORAGE_MINFS_VNODE_ALLOCATION_H_ | 
|  |  | 
|  | #include <bitmap/rle-bitmap.h> | 
|  |  | 
|  | #include "src/storage/minfs/allocator/allocator.h" | 
|  | #include "src/storage/minfs/format.h" | 
|  |  | 
|  | namespace minfs { | 
|  |  | 
|  | // PendingAllocationData stores information about data blocks which are yet to be allocated. | 
|  | // This includes the relative index of each block to be processed, corresponding | 
|  | // reservations, and (in the future) additional information about modifications to the inode's size | 
|  | // and block count. | 
|  | class PendingAllocationData { | 
|  | public: | 
|  | using const_iterator = bitmap::RleBitmapBase<blk_t>::const_iterator; | 
|  | PendingAllocationData() = default; | 
|  | ~PendingAllocationData() { ZX_DEBUG_ASSERT(IsEmpty()); } | 
|  |  | 
|  | // Clears out all allocation/reservation data. | 
|  | void Reset(blk_t size); | 
|  |  | 
|  | // Returns the |start| and |count| of the first range in the block_map_. | 
|  | zx_status_t GetNextRange(blk_t* start, blk_t* count) const; | 
|  |  | 
|  | // Returns true if no blocks are marked for allocation. | 
|  | bool IsEmpty() const { return block_map_.num_bits() == 0 && new_blocks_ == 0; } | 
|  |  | 
|  | // Returns true if |block_num| is marked in the block_map_. | 
|  | bool IsPending(blk_t block_num) const { return block_map_.GetOne(block_num); } | 
|  |  | 
|  | // Sets |block_num| in the block_map_. |allocated| indicates whether the block at |block_num| | 
|  | // was previously allocated. | 
|  | void SetPending(blk_t block_num, bool allocated); | 
|  |  | 
|  | // Clears |block_num| from the block_map_. |allocated| indicates whether the block at | 
|  | // |block_num| was previously allocated. Returns true if the block_num was cleared from the map | 
|  | // (i.e., it was set in the map initially). | 
|  | bool ClearPending(blk_t block_num, bool allocated); | 
|  |  | 
|  | // Returns the count of pending blocks which are not already allocated. | 
|  | blk_t GetNewPending() const { return new_blocks_; } | 
|  |  | 
|  | // Returns the total number of pending blocks. | 
|  | blk_t GetTotalPending() const { return static_cast<blk_t>(block_map_.num_bits()); } | 
|  |  | 
|  | blk_t GetNodeSize() const { return node_size_; } | 
|  |  | 
|  | void SetNodeSize(blk_t size) { node_size_ = size; } | 
|  |  | 
|  | // Iterate over the ranges in the bitmap.  Modifying the list while | 
|  | // iterating over it may yield undefined results. | 
|  | const_iterator cbegin() const { return block_map_.cbegin(); } | 
|  | const_iterator cend() const { return block_map_.cend(); } | 
|  |  | 
|  | private: | 
|  | // Number of additional blocks to be allocated on behalf of the vnode. | 
|  | // | 
|  | // For example, when writing to a block which has already been allocated to a file, | 
|  | // we will allocate a "different" block, but simultenously free the old data block. | 
|  | // This results in a net "block change" of zero blocks. | 
|  | // | 
|  | // This size should always be less than or equal to |block_map_.size()|. | 
|  | blk_t new_blocks_ = 0; | 
|  |  | 
|  | // The expected size of the vnode after all blocks in block_map_ have been allocated. | 
|  | blk_t node_size_ = 0; | 
|  |  | 
|  | // Map of relative data blocks to be allocated at a later time. | 
|  | bitmap::RleBitmapBase<blk_t> block_map_; | 
|  | }; | 
|  |  | 
|  | }  // namespace minfs | 
|  |  | 
|  | #endif  // SRC_STORAGE_MINFS_VNODE_ALLOCATION_H_ |