| // Copyright 2017 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. |
| |
| #ifndef SRC_STORAGE_FVM_DRIVER_VPARTITION_H_ |
| #define SRC_STORAGE_FVM_DRIVER_VPARTITION_H_ |
| |
| #include <fuchsia/hardware/block/cpp/banjo.h> |
| #include <fuchsia/hardware/block/partition/cpp/banjo.h> |
| #include <fuchsia/hardware/block/volume/cpp/banjo.h> |
| #include <lib/ddk/device.h> |
| #include <lib/zircon-internal/thread_annotations.h> |
| #include <zircon/types.h> |
| |
| #include <cstdint> |
| #include <memory> |
| |
| #include <ddktl/device.h> |
| #include <fbl/intrusive_wavl_tree.h> |
| #include <fbl/mutex.h> |
| |
| #include "src/storage/fvm/driver/slice_extent.h" |
| |
| namespace fvm { |
| |
| // Forward Declaration |
| class VPartitionManager; |
| class VPartition; |
| |
| using PartitionDeviceType = ddk::Device<VPartition, ddk::GetProtocolable, ddk::GetSizable>; |
| |
| class VPartition : public PartitionDeviceType, |
| public ddk::BlockImplProtocol<VPartition, ddk::base_protocol>, |
| public ddk::BlockPartitionProtocol<VPartition>, |
| public ddk::BlockVolumeProtocol<VPartition> { |
| public: |
| using SliceMap = fbl::WAVLTree<uint64_t, std::unique_ptr<SliceExtent>>; |
| |
| static zx_status_t Create(VPartitionManager* vpm, size_t entry_index, |
| std::unique_ptr<VPartition>* out); |
| // Device Protocol |
| zx_status_t DdkGetProtocol(uint32_t proto_id, void* out); |
| zx_off_t DdkGetSize(); |
| void DdkRelease(); |
| |
| // Block Protocol |
| void BlockImplQuery(block_info_t* info_out, size_t* block_op_size_out); |
| void BlockImplQueue(block_op_t* txn, block_impl_queue_callback completion_cb, void* cookie); |
| |
| // Partition Protocol |
| zx_status_t BlockPartitionGetGuid(guidtype_t guid_type, guid_t* out_guid); |
| zx_status_t BlockPartitionGetName(char* out_name, size_t capacity); |
| |
| // Volume Protocol |
| zx_status_t BlockVolumeExtend(const slice_extent_t* extent); |
| zx_status_t BlockVolumeShrink(const slice_extent_t* extent); |
| zx_status_t BlockVolumeGetInfo(volume_manager_info_t* out_manager, volume_info_t* out_volume); |
| zx_status_t BlockVolumeQuerySlices(const uint64_t* start_list, size_t start_count, |
| slice_region_t* out_responses_list, size_t responses_count, |
| size_t* out_responses_actual); |
| zx_status_t BlockVolumeDestroy(); |
| SliceMap::iterator ExtentBegin() TA_REQ(lock_) { return slice_map_.begin(); } |
| |
| // Returns true if the respective |vslice| is mapped to a physical slice, and sets |*pslice| to |
| // the mapped physical slice. Returns false if the |vslice| is unallocated. |
| bool SliceGetLocked(uint64_t vslice, uint64_t* out_pslice) const TA_REQ(lock_); |
| |
| // Check slices starting from |vslice_start|. |
| // Sets |*count| to the number of contiguous allocated or unallocated slices found. |
| // Sets |*allocated| to true if the vslice range is allocated, and false otherwise. |
| zx_status_t CheckSlices(uint64_t vslice_start, size_t* count, bool* allocated) TA_EXCL(lock_); |
| |
| void SliceSetUnsafe(uint64_t vslice, uint64_t pslice) TA_NO_THREAD_SAFETY_ANALYSIS { |
| SliceSetLocked(vslice, pslice); |
| } |
| // Maps the respective |vslice| to the given |pslice| and it will be considered as allocated. |
| void SliceSetLocked(uint64_t vslice, uint64_t pslice) TA_REQ(lock_); |
| |
| // Returns true if the respective vslice is considered allocated by this partition. |
| bool SliceCanFree(uint64_t vslice) const TA_REQ(lock_) { |
| auto extent = --slice_map_.upper_bound(vslice); |
| return extent.IsValid() && extent->contains(vslice); |
| } |
| |
| // Marks |vslice| free from this partition. |vslice| is required to be allocated in the |
| // partition, users should call SliceCanFree(vslice) before calling this method. |
| void SliceFreeLocked(uint64_t vslice) TA_REQ(lock_); |
| |
| // Returns the number of slices which are assigned to the vpartition. |
| size_t NumSlicesLocked() TA_REQ(lock_); |
| |
| // Destroy the extent containing the vslice. |
| void ExtentDestroyLocked(uint64_t vslice) TA_REQ(lock_); |
| |
| size_t BlockSize() const TA_NO_THREAD_SAFETY_ANALYSIS { return info_.block_size; } |
| void AddBlocksLocked(ssize_t nblocks) TA_REQ(lock_) { info_.block_count += nblocks; } |
| |
| size_t entry_index() const { return entry_index_; } |
| |
| void KillLocked() TA_REQ(lock_) { entry_index_ = 0; } |
| bool IsKilledLocked() const TA_REQ(lock_) { return entry_index_ == 0; } |
| |
| VPartition(VPartitionManager* vpm, size_t entry_index, size_t block_op_size); |
| ~VPartition(); |
| fbl::Mutex lock_; |
| |
| private: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(VPartition); |
| |
| zx_device_t* GetParent() const; |
| |
| VPartitionManager* mgr_; |
| size_t entry_index_; |
| |
| // Mapping of virtual slice number (index) to physical slice number (value). |
| // Physical slice zero is reserved to mean "unmapped", so a zeroed slice_map |
| // indicates that the vpartition is completely unmapped, and uses no |
| // physical slices. |
| SliceMap slice_map_ TA_GUARDED(lock_); |
| block_info_t info_ TA_GUARDED(lock_); |
| }; |
| |
| } // namespace fvm |
| |
| #endif // SRC_STORAGE_FVM_DRIVER_VPARTITION_H_ |