#[repr(C)]pub struct MetaSlot {
pub storage: PCell<MetaSlotStorage>,
pub ref_count: PAtomicU64,
pub vtable_ptr: PPtr<usize>,
pub in_list: PAtomicU64,
}Fields§
§storage: PCell<MetaSlotStorage>The metadata of a frame.
It is placed at the beginning of a slot because:
- the implementation can simply cast a
*const MetaSlotto a*const AnyFrameMetafor manipulation; - if the metadata need special alignment, we can provide
at most
PAGE_METADATA_ALIGNbytes of alignment; - the subsequent fields can utilize the padding of the reference count to save space.
§Verification Design
We model the metadata of the slot as a MetaSlotStorage, which is a tagged union of the different
types of metadata defined in the development.
ref_count: PAtomicU64The reference count of the page.
Specifically, the reference count has the following meaning:
REF_COUNT_UNUSED: The page is not in use.REF_COUNT_UNIQUE: The page is owned by a [UniqueFrame].0: The page is being constructed ([Frame::from_unused]) or destructured ([drop_last_in_place]).1..REF_COUNT_MAX: The page is in use.REF_COUNT_MAX..REF_COUNT_UNIQUE: Illegal values to prevent the reference count from overflowing. Otherwise, overflowing the reference count will cause soundness issue.
vtable_ptr: PPtr<usize>The virtual table that indicates the type of the metadata. Currently we do not verify this because
of the dependency on the dyn Trait pattern. But we can revisit it now that dyn Trait is supported by Verus.
in_list: PAtomicU64This is only accessed by crate::mm::frame::linked_list.
It stores 0 if the frame is not in any list, otherwise it stores the
ID of the list.
It is ugly but allows us to tell if a frame is in a specific list by
one relaxed read. Otherwise, if we store it conditionally in storage
we would have to ensure that the type is correct before the read, which
costs a synchronization.
Implementations§
Source§impl MetaSlot
impl MetaSlot
Sourcepub exec fn cast_slot<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
&self,
addr: usize,
verus_tmp_perm: Tracked<&PointsTo<MetaSlot>>,
) -> res : ReprPtr<MetaSlot, Metadata<M>>
pub exec fn cast_slot<M: AnyFrameMeta + Repr<MetaSlotStorage>>( &self, addr: usize, verus_tmp_perm: Tracked<&PointsTo<MetaSlot>>, ) -> res : ReprPtr<MetaSlot, Metadata<M>>
perm.value() == self,addr == perm.addr(),ensuresres.ptr.addr() == addr,res.addr == addr,A helper function that casts a MetaSlot pointer to a Metadata pointer of type M.
Sourcepub exec fn cast_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
addr: usize,
verus_tmp_perm: Tracked<PointsTo<MetaSlot>>,
verus_tmp_inner_perms: Tracked<MetadataInnerPerms>,
) -> res : Tracked<PointsTo<MetaSlot, Metadata<M>>>
pub exec fn cast_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>( addr: usize, verus_tmp_perm: Tracked<PointsTo<MetaSlot>>, verus_tmp_inner_perms: Tracked<MetadataInnerPerms>, ) -> res : Tracked<PointsTo<MetaSlot, Metadata<M>>>
res@.addr == addr,res@.points_to == perm,res@.inner_perms == inner_perms,A helper function that casts MetaSlot permission to a Metadata permission of type M.
Source§impl MetaSlot
impl MetaSlot
Sourcepub open spec fn get_from_unused_inner_perms_spec(
as_unique: bool,
perms: MetadataInnerPerms,
) -> bool
pub open spec fn get_from_unused_inner_perms_spec( as_unique: bool, perms: MetadataInnerPerms, ) -> bool
{
&&& perms.ref_count.value()
== (if as_unique { REF_COUNT_UNIQUE as u64 } else { 1u64 })
&&& perms.in_list.value() == 0
&&& perms.storage.is_init()
&&& perms.vtable_ptr.is_init()
}Sourcepub open spec fn get_from_unused_spec(
paddr: Paddr,
as_unique: bool,
pre: MetaRegionOwners,
post: MetaRegionOwners,
) -> bool
pub open spec fn get_from_unused_spec( paddr: Paddr, as_unique: bool, pre: MetaRegionOwners, post: MetaRegionOwners, ) -> bool
paddr % PAGE_SIZE == 0,paddr < MAX_PADDR,pre.inv(),{
let idx = frame_to_index(paddr);
{
&&& post.slots =~= pre.slots.remove(idx)
&&& MetaSlot::get_from_unused_inner_perms_spec(
as_unique,
post.slot_owners[idx].inner_perms,
)
&&& post.slot_owners[idx].usage == PageUsage::Frame
&&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
&&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
&&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
&&& forall |i: usize| {
i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
}
}
}Sourcepub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
paddr: Paddr,
metadata: M,
as_unique: bool,
ptr: PPtr<MetaSlot>,
perm: PointsTo<MetaSlot, Metadata<M>>,
) -> bool
pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>( paddr: Paddr, metadata: M, as_unique: bool, ptr: PPtr<MetaSlot>, perm: PointsTo<MetaSlot, Metadata<M>>, ) -> bool
{
&&& ptr.addr() == frame_to_meta(paddr)
&&& perm.addr() == frame_to_meta(paddr)
&&& MetaSlot::get_from_unused_inner_perms_spec(as_unique, perm.inner_perms)
}Sourcepub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool
pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool
{ rc_perm.value() >= REF_COUNT_MAX }Sourcepub open spec fn frame_paddr_safety_cond(perm: PointsTo<MetaSlot>) -> bool
pub open spec fn frame_paddr_safety_cond(perm: PointsTo<MetaSlot>) -> bool
{
&&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
&&& perm.addr() % META_SLOT_SIZE == 0
}Sourcepub open spec fn get_from_in_use_panic_cond(
paddr: Paddr,
regions: MetaRegionOwners,
) -> bool
pub open spec fn get_from_in_use_panic_cond( paddr: Paddr, regions: MetaRegionOwners, ) -> bool
{
let idx = frame_to_index(paddr);
let pre_perms = regions.slot_owners[idx].inner_perms.ref_count.value();
pre_perms + 1 >= REF_COUNT_MAX
}Sourcepub open spec fn get_from_in_use_success(
paddr: Paddr,
pre: MetaRegionOwners,
post: MetaRegionOwners,
) -> bool
pub open spec fn get_from_in_use_success( paddr: Paddr, pre: MetaRegionOwners, post: MetaRegionOwners, ) -> bool
paddr % PAGE_SIZE == 0,paddr < MAX_PADDR,pre.inv(),{
let idx = frame_to_index(paddr);
let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
{
&&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
&&& post.slot_owners[idx].inner_perms.ref_count.id()
== pre.slot_owners[idx].inner_perms.ref_count.id()
&&& post.slot_owners[idx].inner_perms.storage
== pre.slot_owners[idx].inner_perms.storage
&&& post.slot_owners[idx].inner_perms.vtable_ptr
== pre.slot_owners[idx].inner_perms.vtable_ptr
&&& post.slot_owners[idx].inner_perms.in_list
== pre.slot_owners[idx].inner_perms.in_list
&&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
&&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
&&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
&&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
&&& forall |i: usize| {
i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
}
}
}Sourcepub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool
pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool
{
&&& (owner.inner_perms.ref_count.value() == 0
|| owner.inner_perms.ref_count.value() == REF_COUNT_UNIQUE)
&&& owner.inner_perms.storage.is_init()
&&& owner.inner_perms.in_list.value() == 0
&&& owner.raw_count == 0
}Sourcepub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> MetaSlotModel
pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> MetaSlotModel
pre.inv(),pre.status == MetaSlotStatus::SHARED,{
MetaSlotModel {
ref_count: (pre.ref_count + 1) as u64,
..pre
}
}Trait Implementations§
Source§impl OwnerOf for MetaSlot
impl OwnerOf for MetaSlot
Source§open spec fn wf(self, owner: Self::Owner) -> bool
open spec fn wf(self, owner: Self::Owner) -> bool
{
&&& self.storage.id() == owner.inner_perms.storage.id()
&&& self.ref_count.id() == owner.inner_perms.ref_count.id()
&&& self.vtable_ptr == owner.inner_perms.vtable_ptr.pptr()
&&& self.in_list.id() == owner.inner_perms.in_list.id()
}Source§type Owner = MetaSlotOwner
type Owner = MetaSlotOwner
Inv, indicating that it must
has a consistent state.Source§impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Repr<MetaSlot> for Metadata<M>
impl<M: AnyFrameMeta + Repr<MetaSlotStorage>> Repr<MetaSlot> for Metadata<M>
Source§open spec fn wf(r: MetaSlot, perm: MetadataInnerPerms) -> bool
open spec fn wf(r: MetaSlot, perm: MetadataInnerPerms) -> bool
{
&&& perm.storage.id() == r.storage.id()
&&& perm.ref_count.id() == r.ref_count.id()
&&& perm.vtable_ptr.pptr() == r.vtable_ptr
&&& perm.in_list.id() == r.in_list.id()
}Source§uninterp fn to_repr_spec(
self,
perm: MetadataInnerPerms,
) -> (MetaSlot, MetadataInnerPerms)
uninterp fn to_repr_spec( self, perm: MetadataInnerPerms, ) -> (MetaSlot, MetadataInnerPerms)
Source§exec fn to_repr(self, Tracked(perm): Tracked<&mut MetadataInnerPerms>) -> MetaSlot
exec fn to_repr(self, Tracked(perm): Tracked<&mut MetadataInnerPerms>) -> MetaSlot
Source§open spec fn from_repr_spec(r: MetaSlot, perm: MetadataInnerPerms) -> Self
open spec fn from_repr_spec(r: MetaSlot, perm: MetadataInnerPerms) -> Self
{
Metadata {
metadata: Self::metadata_from_inner_perms(perm.storage),
ref_count: perm.ref_count.value(),
vtable_ptr: perm.vtable_ptr.mem_contents(),
in_list: perm.in_list.value(),
}
}