blob: 3d188e07c63623515250b63edbbb9f9ec67bcc32 [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<size_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(); }
// Given a virtual slice, return the physical slice allocated
// to it. If no slice is allocated, return PSLICE_UNALLOCATED.
uint32_t SliceGetLocked(size_t vslice) 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(size_t vslice_start, size_t* count, bool* allocated) TA_EXCL(lock_);
zx_status_t SliceSetUnsafe(size_t vslice, uint32_t pslice) TA_NO_THREAD_SAFETY_ANALYSIS {
return SliceSetLocked(vslice, pslice);
}
zx_status_t SliceSetLocked(size_t vslice, uint32_t pslice) TA_REQ(lock_);
bool SliceCanFree(size_t vslice) const TA_REQ(lock_) {
auto extent = --slice_map_.upper_bound(vslice);
return extent.IsValid() && extent->get(vslice) != PSLICE_UNALLOCATED;
}
// Returns "true" if slice freed successfully, false otherwise.
// If freeing from the back of an extent, guaranteed not to fail.
bool SliceFreeLocked(size_t vslice) TA_REQ(lock_);
// Destroy the extent containing the vslice.
void ExtentDestroyLocked(size_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