blob: 49ded05d31730190d87ee2d45cceb13b1d0351c3 [file] [log] [blame]
// 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.
#pragma once
#include <cstdint>
#include <ddk/device.h>
#include <ddktl/device.h>
#include <ddktl/protocol/block.h>
#include <ddktl/protocol/block/partition.h>
#include <ddktl/protocol/block/volume.h>
#include <fbl/intrusive_wavl_tree.h>
#include <fbl/mutex.h>
#include <fbl/unique_ptr.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
#include "slice-extent.h"
namespace fvm {
// Forward Declaration
class VPartitionManager;
class VPartition;
using PartitionDeviceType =
ddk::Device<VPartition, ddk::GetProtocolable, ddk::GetSizable, ddk::Unbindable>;
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, fbl::unique_ptr<SliceExtent>>;
static zx_status_t Create(VPartitionManager* vpm, size_t entry_index,
fbl::unique_ptr<VPartition>* out);
// Device Protocol
zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
zx_off_t DdkGetSize();
void DdkUnbind();
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 BlockVolumeQuery(parent_volume_info_t* out_info);
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_);
// 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 GetEntryIndex() const { return entry_index_; }
void KillLocked() TA_REQ(lock_) { entry_index_ = 0; }
bool IsKilledLocked() 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