Skip to content

Commit 575afec

Browse files
committed
samples: puzzlefs: add basic deserializing support for the puzzlefs metadata
Puzzlefs uses capnproto for storing the filesystem metadata, defined in manifest.capnp and metadata.capnp. The files manifest_capnp.rs and metadata_capnp.rs were generated with (Cap'n Proto version 0.10.4): ``` capnp compile -orust manifest.capnp capnp compile -orust metadata.capnp ``` , formatted with rustfmt and I have also added the following lines: ``` ``` to avoid warnings. Ideally, manifest_capnp.rs and metadata_capnp.rs should be automatically generated at build time. However, this means the capnp binary becomes a dependency for the build and I didn't want this. Besides, the metadata schemas are not expected to change frequently, so it's acceptable to manually regenerate the two rust files when this happens. The code is adapted from the puzzlefs FUSE driver [1]. The data structures required for the filesystem metadata are defined in types.rs. Each structure has a `from_capnp` method used to convert between the capnp memory layout and the native Rust structures. This leaves room for improvement [2]. The deserializing code also uses `NoAllocBufferSegments` which is not yet merged in capnproto-rust upstream [3]. When a new release is published, then we'll be able to use capnproto-rust in the kernel with only a few patches to it. inode.rs implements the PuzzleFS structure which contains a list of metadata layers. Link: https://github.com/project-machine/puzzlefs [1] Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [2] Link: capnproto/capnproto-rust#423 [3] Signed-off-by: Ariel Miculas <[email protected]>
1 parent 41a2dbe commit 575afec

File tree

10 files changed

+5806
-1
lines changed

10 files changed

+5806
-1
lines changed

rust/kernel/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl Error {
9999
///
100100
/// It is a bug to pass an out-of-range `errno`. `EINVAL` would
101101
/// be returned in such a case.
102-
pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error {
102+
pub fn from_errno(errno: core::ffi::c_int) -> Error {
103103
if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
104104
// TODO: Make it a `WARN_ONCE` once available.
105105
crate::pr_warn!(

samples/rust/puzzle.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub(crate) mod error;
2+
pub(crate) mod types;
3+
pub(crate) use types::{manifest_capnp, metadata_capnp};
4+
pub(crate) mod inode;

samples/rust/puzzle/error.rs

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use alloc::collections::TryReserveError;
2+
use core::ffi::c_int;
3+
use core::fmt::{self, Display};
4+
use kernel::prelude::EINVAL;
5+
6+
pub(crate) enum WireFormatError {
7+
InvalidSerializedData,
8+
KernelError(kernel::error::Error),
9+
TryReserveError(TryReserveError),
10+
CapnpError(capnp::Error),
11+
FromIntError(core::num::TryFromIntError),
12+
FromSliceError(core::array::TryFromSliceError),
13+
HexError(hex::FromHexError),
14+
}
15+
16+
impl WireFormatError {
17+
pub(crate) fn to_errno(&self) -> c_int {
18+
match self {
19+
WireFormatError::InvalidSerializedData => kernel::error::Error::to_errno(EINVAL),
20+
WireFormatError::KernelError(e) => kernel::error::Error::to_errno(*e),
21+
WireFormatError::TryReserveError(_) => kernel::error::Error::to_errno(EINVAL),
22+
WireFormatError::CapnpError(_) => kernel::error::Error::to_errno(EINVAL),
23+
WireFormatError::FromIntError(_) => kernel::error::Error::to_errno(EINVAL),
24+
WireFormatError::FromSliceError(_) => kernel::error::Error::to_errno(EINVAL),
25+
WireFormatError::HexError(_) => kernel::error::Error::to_errno(EINVAL),
26+
}
27+
}
28+
29+
pub(crate) fn from_errno(errno: kernel::error::Error) -> Self {
30+
Self::KernelError(errno)
31+
}
32+
}
33+
34+
impl Display for WireFormatError {
35+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36+
match self {
37+
WireFormatError::InvalidSerializedData => f.write_str("invalid serialized data"),
38+
WireFormatError::KernelError(e) => {
39+
f.write_fmt(format_args!("Kernel error {}", e.to_errno()))
40+
}
41+
WireFormatError::TryReserveError(_) => f.write_str("TryReserveError"),
42+
WireFormatError::CapnpError(_) => f.write_str("Capnp error"),
43+
WireFormatError::FromIntError(_) => f.write_str("TryFromIntError"),
44+
WireFormatError::FromSliceError(_) => f.write_str("TryFromSliceError"),
45+
WireFormatError::HexError(_) => f.write_str("HexError"),
46+
}
47+
}
48+
}
49+
50+
pub(crate) type Result<T> = kernel::error::Result<T, WireFormatError>;
51+
52+
// TODO figure out how to use thiserror
53+
#[allow(unused_qualifications)]
54+
impl core::convert::From<kernel::error::Error> for WireFormatError {
55+
#[allow(deprecated)]
56+
fn from(source: kernel::error::Error) -> Self {
57+
WireFormatError::KernelError(source)
58+
}
59+
}
60+
61+
#[allow(unused_qualifications)]
62+
impl core::convert::From<TryReserveError> for WireFormatError {
63+
#[allow(deprecated)]
64+
fn from(source: TryReserveError) -> Self {
65+
WireFormatError::TryReserveError(source)
66+
}
67+
}
68+
69+
#[allow(unused_qualifications)]
70+
impl core::convert::From<capnp::Error> for WireFormatError {
71+
#[allow(deprecated)]
72+
fn from(source: capnp::Error) -> Self {
73+
WireFormatError::CapnpError(source)
74+
}
75+
}
76+
77+
#[allow(unused_qualifications)]
78+
impl core::convert::From<core::array::TryFromSliceError> for WireFormatError {
79+
#[allow(deprecated)]
80+
fn from(source: core::array::TryFromSliceError) -> Self {
81+
WireFormatError::FromSliceError(source)
82+
}
83+
}
84+
85+
#[allow(unused_qualifications)]
86+
impl core::convert::From<core::num::TryFromIntError> for WireFormatError {
87+
#[allow(deprecated)]
88+
fn from(source: core::num::TryFromIntError) -> Self {
89+
WireFormatError::FromIntError(source)
90+
}
91+
}
92+
93+
impl core::convert::From<hex::FromHexError> for WireFormatError {
94+
#[allow(deprecated)]
95+
fn from(source: hex::FromHexError) -> Self {
96+
WireFormatError::HexError(source)
97+
}
98+
}
99+
100+
#[allow(unused_qualifications)]
101+
impl core::convert::From<WireFormatError> for kernel::error::Error {
102+
#[allow(deprecated)]
103+
fn from(source: WireFormatError) -> Self {
104+
kernel::error::Error::from_errno(source.to_errno())
105+
}
106+
}

samples/rust/puzzle/inode.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// This contents of this file is taken from puzzlefs.rs (the userspace implementation)
2+
// It is named inode.rs instead puzzlefs.rs since the root of this kernel module already has that name
3+
4+
use crate::puzzle::error::Result;
5+
use crate::puzzle::error::WireFormatError;
6+
use crate::puzzle::types as format;
7+
use crate::puzzle::types::{Inode, InodeMode, MetadataBlob};
8+
use alloc::vec::Vec;
9+
use kernel::prelude::ENOENT;
10+
11+
pub(crate) struct PuzzleFS {
12+
layers: Vec<format::MetadataBlob>,
13+
}
14+
15+
impl PuzzleFS {
16+
pub(crate) fn new(md: MetadataBlob) -> Result<Self> {
17+
let mut v = Vec::new();
18+
v.try_push(md)?;
19+
Ok(PuzzleFS { layers: v })
20+
}
21+
22+
pub(crate) fn find_inode(&self, ino: u64) -> Result<Inode> {
23+
for layer in self.layers.iter() {
24+
if let Some(inode) = layer.find_inode(ino)? {
25+
let inode = Inode::from_capnp(inode)?;
26+
if let InodeMode::Wht = inode.mode {
27+
// TODO: seems like this should really be an Option.
28+
return Err(WireFormatError::from_errno(ENOENT));
29+
}
30+
return Ok(inode);
31+
}
32+
}
33+
34+
Err(WireFormatError::from_errno(ENOENT))
35+
}
36+
}

0 commit comments

Comments
 (0)