Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a NVME FS prototype #192

Merged
merged 20 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ members = [
"src/bin/netmgr",
"src/bin/nettest",
"src/bin/pager",
"src/bin/mnemosyne",
"src/bin/stdfs_demo",
"src/kernel",
"src/lib/twizzler-queue-raw",
"src/lib/twizzler-queue",
Expand All @@ -23,7 +25,7 @@ members = [
"src/runtime/monitor",
"src/runtime/monitor-api",
"src/runtime/twz-rt",
"src/lib/twizzler-futures",
"src/lib/twizzler-futures",
]

exclude = ["toolchain/src/rust"]
Expand All @@ -37,6 +39,8 @@ initrd = [
"crate:netmgr",
"crate:nettest",
"crate:pager",
"crate:mnemosyne",
"crate:stdfs_demo",
#"lib:twz-rt",
#"lib:monitor",
#"third-party:hello-world-rs"
Expand Down
24 changes: 24 additions & 0 deletions src/bin/mnemosyne/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "mnemosyne"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
twizzler-abi = { path = "../../lib/twizzler-abi", features = ["runtime"] }
twizzler-net = { path = "../../lib/twizzler-net" }
twizzler-object = { path = "../../lib/twizzler-object" }
twizzler-queue = { path = "../../lib/twizzler-queue" }
twizzler-async = { path = "../../lib/twizzler-async" }
twizzler-driver = { path = "../../lib/twizzler-driver" }
nvme = { path = "../../lib/nvme-rs" }
lethe-gadget-fat = { path = "./fat" }
layout = { path = "./fat/layout" }
tickv = { version = "1.0.0" }
async-trait = "0.1.66"
volatile = "0.5"
pci-ids = "0.2.4"

[package.metadata]
twizzler-build = "static"
9 changes: 9 additions & 0 deletions src/bin/mnemosyne/fat/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "lethe-gadget-fat"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
layout = { path = "./layout" }
10 changes: 10 additions & 0 deletions src/bin/mnemosyne/fat/layout/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "layout"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
array-init = "2.0.1"
layout-derive = { path = "./layout-derive" }
12 changes: 12 additions & 0 deletions src/bin/mnemosyne/fat/layout/layout-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "layout-derive"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.46"
quote = "1.0.21"
syn = { version = "1.0.102", features = ["full"] }
239 changes: 239 additions & 0 deletions src/bin/mnemosyne/fat/layout/layout-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{parse_macro_input, Ident, ItemStruct, Type};

enum FieldLayout {
SubLayout,
Primitive,
}

impl FieldLayout {
fn gen_accessor(
&self,
offset_in_parent: &TokenStream2,
name: &Ident,
ty: &Type,
) -> TokenStream2 {
match self {
FieldLayout::SubLayout => {
let all_name = Ident::new(&format!("all_{name}"), name.span());
quote! {
pub fn #name (&mut self) -> Result<<#ty as ::layout::ApplyLayout<'_, R>>::Frame, R::Error> {
let offset_in_parent = #offset_in_parent;
<#ty as ::layout::ApplyLayout<'_, R>>::apply_layout(self.stream, self.offset + offset_in_parent)
}

pub fn #all_name (&mut self) -> Result<#ty, R::Error> {
let offset_in_parent = #offset_in_parent;
self.stream.seek(::layout::io::SeekFrom::Start(self.offset + offset_in_parent))?;
<#ty as ::layout::Decode>::decode(self.stream)
}
}
}
FieldLayout::Primitive => quote! {
pub fn #name (&mut self) -> Result<#ty, R::Error> {
let offset_in_parent = #offset_in_parent;
self.stream.seek(::layout::io::SeekFrom::Start(self.offset + offset_in_parent))?;
<#ty as ::layout::Decode>::decode(self.stream)
}
},
}
}

fn gen_setter(&self, offset_in_parent: &TokenStream2, name: &Ident, ty: &Type) -> TokenStream2 {
let setter_name = Ident::new(&format!("set_{name}"), name.span());
quote! {
pub fn #setter_name (&mut self, data: &#ty) -> Result<(), W::Error> {
let offset_in_parent = #offset_in_parent;
self.stream.seek(::layout::io::SeekFrom::Start(self.offset + offset_in_parent))?;
<#ty as ::layout::Encode>::encode(data, self.stream)
}
}
}
}

enum Size {
Dynamic,
Fixed,
}

