Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion litebox/src/fs/inode_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,15 @@ impl InodeAllocator {
pub fn next(&self) -> NodeInfo {
let ino = self.counter.fetch_add(1, Ordering::Relaxed);
NodeInfo {
dev: self.device_id.try_into().unwrap(),
dev: self.device_id(),
ino: ino.try_into().unwrap(),
rdev: None,
}
}

/// The device id this allocator hands out.
#[must_use]
pub fn device_id(&self) -> usize {
self.device_id.try_into().unwrap()
}
}
46 changes: 36 additions & 10 deletions litebox/src/fs/nine_p/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ impl<Platform: RawSyncPrimitivesProvider> Drop for FidInner<Platform> {
}
}

/// The outcome of a [`Client::walk`].
pub(super) struct WalkResult<Platform: RawSyncPrimitivesProvider> {
/// The qids of the components that were walked, in order.
pub(super) wqids: Vec<fcall::Qid>,
/// The fid for the final location.
///
/// `Some` iff `wqids.len() == wnames.len()`: per 9P2000.L, a short walk does not establish a
/// new fid, so a partial walk yields qids but nothing to address them with.
pub(super) fid: Option<Fid<Platform>>,
}

impl<Platform: RawSyncPrimitivesProvider> WalkResult<Platform> {
/// The fid for a walk that reached the requested path, treating a short walk as `ENOENT`.
pub(super) fn into_complete_fid(self) -> Result<Fid<Platform>, Error> {
self.fid.ok_or(Error::Remote(super::ENOENT))
}
}

/// 9P client state for writing to the connection
struct ClientWriteState<T> {
/// The underlying transport
Expand Down Expand Up @@ -307,14 +325,19 @@ impl<Platform: RawSyncPrimitivesProvider, T: Read + Write> Client<Platform, T> {

/// Walks the path from the given fid, handling paths longer than fcall::MAXWELEM by walking in chunks.
///
/// Returns the qids for each path component and a new fid for the final location on success.
/// Returns the qids for each walked path component, along with a new fid for the final
/// location if the whole path was walked.
fn walk_chunked(
&self,
fid: &Fid<Platform>,
wnames: &[FcallStr],
) -> Result<(Vec<fcall::Qid>, Fid<Platform>), Error> {
) -> Result<WalkResult<Platform>, Error> {
if wnames.is_empty() {
return self.walk_once(fid, wnames);
let (wqids, fid) = self.walk_once(fid, wnames)?;
return Ok(WalkResult {
wqids,
fid: Some(fid),
});
}
let mut wqids = Vec::with_capacity(fcall::MAXWELEM);
let mut prev: Option<Fid<Platform>> = None;
Expand All @@ -336,22 +359,26 @@ impl<Platform: RawSyncPrimitivesProvider, T: Read + Write> Client<Platform, T> {
}
// It means that the walk failed at the nwqid-th element
if new_len < chunk.len() {
// XXX: Per 9P2000.L the server does not establish `new_f` on a short walk, so not

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weiteng Chen (@CvvT) do you remember why we have a clunk here?

// sure why we have a clunk here; it does lead to a round-trip cost (and a
// swallowed `Rlerror`) on every short walk, so might be good to clean up?
self.clunk(new_f);
return Err(Error::Remote(super::ENOENT));
return Ok(WalkResult { wqids, fid: None });
}
prev = Some(new_f);
}
Ok((wqids, prev.unwrap()))
Ok(WalkResult {
wqids,
fid: Some(prev.unwrap()),
})
}

/// Walk to a path from a given fid.
///
/// Returns the qids for each path component and a new fid for the final location.
pub(super) fn walk<S: AsRef<[u8]>>(
&self,
fid: &Fid<Platform>,
wnames: &[S],
) -> Result<(Vec<fcall::Qid>, Fid<Platform>), Error> {
) -> Result<WalkResult<Platform>, Error> {
let wnames: Vec<fcall::FcallStr<'_>> = wnames
.iter()
.map(|s| fcall::FcallStr::Borrowed(s.as_ref()))
Expand Down Expand Up @@ -687,7 +714,6 @@ impl<Platform: RawSyncPrimitivesProvider, T: Read + Write> Client<Platform, T> {
/// Clone a fid (walk with empty path)
pub(super) fn clone_fid(&self, fid: &Fid<Platform>) -> Result<Fid<Platform>, Error> {
let empty: [&str; 0] = [];
let (_, new_fid) = self.walk(fid, &empty)?;
Ok(new_fid)
self.walk(fid, &empty)?.into_complete_fid()
}
}
Loading