class PagedVnode
Defined at line 48 of file ../../src/storage/lib/vfs/cpp/paged_vnode.h
A Vnode that supports paged I/O.
To supply pager requests:
- Implement Vnode::GetVmo().
- Use PagedVnode::EnsureCreateVmo() to create the data mapping. This will create it in such a
way that it's registered with the paging system for callbacks.
- Do paged_vmo().create_child() to clone the VMO backing this node.
- Set the rights on the cloned VMO with the rights passed to GetVmo().
- Call DidCloneVmo() to start tracking the clone.
- Populate the GetVmo() out parameter with the child VMO.
- Implement VmoRead() to fill the VMO data when requested.
- Implement VmoDirty() to deal with the transition of the VMO page state from clean to dirty.
To unregister from pager requests:
- This class will be automatically kept in scope by has_clones_reference_ as long as there are
memory mappings.
- The VMO will be automatically freed when there are no more mappings.
- You can override this behavior by overriding OnNoPagedVmoClones().
Public Methods
void VmoRead (uint64_t offset, uint64_t length)
Called by the paging system in response to a kernel request to fill data into this node's VMO.
- On success, calls vfs()->SupplyPages() with the created data range.
- On failure, calls vfs()->ReportPagerError() with the error information.
The success or failure cases can happen synchronously (from within this call stack) or
asynchronously in the future. Failure to report success or failure will hang the requesting
process.
Note that offset + length will be page-aligned so can extend beyond the end of the file.
Race conditions
---------------
Since the OnNoPagedVmoClones() is not synchronized with page requests, these requests can come
in after there are no clones.
Additionally, because this function is called outside of the Vfs' lock, this function can be
called even if the VMO handle is detached and freed. If the VMO handle is freed, it is safe to
drop this request (there's no way to even report an error without a handle). More
theoretically, if the VMO was freed, then a new one created, and then we get a stale read for
the first one, the kernel might not actually need the pages but unnecessary read won't be
harmful.
If the VMO still exists and could possibly be used in the future (even if it isn't cloned now),
all page requests should be fulfilled to the extent possible to avoid accumulating failed state
in the kernel (See OnNoPagedVmoClones() for more).
void VmoDirty (uint64_t offset, uint64_t length)
Called by the paging system in response to a kernel request to transit page state.
- On success, calls vfs()->DirtyPages() with the requested data range.
- On failure, calls vfs()->ReportPagerError() with the error information.
The success or failure cases can happen synchronously. Failure to report success or failure
will hang the requesting process.
Note that offset + length will be page-aligned so can extend beyond the end of the file.
Race conditions
---------------
The consideration of race condition with OnNoPagedVmoClones() is the same as VmoRead().
Theoretically, VmoDirty() requests can be handled with freed VMO. This unnecessarily changes
the page state from clean to dirty. In this case, there is no problem with data integrity
because the data on the dirty page has not been changed.
|mutex_| lock should be held inside VmoDirty() to avoid race condition with
CreatePagedNodeVmo().
Defined at line 30 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
void fbl_recycle ()
Required for memory management, see the class comment above Vnode for more.
Defined at line 51 of file ../../src/storage/lib/vfs/cpp/paged_vnode.h
void WillDestroyVfs ()
Called when the VFS associated with this node is shutting down. The associated VFS will still
be valid at the time of the call.
Defined at line 157 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
void TearDown ()
This is called by PagedVfs to tear down the node.
Defined at line 162 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
Protected Methods
void PagedVnode (PagedVfs & vfs)
Defined at line 28 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
zx::result<> EnsureCreatePagedVmo (uint64_t size, uint32_t options)
Populates the paged_vmo() if necessary. Does nothing if it already exists. Access the created
vmo with this class' paged_vmo() getter. This will register with the PagedVfs and will start
serving kernel page requests.
When a mapping is requested, the derived class should call this function, create a
clone of the paged_vmo_ with the desired flags, and then call DidCloneVmo().
Defined at line 34 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
void DidClonePagedVmo ()
Call after successfully creating a paged_vmo() clone. This will ensure that the tracking
information for clones is set up:
- The has_clones_reference_ keeps this object alive as long as there are clones.
- The clone_watcher_ will notice when there are no clones, send notifications, and clean up
the has_clones_reference_.
Defined at line 51 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
fbl::RefPtr<Vnode> FreePagedVmo ()
Releases the vmo_ and unregisters for paging notifications from the PagedVfs. This will
detach the VMO from the pager and unregister from paging notifications.
If there are any clones of the vmo alive, all future paging requests on those vmo clones will
fail.
This function returns any reference held on behalf of the pager that is keeping this class
alive. The caller should ensure that this reference (if non-null) is safely released outside of
the Vnode's mutex_.
TODO(https://fxbug.dev/42128267) make the return value a PagedVnode. Using the base class here
allows the blobfs conversion to the new pager easier.
Defined at line 64 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
void OnNoPagedVmoClones ()
Implementors of this class can override this function to response to the event that there
are no more clones of the vmo_. The default implementation calls FreePagedVmo().
Some implementations may want to cache the vmo object and therefore avoid calling
FreePagedVmo().
Note that it is important to continue serving page requests for as long as the VMO could
re-used. If a race causes a page request to be delivered after the "no clones" message, failing
or dropping the request will accumulate that state in the kernel for the VMO which can affect
future clones of the VMO.
Defined at line 86 of file ../../src/storage/lib/vfs/cpp/paged_vnode.cc
std::optional<std::reference_wrapper<PagedVfs>> vfs ()
has_value iff the vfs hasn't been shut down.
Defined at line 118 of file ../../src/storage/lib/vfs/cpp/paged_vnode.h
const zx::vmo & paged_vmo ()
Returns the vmo associated with the paging system, if any. This will be a null handle if there
is no paged vmo associated with this vnode.
Populate with EnsureCreatePagedVmo(), free with FreeVmo().
This vmo must not be mapped and then written to. Doing so will cause the kernel to "page in"
the vmo which will reenter the filesystem to populate it, which is not what you want when
writing to it.
It is theoretically possible to read from this vmo (either mapped or using zx::vmo::read()) but
the caller must be VERY careful and it is strongly recommended that you avoid this. Reading
will cause the data to be paged in which will reenter the PagedVnode. Therefore, the mutex_
must NOT be held during the read process. The caller's memory management structure must then
guarantee that everything remain valid across this unlocked period (the vnode could be closed
on another thread) or it must be able to handle the ensuing race conditions.
Defined at line 137 of file ../../src/storage/lib/vfs/cpp/paged_vnode.h
bool has_clones ()
Returns true if there are clones of the VMO alive that have been given out.
Defined at line 140 of file ../../src/storage/lib/vfs/cpp/paged_vnode.h
Friends
class RefPtr