impl Size {
fn gen_field_size(&self, name: &Ident, ty: &Type) -> [TokenStream2; 3] {
match self {
Size::Dynamic => [
quote!(::layout::FramedDynamic::framed_size(&mut self.#name()?)?),
quote!(::layout::SourcedDynamic::sourced_size(&#name)),
quote!(::layout::SourcedDynamic::sourced_size(&self.#name)),
],
Size::Fixed => {
let s = quote!(<#ty as ::layout::Fixed>::size());
[s.clone(), s.clone(), s]
}
}
}

fn gen_impl_wrapper(
&self,
framed: TokenStream2,
sourced: TokenStream2,
name: &Ident,
frame_name: &Ident,
) -> TokenStream2 {
match self {
Size::Dynamic => quote! {
impl<'a, S> ::layout::FramedDynamic<S> for #frame_name<'a, S>
where
S: ::layout::Read + ::layout::Seek + ::layout::IO
{
fn framed_size(&mut self) -> Result<u64, S::Error> {
Ok(#framed)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

There is a lot of extra white space throuhout. Can we tighten this up? Perhaps @dbittman has thoughts on how the code looks as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

One thing we need to do is setup a CI step that ensures that rustfmt is happy. @CPTforever is this code formatted with rustfmt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty sure I did, I ran cargo fmt in the crate's root but I'll double check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok today I found out it's not recursive, I'll commit the fix soon,

}

impl ::layout::SourcedDynamic for #name {
fn sourced_size(&self) -> u64 {
#sourced
}
}
},
Size::Fixed => quote! {
impl ::layout::Fixed for #name {
fn size() -> u64 {
#framed
}
}
},
}
}
}

#[proc_macro_attribute]
pub fn layout(_: TokenStream, item: TokenStream) -> TokenStream {
let mut tokens = parse_macro_input!(item as ItemStruct);

let vis = &tokens.vis;
let source_name = &tokens.ident;
let frame_name = Ident::new(&format!("{}Frame", tokens.ident), tokens.ident.span());

let mut accessor_impls = TokenStream2::new();
let mut setter_impls = TokenStream2::new();

let mut encode_impl = TokenStream2::new();
let mut decode_impl_assigns = TokenStream2::new();
let mut decode_impl_struct_init = TokenStream2::new();

let mut total_framed_offset: TokenStream2 = quote!(0);
let mut total_sourced_offset: TokenStream2 = quote!(0);
let mut total_selfed_offset: TokenStream2 = quote!(0);

let mut size = Size::Fixed;

'outer: for field in &mut tokens.fields {
let mut field_layout = FieldLayout::Primitive;
let mut field_size = Size::Fixed;

for attr in field.attrs.drain(..) {
let p = attr.path;
match quote!(#p).to_string().as_str() {
"sublayout" => field_layout = FieldLayout::SubLayout,
"dynamic" => {
field_size = Size::Dynamic;
size = Size::Dynamic;
field_layout = FieldLayout::SubLayout;
}
"ignore" => continue 'outer,
_ => continue,
}
}

let field_name = field.ident.as_ref().unwrap();
let field_ty = &field.ty;

let accessor = field_layout.gen_accessor(&total_framed_offset, field_name, field_ty);
accessor_impls = quote!(#accessor_impls #accessor);

let setter = field_layout.gen_setter(&total_framed_offset, field_name, field_ty);
setter_impls = quote!(#setter_impls #setter);

encode_impl = quote!(#encode_impl self.#field_name.encode(writer)?;);

decode_impl_assigns = quote!(#decode_impl_assigns let #field_name = <#field_ty>::decode(reader)?;);
decode_impl_struct_init = quote!(#decode_impl_struct_init #field_name,);

let [framed, sourced, selfed] = field_size.gen_field_size(field_name, field_ty);
total_framed_offset = quote!(#total_framed_offset + #framed);
total_sourced_offset = quote!(#total_sourced_offset + #sourced);
total_selfed_offset = quote!(#total_selfed_offset + #selfed);
}

let size_impl = size.gen_impl_wrapper(
total_framed_offset,
total_selfed_offset,
source_name,
&frame_name,
);

// todo: already existent generics
let out = quote! {
#tokens

impl<'a, R: 'a + ::layout::IO> ::layout::ApplyLayout<'a, R> for #source_name {
type Frame = #frame_name<'a, R>;

fn apply_layout(stream: &'a mut R, offset: u64) -> Result<Self::Frame, R::Error> {
Ok(#frame_name {
stream,
offset
})
}
}

impl ::layout::Encode for #source_name {
fn encode<S: ::layout::Write + ::layout::Seek + ::layout::IO>(&self, writer: &mut S) -> Result<(), S::Error> {
#encode_impl
Ok(())
}
}

impl ::layout::Decode for #source_name {
fn decode<S: ::layout::Read + ::layout::Seek + ::layout::IO>(reader: &mut S) -> Result<Self, S::Error> {
#decode_impl_assigns

Ok(Self {
#decode_impl_struct_init
})
}
}

#vis struct #frame_name<'a, R> {
stream: &'a mut R,
offset: u64
}

#size_impl

impl<'a, R> ::layout::Frame<R> for #frame_name<'a, R> {
fn stream(&mut self) -> &mut R {
self.stream
}

fn offset(&self) -> u64 {
self.offset
}
}

impl<'a, R: ::layout::Read + ::layout::Seek + ::layout::IO> #frame_name<'a, R> {
#accessor_impls
}

impl<'a, W: ::layout::Write + ::layout::Read + ::layout::Seek + ::layout::IO> #frame_name<'a, W> {
#setter_impls
}
};

// println!("{out}");

out.into()
}
Loading