Skip to content

Add 9p fs to LiteBox#663

Open
CvvT wants to merge 16 commits intomainfrom
weiteng/nine_p
Open

Add 9p fs to LiteBox#663
CvvT wants to merge 16 commits intomainfrom
weiteng/nine_p

Conversation

@CvvT
Copy link
Contributor

@CvvT CvvT commented Feb 11, 2026

This PR adds implementation of 9p fs that uses 9P2000.L protocol. For testing, I used diod as the remote server. The implementation of 9p client was largely migrated from VSBox.

Note that different from other fs, this only support blocking operations as it relies on network. Not sure if it breaks any assumption that LiteBox has.

Currently it only allows issuing one call over network at a time and waiting for it to complete. We should allow concurrent requests. I will fix it in the next PR.

@github-actions
Copy link

🤖 SemverChecks 🤖 ⚠️ Potential breaking API changes detected ⚠️

Click for details
--- failure enum_variant_added: enum variant added on exhaustive enum ---

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_variant_added.ron

Failed in:
  variant MigrationError:Io in /home/runner/work/litebox/litebox/litebox/src/fs/layered.rs:427
  variant TruncateError:Io in /home/runner/work/litebox/litebox/litebox/src/fs/errors.rs:95

--- failure method_parameter_count_changed: pub method parameter count changed ---

Description:
A publicly-visible method now takes a different number of parameters, not counting the receiver (self) parameter.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/method_parameter_count_changed.ron

Failed in:
  litebox::fs::nine_p::FileSystem::new now takes 5 parameters instead of 1, in /home/runner/work/litebox/litebox/litebox/src/fs/nine_p/mod.rs:313

--- failure trait_requires_more_generic_type_params: trait now requires more generic type parameters ---

Description:
A trait now requires more generic type parameters than it used to. Uses of this trait that supplied the previously-required number of generic types will be broken. To fix this, consider supplying default values for newly-added generic types.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-parameter-no-default
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/trait_requires_more_generic_type_params.ron

Failed in:
  trait FileSystem (1 -> 2 required generic types) in /home/runner/work/litebox/litebox/litebox/src/fs/nine_p/mod.rs:277

--- failure type_requires_more_generic_type_params: type now requires more generic type parameters ---

Description:
A type now requires more generic type parameters than it used to. Uses of this type that supplied the previously-required number of generic types will be broken. To fix this, consider supplying default values for newly-added generic types.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-parameter-no-default
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/type_requires_more_generic_type_params.ron

Failed in:
  Struct FileSystem (1 -> 2 required generic types) in /home/runner/work/litebox/litebox/litebox/src/fs/nine_p/mod.rs:277

@CvvT CvvT marked this pull request as ready for review February 11, 2026 22:23
Copy link
Member

@wdcui wdcui left a comment

Choose a reason for hiding this comment

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

I went through the code and left some comments. Thank you for adding 9p support in LiteBox!

match self.lower.file_status(path) {
Ok(stat) => Ok(stat.file_type),
Err(FileStatusError::ClosedFd) => unreachable!(),
Err(FileStatusError::Io) => Err(PathError::NoSuchFileOrDirectory),
Copy link
Member

Choose a reason for hiding this comment

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

Io is a pretty general erorr name. Why would it imply NoSuchFileOrDirectory?

#[error("error when truncating: {0}")]
TruncateError(#[from] TruncateError),
#[error("I/O error")]
Io,
Copy link
Member

Choose a reason for hiding this comment

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

Should we interpret Io error as network failure instead of the file or directory not exist?

}
}

/// Walk to the parent of a path and return the parent fid and the name
Copy link
Member

Choose a reason for hiding this comment

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

Nit: "the name of the child"?

super::FileStatus {
file_type,
mode: super::Mode::from_bits_truncate(attr.stat.mode),
size: usize::try_from(attr.stat.size).expect("file size exceeds usize"),
Copy link
Member

Choose a reason for hiding this comment

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

expect() will cause litebox to crash, right? Should we avoid that?


let bytes_read = self.client.read(fid, read_offset as u64, buf)?;

// Update offset if not using explicit offset
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we always update the offset stored in the descriptor table?

/// Tagged 9P message
#[derive(Clone, Debug)]
pub(super) struct TaggedFcall<'a> {
pub(super) tag: u16,
Copy link
Member

Choose a reason for hiding this comment

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

What is the tag for?

encode_fcall(buf, tag, fcall)?;

// Write the size at the beginning
let size = u32::try_from(buf.len()).expect("buffer length exceeds u32");
Copy link
Member

Choose a reason for hiding this comment

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

Should we return the error instead of panic?

}

// ============================================================================
// Encoding functions
Copy link
Member

Choose a reason for hiding this comment

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

Can we simplify the encoding/decoding to serde of structs?

//! 9P transport layer abstraction
//!
//! This module defines traits for reading and writing 9P protocol messages over
//! an underlying transport (e.g., TCP socket, virtio-9p, etc.).
Copy link
Member

Choose a reason for hiding this comment

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

Where is the network integration?

// ---------------------------------------------------------------------------

/// A wrapper around `TcpStream` that implements the litebox 9P transport traits.
struct TcpTransport {
Copy link
Member

Choose a reason for hiding this comment

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

Why do we have both implementations and tests in this file?

Comment on lines +10 to +16
//!
//! # Submodules
//!
//! The 9P implementation is split into several submodules:
//! - `fcall` - Protocol message definitions and encoding/decoding
//! - `transport` - Transport layer traits and message I/O
//! - `client` - High-level 9P client for protocol operations
Copy link
Member

Choose a reason for hiding this comment

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

Minor comment (I have not reviewed the code, just was looking through the docs): we might wish to skip this from the doc-strings and change it to a regular comment. Anything in the doc-strings (here, module-level) effectively behaves like a spec. The details most of these submodules (which are not necessarily public) is not useful/needed to callers of this module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants