Skip to content

vfs abstractions and tarfs #1037

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

Draft
wants to merge 29 commits into
base: rust-next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a3fe8d8
xattr: make the xattr array itself const
wedsonaf Sep 29, 2023
484ec70
rust: introduce `InPlaceModule`
wedsonaf Sep 29, 2023
da1a2b6
samples: rust: add in-place initialisation sample
wedsonaf Sep 29, 2023
883e433
rust: add the `container_of` macro
wedsonaf Sep 29, 2023
14513c0
rust: init: introduce `Opaque::try_ffi_init`
wedsonaf Sep 29, 2023
c7d0fb2
rust: time: introduce `time` module
wedsonaf Sep 29, 2023
ca4a93c
rust: types: add little-endian type
wedsonaf Sep 29, 2023
a44bdcc
rust: types: introduce `FromBytes` trait
wedsonaf Sep 29, 2023
caf9b29
rust: mem_cache: introduce `MemCache`
wedsonaf Sep 29, 2023
b0bc357
kbuild: rust: allow modules to allocate memory
wedsonaf Sep 29, 2023
528babd
rust: fs: add registration/unregistration of file systems
wedsonaf Sep 29, 2023
e909f43
rust: fs: introduce the `module_fs` macro
wedsonaf Sep 29, 2023
ad07f4b
samples: rust: add initial ro file system sample
wedsonaf Sep 29, 2023
626056a
rust: fs: introduce `FileSystem::super_params`
wedsonaf Sep 29, 2023
a448dc5
rust: fs: introduce `INode<T>`
wedsonaf Sep 29, 2023
b26f77a
rust: fs: introduce `FileSystem::init_root`
wedsonaf Sep 29, 2023
ac0f637
rust: fs: introduce `FileSystem::read_dir`
wedsonaf Sep 29, 2023
14b32d0
rust: fs: introduce `FileSystem::lookup`
wedsonaf Sep 29, 2023
5e601b9
rust: folio: introduce basic support for folios
wedsonaf Sep 29, 2023
c02d2b9
rust: fs: introduce `FileSystem::read_folio`
wedsonaf Sep 29, 2023
ce0acb6
rust: fs: introduce `FileSystem::read_xattr`
wedsonaf Sep 29, 2023
3f94966
rust: fs: introduce `FileSystem::statfs`
wedsonaf Sep 29, 2023
6032d93
rust: fs: introduce more inode types
wedsonaf Sep 29, 2023
1cf6e5e
rust: fs: add per-superblock data
wedsonaf Sep 29, 2023
516d0e4
rust: fs: add basic support for fs buffer heads
wedsonaf Sep 29, 2023
0605dba
rust: fs: allow file systems backed by a block device
wedsonaf Sep 29, 2023
b40e37b
rust: fs: allow per-inode data
wedsonaf Sep 29, 2023
80fda66
rust: fs: export file type from mode constants
wedsonaf Sep 29, 2023
7189177
tarfs: introduce tar fs
wedsonaf Sep 29, 2023
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
Prev Previous commit
Next Next commit
rust: fs: introduce FileSystem::read_folio
Allow Rust file systems to create regular file inodes backed by the page
cache. The contents of such files are read into folios via `read_folio`.

Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
  • Loading branch information
wedsonaf committed Oct 18, 2023
commit c02d2b9c336a987784deb39a75302c77842b1c4b
1 change: 0 additions & 1 deletion rust/kernel/folio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ impl LockedFolio<'_> {
/// Callers must ensure that the folio is valid and locked. Additionally, that the
/// responsibility of unlocking is transferred to the new instance of [`LockedFolio`]. Lastly,
/// that the returned [`LockedFolio`] doesn't outlive the refcount that keeps it alive.
#[allow(dead_code)]
pub(crate) unsafe fn from_raw(folio: *const bindings::folio) -> Self {
let ptr = folio.cast();
// SAFETY: The safety requirements ensure that `folio` (from which `ptr` is derived) is
Expand Down
75 changes: 73 additions & 2 deletions rust/kernel/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

use crate::error::{code::*, from_result, to_result, Error, Result};
use crate::types::{ARef, AlwaysRefCounted, Either, Opaque};
use crate::{bindings, init::PinInit, str::CStr, time::Timespec, try_pin_init, ThisModule};
use crate::{
bindings, folio::LockedFolio, init::PinInit, str::CStr, time::Timespec, try_pin_init,
ThisModule,
};
use core::{marker::PhantomData, marker::PhantomPinned, mem::ManuallyDrop, pin::Pin, ptr};
use macros::{pin_data, pinned_drop};

Expand Down Expand Up @@ -36,6 +39,9 @@ pub trait FileSystem {

/// Returns the inode corresponding to the directory entry with the given name.
fn lookup(parent: &INode<Self>, name: &[u8]) -> Result<ARef<INode<Self>>>;

/// Reads the contents of the inode into the given folio.
fn read_folio(inode: &INode<Self>, folio: LockedFolio<'_>) -> Result;
}

/// The types of directory entries reported by [`FileSystem::read_dir`].
Expand Down Expand Up @@ -74,6 +80,7 @@ impl From<INodeType> for DirEntryType {
fn from(value: INodeType) -> Self {
match value {
INodeType::Dir => DirEntryType::Dir,
INodeType::Reg => DirEntryType::Reg,
}
}
}
Expand Down Expand Up @@ -232,6 +239,15 @@ impl<T: FileSystem + ?Sized> NewINode<T> {
inode.i_op = &Tables::<T>::DIR_INODE_OPERATIONS;
bindings::S_IFDIR
}
INodeType::Reg => {
// SAFETY: `generic_ro_fops` never changes, it's safe to reference it.
inode.__bindgen_anon_3.i_fop = unsafe { &bindings::generic_ro_fops };
inode.i_data.a_ops = &Tables::<T>::FILE_ADDRESS_SPACE_OPERATIONS;

// SAFETY: The `i_mapping` pointer doesn't change and is valid.
unsafe { bindings::mapping_set_large_folios(inode.i_mapping) };
bindings::S_IFREG
}
};

inode.i_mode = (params.mode & 0o777) | u16::try_from(mode)?;
Expand Down Expand Up @@ -268,6 +284,9 @@ impl<T: FileSystem + ?Sized> Drop for NewINode<T> {
pub enum INodeType {
/// Directory type.
Dir,

/// Regular file type.
Reg,
}

/// Required inode parameters.
Expand Down Expand Up @@ -588,6 +607,55 @@ impl<T: FileSystem + ?Sized> Tables<T> {
},
}
}

const FILE_ADDRESS_SPACE_OPERATIONS: bindings::address_space_operations =
bindings::address_space_operations {
writepage: None,
read_folio: Some(Self::read_folio_callback),
writepages: None,
dirty_folio: None,
readahead: None,
write_begin: None,
write_end: None,
bmap: None,
invalidate_folio: None,
release_folio: None,
free_folio: None,
direct_IO: None,
migrate_folio: None,
launder_folio: None,
is_partially_uptodate: None,
is_dirty_writeback: None,
error_remove_page: None,
swap_activate: None,
swap_deactivate: None,
swap_rw: None,
};

extern "C" fn read_folio_callback(
_file: *mut bindings::file,
folio: *mut bindings::folio,
) -> i32 {
from_result(|| {
// SAFETY: All pointers are valid and stable.
let inode = unsafe {
&*(*(*folio)
.__bindgen_anon_1
.page
.__bindgen_anon_1
.__bindgen_anon_1
.mapping)
.host
.cast::<INode<T>>()
};

// SAFETY: The C contract guarantees that the folio is valid and locked, with ownership
// of the lock transferred to the callee (this function). The folio is also guaranteed
// not to outlive this function.
T::read_folio(inode, unsafe { LockedFolio::from_raw(folio) })?;
Ok(0)
})
}
}

/// Directory entry emitter.
Expand Down Expand Up @@ -673,7 +741,7 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
/// # mod module_fs_sample {
/// use kernel::fs::{DirEmitter, INode, NewSuperBlock, SuperBlock, SuperParams};
/// use kernel::prelude::*;
/// use kernel::{c_str, fs, types::ARef};
/// use kernel::{c_str, folio::LockedFolio, fs, types::ARef};
///
/// kernel::module_fs! {
/// type: MyFs,
Expand All @@ -698,6 +766,9 @@ impl<T: FileSystem + ?Sized + Sync + Send> crate::InPlaceModule for Module<T> {
/// fn lookup(_: &INode<Self>, _: &[u8]) -> Result<ARef<INode<Self>>> {
/// todo!()
/// }
/// fn read_folio(_: &INode<Self>, _: LockedFolio<'_>) -> Result {
/// todo!()
/// }
/// }
/// # }
/// ```
Expand Down
69 changes: 49 additions & 20 deletions samples/rust/rust_rofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use kernel::fs::{
DirEmitter, INode, INodeParams, INodeType, NewSuperBlock, SuperBlock, SuperParams,
};
use kernel::prelude::*;
use kernel::{c_str, fs, time::UNIX_EPOCH, types::ARef, types::Either};
use kernel::{c_str, folio::LockedFolio, fs, time::UNIX_EPOCH, types::ARef, types::Either};

kernel::module_fs! {
type: RoFs,
Expand All @@ -20,23 +20,27 @@ struct Entry {
name: &'static [u8],
ino: u64,
etype: INodeType,
contents: &'static [u8],
}

const ENTRIES: [Entry; 3] = [
Entry {
name: b".",
ino: 1,
etype: INodeType::Dir,
contents: b"",
},
Entry {
name: b"..",
ino: 1,
etype: INodeType::Dir,
contents: b"",
},
Entry {
name: b"subdir",
name: b"test.txt",
ino: 2,
etype: INodeType::Dir,
etype: INodeType::Reg,
contents: b"hello\n",
},
];

Expand Down Expand Up @@ -95,23 +99,48 @@ impl fs::FileSystem for RoFs {
return Err(ENOENT);
}

match name {
b"subdir" => match parent.super_block().get_or_create_inode(2)? {
Either::Left(existing) => Ok(existing),
Either::Right(new) => new.init(INodeParams {
typ: INodeType::Dir,
mode: 0o555,
size: 0,
blocks: 1,
nlink: 2,
uid: 0,
gid: 0,
atime: UNIX_EPOCH,
ctime: UNIX_EPOCH,
mtime: UNIX_EPOCH,
}),
},
_ => Err(ENOENT),
for e in &ENTRIES {
if name == e.name {
return match parent.super_block().get_or_create_inode(e.ino)? {
Either::Left(existing) => Ok(existing),
Either::Right(new) => new.init(INodeParams {
typ: e.etype,
mode: 0o444,
size: e.contents.len().try_into()?,
blocks: 1,
nlink: 1,
uid: 0,
gid: 0,
atime: UNIX_EPOCH,
ctime: UNIX_EPOCH,
mtime: UNIX_EPOCH,
}),
};
}
}

Err(ENOENT)
}

fn read_folio(inode: &INode<Self>, mut folio: LockedFolio<'_>) -> Result {
let data = match inode.ino() {
2 => ENTRIES[2].contents,
_ => return Err(EINVAL),
};

let pos = usize::try_from(folio.pos()).unwrap_or(usize::MAX);
let copied = if pos >= data.len() {
0
} else {
let to_copy = core::cmp::min(data.len() - pos, folio.size());
folio.write(0, &data[pos..][..to_copy])?;
to_copy
};

folio.zero_out(copied, folio.size() - copied)?;
folio.mark_uptodate();
folio.flush_dcache();

Ok(())
}
}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy