* [RFC PATCH 00/24] erofs: introduce Rust implementation
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
Greetings,
So here is a patchset to add Rust skeleton codes to the current EROFS
implementation. The implementation is deeply inspired by the current C
implementation, and it's based on a generic erofs_sys crate[1] written
by me. The purpose is to potentially replace some of C codes to make
to make full use of Rust's safety features and better
optimization guarantees.
Many of the features (like compression inodes) still
fall back to C implementation because of my limited time and lack of
Rust counterparts. However, the Extended Attributes work purely in Rust.
Some changes are done to the original C code.
1) Some of superblock operations are modified slightly to make sure
memory allocation and deallocation are done correctly when interacting
with Rust.
2) A new rust_helpers.c file is introduced to help Rust to deal with
self-included EROFS API without exporting types that are not
interpreted in Rust.
3) A new rust_bindings.h is introduced to provide Rust functions
externs with the same function signature as Rust side so that
C-side code can use the bindings easily.
4) CONFIG_EROFS_FS_RUST is added in dir.c, inode.c, super.c, data.c,
and xattr.c to allow C code to be opt out and uses Rust implementation.
5) Some macros and function signatures are tweaked in internal.h
with the compilation options.
Note that, since currently there is no mature Rust VFS implementation
landed upstream, this patchset only uses C bindings internally and
each unsafe operation is examined. This implementation only offers
C-ABI-compatible functions impls and gets its exposed to original C
implementation as either hooks or function pointers.
Also note that, this patchset only uses already-present self-included
EROFS API and it uses as few C bindings generated from bindgen as
possible, only inode, dentry, file and dir_context related are used,
to be precise.
Since the EROFS community is pretty interested in giving Rust a try,
I think this patchset will be a good start for Rust EROFS.
This patchset is based on the latest EROFS development tree.
And the current codebase can also be found on my github repo[2].
[1]: https://github.com/ToolmanP/erofs-rs
[2]: https://github.com/ToolmanP/erofs-rs-linux
Yiyang Wu (24):
erofs: lift up erofs_fill_inode to global
erofs: add superblock data structure in Rust
erofs: add Errno in Rust
erofs: add xattrs data structure in Rust
erofs: add inode data structure in Rust
erofs: add alloc_helper in Rust
erofs: add data abstraction in Rust
erofs: add device data structure in Rust
erofs: add continuous iterators in Rust
erofs: add device_infos implementation in Rust
erofs: add map data structure in Rust
erofs: add directory entry data structure in Rust
erofs: add runtime filesystem and inode in Rust
erofs: add block mapping capability in Rust
erofs: add iter methods in filesystem in Rust
erofs: implement dir and inode operations in Rust
erofs: introduce Rust SBI to C
erofs: introduce iget alternative to C
erofs: introduce namei alternative to C
erofs: introduce readdir alternative to C
erofs: introduce erofs_map_blocks alternative to C
erofs: add skippable iters in Rust
erofs: implement xattrs operations in Rust
erofs: introduce xattrs replacement to C
fs/erofs/Kconfig | 10 +
fs/erofs/Makefile | 4 +
fs/erofs/data.c | 5 +
fs/erofs/data_rs.rs | 63 +++
fs/erofs/dir.c | 2 +
fs/erofs/dir_rs.rs | 57 ++
fs/erofs/inode.c | 10 +-
fs/erofs/inode_rs.rs | 64 +++
fs/erofs/internal.h | 47 ++
fs/erofs/namei.c | 2 +
fs/erofs/namei_rs.rs | 56 ++
fs/erofs/rust/erofs_sys.rs | 47 ++
fs/erofs/rust/erofs_sys/alloc_helper.rs | 35 ++
fs/erofs/rust/erofs_sys/data.rs | 70 +++
fs/erofs/rust/erofs_sys/data/backends.rs | 4 +
.../erofs_sys/data/backends/uncompressed.rs | 39 ++
fs/erofs/rust/erofs_sys/data/raw_iters.rs | 127 +++++
.../rust/erofs_sys/data/raw_iters/ref_iter.rs | 131 +++++
.../rust/erofs_sys/data/raw_iters/traits.rs | 17 +
fs/erofs/rust/erofs_sys/devices.rs | 75 +++
fs/erofs/rust/erofs_sys/dir.rs | 98 ++++
fs/erofs/rust/erofs_sys/errnos.rs | 191 +++++++
fs/erofs/rust/erofs_sys/inode.rs | 398 ++++++++++++++
fs/erofs/rust/erofs_sys/map.rs | 99 ++++
fs/erofs/rust/erofs_sys/operations.rs | 62 +++
fs/erofs/rust/erofs_sys/superblock.rs | 514 ++++++++++++++++++
fs/erofs/rust/erofs_sys/superblock/mem.rs | 94 ++++
fs/erofs/rust/erofs_sys/xattrs.rs | 272 +++++++++
fs/erofs/rust/kinode.rs | 76 +++
fs/erofs/rust/ksources.rs | 66 +++
fs/erofs/rust/ksuperblock.rs | 30 +
fs/erofs/rust/mod.rs | 7 +
fs/erofs/rust_bindings.h | 39 ++
fs/erofs/rust_helpers.c | 86 +++
fs/erofs/rust_helpers.h | 23 +
fs/erofs/super.c | 51 +-
fs/erofs/super_rs.rs | 59 ++
fs/erofs/xattr.c | 31 +-
fs/erofs/xattr.h | 7 +
fs/erofs/xattr_rs.rs | 106 ++++
40 files changed, 3153 insertions(+), 21 deletions(-)
create mode 100644 fs/erofs/data_rs.rs
create mode 100644 fs/erofs/dir_rs.rs
create mode 100644 fs/erofs/inode_rs.rs
create mode 100644 fs/erofs/namei_rs.rs
create mode 100644 fs/erofs/rust/erofs_sys.rs
create mode 100644 fs/erofs/rust/erofs_sys/alloc_helper.rs
create mode 100644 fs/erofs/rust/erofs_sys/data.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
create mode 100644 fs/erofs/rust/erofs_sys/devices.rs
create mode 100644 fs/erofs/rust/erofs_sys/dir.rs
create mode 100644 fs/erofs/rust/erofs_sys/errnos.rs
create mode 100644 fs/erofs/rust/erofs_sys/inode.rs
create mode 100644 fs/erofs/rust/erofs_sys/map.rs
create mode 100644 fs/erofs/rust/erofs_sys/operations.rs
create mode 100644 fs/erofs/rust/erofs_sys/superblock.rs
create mode 100644 fs/erofs/rust/erofs_sys/superblock/mem.rs
create mode 100644 fs/erofs/rust/erofs_sys/xattrs.rs
create mode 100644 fs/erofs/rust/kinode.rs
create mode 100644 fs/erofs/rust/ksources.rs
create mode 100644 fs/erofs/rust/ksuperblock.rs
create mode 100644 fs/erofs/rust/mod.rs
create mode 100644 fs/erofs/rust_bindings.h
create mode 100644 fs/erofs/rust_helpers.c
create mode 100644 fs/erofs/rust_helpers.h
create mode 100644 fs/erofs/super_rs.rs
create mode 100644 fs/erofs/xattr_rs.rs
--
2.46.0
^ permalink raw reply [flat|nested] 26+ messages in thread
* [RFC PATCH 01/24] erofs: lift up erofs_fill_inode to global
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
Lift up erofs_fill_inode as a global symbol so that
rust_helpers can use it for better compatibility.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/inode.c | 2 +-
fs/erofs/internal.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index db29190656eb..d2fd51fcebd2 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -196,7 +196,7 @@ static int erofs_read_inode(struct inode *inode)
return err;
}
-static int erofs_fill_inode(struct inode *inode)
+int erofs_fill_inode(struct inode *inode)
{
struct erofs_inode *vi = EROFS_I(inode);
int err;
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 4efd578d7c62..8674a4cb9d39 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -416,6 +416,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map);
void erofs_onlinefolio_init(struct folio *folio);
void erofs_onlinefolio_split(struct folio *folio);
void erofs_onlinefolio_end(struct folio *folio, int err);
+int erofs_fill_inode(struct inode *inode);
struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid);
int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask,
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 01/24] erofs: lift up erofs_fill_inode to global
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
Lift up erofs_fill_inode as a global symbol so that
rust_helpers can use it for better compatibility.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/inode.c | 2 +-
fs/erofs/internal.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
index db29190656eb..d2fd51fcebd2 100644
--- a/fs/erofs/inode.c
+++ b/fs/erofs/inode.c
@@ -196,7 +196,7 @@ static int erofs_read_inode(struct inode *inode)
return err;
}
-static int erofs_fill_inode(struct inode *inode)
+int erofs_fill_inode(struct inode *inode)
{
struct erofs_inode *vi = EROFS_I(inode);
int err;
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 4efd578d7c62..8674a4cb9d39 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -416,6 +416,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map);
void erofs_onlinefolio_init(struct folio *folio);
void erofs_onlinefolio_split(struct folio *folio);
void erofs_onlinefolio_end(struct folio *folio, int err);
+int erofs_fill_inode(struct inode *inode);
struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid);
int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask,
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 02/24] erofs: add superblock data structure in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
This patch adds a compilable super_rs.rs and introduces superblock
data structure in Rust. Note that this patch leaves C-side code
untouched.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/Kconfig | 10 ++
fs/erofs/Makefile | 1 +
fs/erofs/rust/erofs_sys.rs | 22 +++++
fs/erofs/rust/erofs_sys/superblock.rs | 132 ++++++++++++++++++++++++++
fs/erofs/rust/mod.rs | 4 +
fs/erofs/super_rs.rs | 9 ++
6 files changed, 178 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys.rs
create mode 100644 fs/erofs/rust/erofs_sys/superblock.rs
create mode 100644 fs/erofs/rust/mod.rs
create mode 100644 fs/erofs/super_rs.rs
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 6ea60661fa55..e2883efbf497 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -178,3 +178,13 @@ config EROFS_FS_PCPU_KTHREAD_HIPRI
at higher priority.
If unsure, say N.
+
+config EROFS_FS_RUST
+ bool "EROFS use RUST Replacement (EXPERIMENTAL)"
+ depends on EROFS_FS && RUST
+ help
+ This permits EROFS to use EXPERIMENTAL Rust implementation
+ for EROFS. This should be considered as an experimental
+ feature for now.
+
+ If unsure, say N.
diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile
index 4331d53c7109..fb46a2c7fb50 100644
--- a/fs/erofs/Makefile
+++ b/fs/erofs/Makefile
@@ -9,3 +9,4 @@ erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o
erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o
+erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
new file mode 100644
index 000000000000..0f1400175fc2
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -0,0 +1,22 @@
+#![allow(dead_code)]
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+//! A pure Rust implementation of the EROFS filesystem.
+//! Technical Details are documented in the [EROFS Documentation](https://erofs.docs.kernel.org/en/latest/)
+
+// It's unavoidable to import alloc here. Since there are so many backends there and if we want to
+// to use trait object to export Filesystem pointer. The alloc crate here is necessary.
+
+#[cfg(not(CONFIG_EROFS_FS = "y"))]
+extern crate alloc;
+
+/// Erofs requires block index to a 32 bit unsigned integer.
+pub(crate) type Blk = u32;
+/// Erofs requires normal offset to be a 64bit unsigned integer.
+pub(crate) type Off = u64;
+/// Erofs requires inode nid to be a 64bit unsigned integer.
+pub(crate) type Nid = u64;
+/// Erofs Super Offset to read the ondisk superblock
+pub(crate) const EROFS_SUPER_OFFSET: Off = 1024;
+pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs
new file mode 100644
index 000000000000..213be6dbc553
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/superblock.rs
@@ -0,0 +1,132 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::*;
+use core::mem::size_of;
+
+/// The ondisk superblock structure.
+#[derive(Debug, Clone, Copy, Default)]
+#[repr(C)]
+pub(crate) struct SuperBlock {
+ pub(crate) magic: u32,
+ pub(crate) checksum: i32,
+ pub(crate) feature_compat: i32,
+ pub(crate) blkszbits: u8,
+ pub(crate) sb_extslots: u8,
+ pub(crate) root_nid: i16,
+ pub(crate) inos: i64,
+ pub(crate) build_time: i64,
+ pub(crate) build_time_nsec: i32,
+ pub(crate) blocks: i32,
+ pub(crate) meta_blkaddr: u32,
+ pub(crate) xattr_blkaddr: u32,
+ pub(crate) uuid: [u8; 16],
+ pub(crate) volume_name: [u8; 16],
+ pub(crate) feature_incompat: i32,
+ pub(crate) compression: i16,
+ pub(crate) extra_devices: i16,
+ pub(crate) devt_slotoff: i16,
+ pub(crate) dirblkbits: u8,
+ pub(crate) xattr_prefix_count: u8,
+ pub(crate) xattr_prefix_start: i32,
+ pub(crate) packed_nid: i64,
+ pub(crate) xattr_filter_reserved: u8,
+ pub(crate) reserved: [u8; 23],
+}
+
+impl TryFrom<&[u8]> for SuperBlock {
+ type Error = core::array::TryFromSliceError;
+ fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
+ value[0..128].try_into()
+ }
+}
+
+impl From<[u8; 128]> for SuperBlock {
+ fn from(value: [u8; 128]) -> Self {
+ Self {
+ magic: u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
+ checksum: i32::from_le_bytes([value[4], value[5], value[6], value[7]]),
+ feature_compat: i32::from_le_bytes([value[8], value[9], value[10], value[11]]),
+ blkszbits: value[12],
+ sb_extslots: value[13],
+ root_nid: i16::from_le_bytes([value[14], value[15]]),
+ inos: i64::from_le_bytes([
+ value[16], value[17], value[18], value[19], value[20], value[21], value[22],
+ value[23],
+ ]),
+ build_time: i64::from_le_bytes([
+ value[24], value[25], value[26], value[27], value[28], value[29], value[30],
+ value[31],
+ ]),
+ build_time_nsec: i32::from_le_bytes([value[32], value[33], value[34], value[35]]),
+ blocks: i32::from_le_bytes([value[36], value[37], value[38], value[39]]),
+ meta_blkaddr: u32::from_le_bytes([value[40], value[41], value[42], value[43]]),
+ xattr_blkaddr: u32::from_le_bytes([value[44], value[45], value[46], value[47]]),
+ uuid: value[48..64].try_into().unwrap(),
+ volume_name: value[64..80].try_into().unwrap(),
+ feature_incompat: i32::from_le_bytes([value[80], value[81], value[82], value[83]]),
+ compression: i16::from_le_bytes([value[84], value[85]]),
+ extra_devices: i16::from_le_bytes([value[86], value[87]]),
+ devt_slotoff: i16::from_le_bytes([value[88], value[89]]),
+ dirblkbits: value[90],
+ xattr_prefix_count: value[91],
+ xattr_prefix_start: i32::from_le_bytes([value[92], value[93], value[94], value[95]]),
+ packed_nid: i64::from_le_bytes([
+ value[96], value[97], value[98], value[99], value[100], value[101], value[102],
+ value[103],
+ ]),
+ xattr_filter_reserved: value[104],
+ reserved: value[105..128].try_into().unwrap(),
+ }
+ }
+}
+
+pub(crate) type SuperBlockBuf = [u8; size_of::<SuperBlock>()];
+pub(crate) const SUPERBLOCK_EMPTY_BUF: SuperBlockBuf = [0; size_of::<SuperBlock>()];
+
+/// Used for external address calculation.
+pub(crate) struct Accessor {
+ pub(crate) base: Off,
+ pub(crate) off: Off,
+ pub(crate) len: Off,
+ pub(crate) nr: Off,
+}
+
+impl Accessor {
+ pub(crate) fn new(address: Off, bits: Off) -> Self {
+ let sz = 1 << bits;
+ let mask = sz - 1;
+ Accessor {
+ base: (address >> bits) << bits,
+ off: address & mask,
+ len: sz - (address & mask),
+ nr: address >> bits,
+ }
+ }
+}
+
+impl SuperBlock {
+ pub(crate) fn blk_access(&self, address: Off) -> Accessor {
+ Accessor::new(address, self.blkszbits as Off)
+ }
+
+ pub(crate) fn blknr(&self, pos: Off) -> Blk {
+ (pos >> self.blkszbits) as Blk
+ }
+
+ pub(crate) fn blkpos(&self, blk: Blk) -> Off {
+ (blk as Off) << self.blkszbits
+ }
+
+ pub(crate) fn blksz(&self) -> Off {
+ 1 << self.blkszbits
+ }
+
+ pub(crate) fn blk_round_up(&self, addr: Off) -> Blk {
+ ((addr + self.blksz() - 1) >> self.blkszbits) as Blk
+ }
+
+ pub(crate) fn iloc(&self, nid: Nid) -> Off {
+ self.blkpos(self.meta_blkaddr) + ((nid as Off) << (5 as Off))
+ }
+}
diff --git a/fs/erofs/rust/mod.rs b/fs/erofs/rust/mod.rs
new file mode 100644
index 000000000000..e6c0731f2533
--- /dev/null
+++ b/fs/erofs/rust/mod.rs
@@ -0,0 +1,4 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod erofs_sys;
diff --git a/fs/erofs/super_rs.rs b/fs/erofs/super_rs.rs
new file mode 100644
index 000000000000..4b8cbef507e3
--- /dev/null
+++ b/fs/erofs/super_rs.rs
@@ -0,0 +1,9 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+//! EROFS Rust Kernel Module Helpers Implementation
+//! This is only for experimental purpose. Feedback is always welcome.
+
+#[allow(dead_code)]
+#[allow(missing_docs)]
+pub(crate) mod rust;
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 02/24] erofs: add superblock data structure in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
This patch adds a compilable super_rs.rs and introduces superblock
data structure in Rust. Note that this patch leaves C-side code
untouched.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/Kconfig | 10 ++
fs/erofs/Makefile | 1 +
fs/erofs/rust/erofs_sys.rs | 22 +++++
fs/erofs/rust/erofs_sys/superblock.rs | 132 ++++++++++++++++++++++++++
fs/erofs/rust/mod.rs | 4 +
fs/erofs/super_rs.rs | 9 ++
6 files changed, 178 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys.rs
create mode 100644 fs/erofs/rust/erofs_sys/superblock.rs
create mode 100644 fs/erofs/rust/mod.rs
create mode 100644 fs/erofs/super_rs.rs
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 6ea60661fa55..e2883efbf497 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -178,3 +178,13 @@ config EROFS_FS_PCPU_KTHREAD_HIPRI
at higher priority.
If unsure, say N.
+
+config EROFS_FS_RUST
+ bool "EROFS use RUST Replacement (EXPERIMENTAL)"
+ depends on EROFS_FS && RUST
+ help
+ This permits EROFS to use EXPERIMENTAL Rust implementation
+ for EROFS. This should be considered as an experimental
+ feature for now.
+
+ If unsure, say N.
diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile
index 4331d53c7109..fb46a2c7fb50 100644
--- a/fs/erofs/Makefile
+++ b/fs/erofs/Makefile
@@ -9,3 +9,4 @@ erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o
erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o
+erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
new file mode 100644
index 000000000000..0f1400175fc2
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -0,0 +1,22 @@
+#![allow(dead_code)]
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+//! A pure Rust implementation of the EROFS filesystem.
+//! Technical Details are documented in the [EROFS Documentation](https://erofs.docs.kernel.org/en/latest/)
+
+// It's unavoidable to import alloc here. Since there are so many backends there and if we want to
+// to use trait object to export Filesystem pointer. The alloc crate here is necessary.
+
+#[cfg(not(CONFIG_EROFS_FS = "y"))]
+extern crate alloc;
+
+/// Erofs requires block index to a 32 bit unsigned integer.
+pub(crate) type Blk = u32;
+/// Erofs requires normal offset to be a 64bit unsigned integer.
+pub(crate) type Off = u64;
+/// Erofs requires inode nid to be a 64bit unsigned integer.
+pub(crate) type Nid = u64;
+/// Erofs Super Offset to read the ondisk superblock
+pub(crate) const EROFS_SUPER_OFFSET: Off = 1024;
+pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs
new file mode 100644
index 000000000000..213be6dbc553
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/superblock.rs
@@ -0,0 +1,132 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::*;
+use core::mem::size_of;
+
+/// The ondisk superblock structure.
+#[derive(Debug, Clone, Copy, Default)]
+#[repr(C)]
+pub(crate) struct SuperBlock {
+ pub(crate) magic: u32,
+ pub(crate) checksum: i32,
+ pub(crate) feature_compat: i32,
+ pub(crate) blkszbits: u8,
+ pub(crate) sb_extslots: u8,
+ pub(crate) root_nid: i16,
+ pub(crate) inos: i64,
+ pub(crate) build_time: i64,
+ pub(crate) build_time_nsec: i32,
+ pub(crate) blocks: i32,
+ pub(crate) meta_blkaddr: u32,
+ pub(crate) xattr_blkaddr: u32,
+ pub(crate) uuid: [u8; 16],
+ pub(crate) volume_name: [u8; 16],
+ pub(crate) feature_incompat: i32,
+ pub(crate) compression: i16,
+ pub(crate) extra_devices: i16,
+ pub(crate) devt_slotoff: i16,
+ pub(crate) dirblkbits: u8,
+ pub(crate) xattr_prefix_count: u8,
+ pub(crate) xattr_prefix_start: i32,
+ pub(crate) packed_nid: i64,
+ pub(crate) xattr_filter_reserved: u8,
+ pub(crate) reserved: [u8; 23],
+}
+
+impl TryFrom<&[u8]> for SuperBlock {
+ type Error = core::array::TryFromSliceError;
+ fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
+ value[0..128].try_into()
+ }
+}
+
+impl From<[u8; 128]> for SuperBlock {
+ fn from(value: [u8; 128]) -> Self {
+ Self {
+ magic: u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
+ checksum: i32::from_le_bytes([value[4], value[5], value[6], value[7]]),
+ feature_compat: i32::from_le_bytes([value[8], value[9], value[10], value[11]]),
+ blkszbits: value[12],
+ sb_extslots: value[13],
+ root_nid: i16::from_le_bytes([value[14], value[15]]),
+ inos: i64::from_le_bytes([
+ value[16], value[17], value[18], value[19], value[20], value[21], value[22],
+ value[23],
+ ]),
+ build_time: i64::from_le_bytes([
+ value[24], value[25], value[26], value[27], value[28], value[29], value[30],
+ value[31],
+ ]),
+ build_time_nsec: i32::from_le_bytes([value[32], value[33], value[34], value[35]]),
+ blocks: i32::from_le_bytes([value[36], value[37], value[38], value[39]]),
+ meta_blkaddr: u32::from_le_bytes([value[40], value[41], value[42], value[43]]),
+ xattr_blkaddr: u32::from_le_bytes([value[44], value[45], value[46], value[47]]),
+ uuid: value[48..64].try_into().unwrap(),
+ volume_name: value[64..80].try_into().unwrap(),
+ feature_incompat: i32::from_le_bytes([value[80], value[81], value[82], value[83]]),
+ compression: i16::from_le_bytes([value[84], value[85]]),
+ extra_devices: i16::from_le_bytes([value[86], value[87]]),
+ devt_slotoff: i16::from_le_bytes([value[88], value[89]]),
+ dirblkbits: value[90],
+ xattr_prefix_count: value[91],
+ xattr_prefix_start: i32::from_le_bytes([value[92], value[93], value[94], value[95]]),
+ packed_nid: i64::from_le_bytes([
+ value[96], value[97], value[98], value[99], value[100], value[101], value[102],
+ value[103],
+ ]),
+ xattr_filter_reserved: value[104],
+ reserved: value[105..128].try_into().unwrap(),
+ }
+ }
+}
+
+pub(crate) type SuperBlockBuf = [u8; size_of::<SuperBlock>()];
+pub(crate) const SUPERBLOCK_EMPTY_BUF: SuperBlockBuf = [0; size_of::<SuperBlock>()];
+
+/// Used for external address calculation.
+pub(crate) struct Accessor {
+ pub(crate) base: Off,
+ pub(crate) off: Off,
+ pub(crate) len: Off,
+ pub(crate) nr: Off,
+}
+
+impl Accessor {
+ pub(crate) fn new(address: Off, bits: Off) -> Self {
+ let sz = 1 << bits;
+ let mask = sz - 1;
+ Accessor {
+ base: (address >> bits) << bits,
+ off: address & mask,
+ len: sz - (address & mask),
+ nr: address >> bits,
+ }
+ }
+}
+
+impl SuperBlock {
+ pub(crate) fn blk_access(&self, address: Off) -> Accessor {
+ Accessor::new(address, self.blkszbits as Off)
+ }
+
+ pub(crate) fn blknr(&self, pos: Off) -> Blk {
+ (pos >> self.blkszbits) as Blk
+ }
+
+ pub(crate) fn blkpos(&self, blk: Blk) -> Off {
+ (blk as Off) << self.blkszbits
+ }
+
+ pub(crate) fn blksz(&self) -> Off {
+ 1 << self.blkszbits
+ }
+
+ pub(crate) fn blk_round_up(&self, addr: Off) -> Blk {
+ ((addr + self.blksz() - 1) >> self.blkszbits) as Blk
+ }
+
+ pub(crate) fn iloc(&self, nid: Nid) -> Off {
+ self.blkpos(self.meta_blkaddr) + ((nid as Off) << (5 as Off))
+ }
+}
diff --git a/fs/erofs/rust/mod.rs b/fs/erofs/rust/mod.rs
new file mode 100644
index 000000000000..e6c0731f2533
--- /dev/null
+++ b/fs/erofs/rust/mod.rs
@@ -0,0 +1,4 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod erofs_sys;
diff --git a/fs/erofs/super_rs.rs b/fs/erofs/super_rs.rs
new file mode 100644
index 000000000000..4b8cbef507e3
--- /dev/null
+++ b/fs/erofs/super_rs.rs
@@ -0,0 +1,9 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+//! EROFS Rust Kernel Module Helpers Implementation
+//! This is only for experimental purpose. Feedback is always welcome.
+
+#[allow(dead_code)]
+#[allow(missing_docs)]
+pub(crate) mod rust;
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 03/24] erofs: add Errno in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
Introduce Errno to Rust side code. Note that in current Rust For Linux,
Errnos are implemented as core::ffi::c_uint unit structs.
However, EUCLEAN, a.k.a EFSCORRUPTED is missing from error crate.
Since the errno_base hasn't changed for over 13 years,
This patch merely serves as a temporary workaround for the missing
errno in the Rust For Linux.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 6 +
fs/erofs/rust/erofs_sys/errnos.rs | 191 ++++++++++++++++++++++++++++++
2 files changed, 197 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/errnos.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 0f1400175fc2..2bd1381da5ab 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -19,4 +19,10 @@
pub(crate) type Nid = u64;
/// Erofs Super Offset to read the ondisk superblock
pub(crate) const EROFS_SUPER_OFFSET: Off = 1024;
+/// PosixResult as a type alias to kernel::error::Result
+/// to avoid naming conflicts.
+pub(crate) type PosixResult<T> = Result<T, Errno>;
+
+pub(crate) mod errnos;
pub(crate) mod superblock;
+pub(crate) use errnos::Errno;
diff --git a/fs/erofs/rust/erofs_sys/errnos.rs b/fs/erofs/rust/erofs_sys/errnos.rs
new file mode 100644
index 000000000000..40e5cdbcb353
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/errnos.rs
@@ -0,0 +1,191 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+#[repr(i32)]
+#[non_exhaustive]
+#[allow(clippy::upper_case_acronyms)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub(crate) enum Errno {
+ NONE = 0,
+ EPERM,
+ ENOENT,
+ ESRCH,
+ EINTR,
+ EIO,
+ ENXIO,
+ E2BIG,
+ ENOEXEC,
+ EBADF,
+ ECHILD,
+ EAGAIN,
+ ENOMEM,
+ EACCES,
+ EFAULT,
+ ENOTBLK,
+ EBUSY,
+ EEXIST,
+ EXDEV,
+ ENODEV,
+ ENOTDIR,
+ EISDIR,
+ EINVAL,
+ ENFILE,
+ EMFILE,
+ ENOTTY,
+ ETXTBSY,
+ EFBIG,
+ ENOSPC,
+ ESPIPE,
+ EROFS,
+ EMLINK,
+ EPIPE,
+ EDOM,
+ ERANGE,
+ EDEADLK,
+ ENAMETOOLONG,
+ ENOLCK,
+ ENOSYS,
+ ENOTEMPTY,
+ ELOOP,
+ ENOMSG = 42,
+ EIDRM,
+ ECHRNG,
+ EL2NSYNC,
+ EL3HLT,
+ EL3RST,
+ ELNRNG,
+ EUNATCH,
+ ENOCSI,
+ EL2HLT,
+ EBADE,
+ EBADR,
+ EXFULL,
+ ENOANO,
+ EBADRQC,
+ EBADSLT,
+ EBFONT = 59,
+ ENOSTR,
+ ENODATA,
+ ETIME,
+ ENOSR,
+ ENONET,
+ ENOPKG,
+ EREMOTE,
+ ENOLINK,
+ EADV,
+ ESRMNT,
+ ECOMM,
+ EPROTO,
+ EMULTIHOP,
+ EDOTDOT,
+ EBADMSG,
+ EOVERFLOW,
+ ENOTUNIQ,
+ EBADFD,
+ EREMCHG,
+ ELIBACC,
+ ELIBBAD,
+ ELIBSCN,
+ ELIBMAX,
+ ELIBEXEC,
+ EILSEQ,
+ ERESTART,
+ ESTRPIPE,
+ EUSERS,
+ ENOTSOCK,
+ EDESTADDRREQ,
+ EMSGSIZE,
+ EPROTOTYPE,
+ ENOPROTOOPT,
+ EPROTONOSUPPORT,
+ ESOCKTNOSUPPORT,
+ EOPNOTSUPP,
+ EPFNOSUPPORT,
+ EAFNOSUPPORT,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ ENETDOWN,
+ ENETUNREACH,
+ ENETRESET,
+ ECONNABORTED,
+ ECONNRESET,
+ ENOBUFS,
+ EISCONN,
+ ENOTCONN,
+ ESHUTDOWN,
+ ETOOMANYREFS,
+ ETIMEDOUT,
+ ECONNREFUSED,
+ EHOSTDOWN,
+ EHOSTUNREACH,
+ EALREADY,
+ EINPROGRESS,
+ ESTALE,
+ EUCLEAN,
+ ENOTNAM,
+ ENAVAIL,
+ EISNAM,
+ EREMOTEIO,
+ EDQUOT,
+ ENOMEDIUM,
+ EMEDIUMTYPE,
+ ECANCELED,
+ ENOKEY,
+ EKEYEXPIRED,
+ EKEYREVOKED,
+ EKEYREJECTED,
+ EOWNERDEAD,
+ ENOTRECOVERABLE,
+ ERFKILL,
+ EHWPOISON,
+ EUNKNOWN,
+}
+
+impl From<i32> for Errno {
+ fn from(value: i32) -> Self {
+ if (-value) <= 0 || (-value) > Errno::EUNKNOWN as i32 {
+ Errno::EUNKNOWN
+ } else {
+ // Safety: The value is guaranteed to be a valid errno and the memory
+ // layout is the same for both types.
+ unsafe { core::mem::transmute(value) }
+ }
+ }
+}
+
+impl From<Errno> for i32 {
+ fn from(value: Errno) -> Self {
+ -(value as i32)
+ }
+}
+
+/// Replacement for ERR_PTR in Linux Kernel.
+impl From<Errno> for *const core::ffi::c_void {
+ fn from(value: Errno) -> Self {
+ (-(value as core::ffi::c_long)) as *const core::ffi::c_void
+ }
+}
+
+impl From<Errno> for *mut core::ffi::c_void {
+ fn from(value: Errno) -> Self {
+ (-(value as core::ffi::c_long)) as *mut core::ffi::c_void
+ }
+}
+
+/// Replacement for PTR_ERR in Linux Kernel.
+impl From<*const core::ffi::c_void> for Errno {
+ fn from(value: *const core::ffi::c_void) -> Self {
+ (-(value as i32)).into()
+ }
+}
+
+impl From<*mut core::ffi::c_void> for Errno {
+ fn from(value: *mut core::ffi::c_void) -> Self {
+ (-(value as i32)).into()
+ }
+}
+/// Replacement for IS_ERR in Linux Kernel.
+#[inline(always)]
+pub(crate) fn is_value_err(value: *const core::ffi::c_void) -> bool {
+ (value as core::ffi::c_ulong) >= (-4095 as core::ffi::c_long) as core::ffi::c_ulong
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 03/24] erofs: add Errno in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
Introduce Errno to Rust side code. Note that in current Rust For Linux,
Errnos are implemented as core::ffi::c_uint unit structs.
However, EUCLEAN, a.k.a EFSCORRUPTED is missing from error crate.
Since the errno_base hasn't changed for over 13 years,
This patch merely serves as a temporary workaround for the missing
errno in the Rust For Linux.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 6 +
fs/erofs/rust/erofs_sys/errnos.rs | 191 ++++++++++++++++++++++++++++++
2 files changed, 197 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/errnos.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 0f1400175fc2..2bd1381da5ab 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -19,4 +19,10 @@
pub(crate) type Nid = u64;
/// Erofs Super Offset to read the ondisk superblock
pub(crate) const EROFS_SUPER_OFFSET: Off = 1024;
+/// PosixResult as a type alias to kernel::error::Result
+/// to avoid naming conflicts.
+pub(crate) type PosixResult<T> = Result<T, Errno>;
+
+pub(crate) mod errnos;
pub(crate) mod superblock;
+pub(crate) use errnos::Errno;
diff --git a/fs/erofs/rust/erofs_sys/errnos.rs b/fs/erofs/rust/erofs_sys/errnos.rs
new file mode 100644
index 000000000000..40e5cdbcb353
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/errnos.rs
@@ -0,0 +1,191 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+#[repr(i32)]
+#[non_exhaustive]
+#[allow(clippy::upper_case_acronyms)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub(crate) enum Errno {
+ NONE = 0,
+ EPERM,
+ ENOENT,
+ ESRCH,
+ EINTR,
+ EIO,
+ ENXIO,
+ E2BIG,
+ ENOEXEC,
+ EBADF,
+ ECHILD,
+ EAGAIN,
+ ENOMEM,
+ EACCES,
+ EFAULT,
+ ENOTBLK,
+ EBUSY,
+ EEXIST,
+ EXDEV,
+ ENODEV,
+ ENOTDIR,
+ EISDIR,
+ EINVAL,
+ ENFILE,
+ EMFILE,
+ ENOTTY,
+ ETXTBSY,
+ EFBIG,
+ ENOSPC,
+ ESPIPE,
+ EROFS,
+ EMLINK,
+ EPIPE,
+ EDOM,
+ ERANGE,
+ EDEADLK,
+ ENAMETOOLONG,
+ ENOLCK,
+ ENOSYS,
+ ENOTEMPTY,
+ ELOOP,
+ ENOMSG = 42,
+ EIDRM,
+ ECHRNG,
+ EL2NSYNC,
+ EL3HLT,
+ EL3RST,
+ ELNRNG,
+ EUNATCH,
+ ENOCSI,
+ EL2HLT,
+ EBADE,
+ EBADR,
+ EXFULL,
+ ENOANO,
+ EBADRQC,
+ EBADSLT,
+ EBFONT = 59,
+ ENOSTR,
+ ENODATA,
+ ETIME,
+ ENOSR,
+ ENONET,
+ ENOPKG,
+ EREMOTE,
+ ENOLINK,
+ EADV,
+ ESRMNT,
+ ECOMM,
+ EPROTO,
+ EMULTIHOP,
+ EDOTDOT,
+ EBADMSG,
+ EOVERFLOW,
+ ENOTUNIQ,
+ EBADFD,
+ EREMCHG,
+ ELIBACC,
+ ELIBBAD,
+ ELIBSCN,
+ ELIBMAX,
+ ELIBEXEC,
+ EILSEQ,
+ ERESTART,
+ ESTRPIPE,
+ EUSERS,
+ ENOTSOCK,
+ EDESTADDRREQ,
+ EMSGSIZE,
+ EPROTOTYPE,
+ ENOPROTOOPT,
+ EPROTONOSUPPORT,
+ ESOCKTNOSUPPORT,
+ EOPNOTSUPP,
+ EPFNOSUPPORT,
+ EAFNOSUPPORT,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ ENETDOWN,
+ ENETUNREACH,
+ ENETRESET,
+ ECONNABORTED,
+ ECONNRESET,
+ ENOBUFS,
+ EISCONN,
+ ENOTCONN,
+ ESHUTDOWN,
+ ETOOMANYREFS,
+ ETIMEDOUT,
+ ECONNREFUSED,
+ EHOSTDOWN,
+ EHOSTUNREACH,
+ EALREADY,
+ EINPROGRESS,
+ ESTALE,
+ EUCLEAN,
+ ENOTNAM,
+ ENAVAIL,
+ EISNAM,
+ EREMOTEIO,
+ EDQUOT,
+ ENOMEDIUM,
+ EMEDIUMTYPE,
+ ECANCELED,
+ ENOKEY,
+ EKEYEXPIRED,
+ EKEYREVOKED,
+ EKEYREJECTED,
+ EOWNERDEAD,
+ ENOTRECOVERABLE,
+ ERFKILL,
+ EHWPOISON,
+ EUNKNOWN,
+}
+
+impl From<i32> for Errno {
+ fn from(value: i32) -> Self {
+ if (-value) <= 0 || (-value) > Errno::EUNKNOWN as i32 {
+ Errno::EUNKNOWN
+ } else {
+ // Safety: The value is guaranteed to be a valid errno and the memory
+ // layout is the same for both types.
+ unsafe { core::mem::transmute(value) }
+ }
+ }
+}
+
+impl From<Errno> for i32 {
+ fn from(value: Errno) -> Self {
+ -(value as i32)
+ }
+}
+
+/// Replacement for ERR_PTR in Linux Kernel.
+impl From<Errno> for *const core::ffi::c_void {
+ fn from(value: Errno) -> Self {
+ (-(value as core::ffi::c_long)) as *const core::ffi::c_void
+ }
+}
+
+impl From<Errno> for *mut core::ffi::c_void {
+ fn from(value: Errno) -> Self {
+ (-(value as core::ffi::c_long)) as *mut core::ffi::c_void
+ }
+}
+
+/// Replacement for PTR_ERR in Linux Kernel.
+impl From<*const core::ffi::c_void> for Errno {
+ fn from(value: *const core::ffi::c_void) -> Self {
+ (-(value as i32)).into()
+ }
+}
+
+impl From<*mut core::ffi::c_void> for Errno {
+ fn from(value: *mut core::ffi::c_void) -> Self {
+ (-(value as i32)).into()
+ }
+}
+/// Replacement for IS_ERR in Linux Kernel.
+#[inline(always)]
+pub(crate) fn is_value_err(value: *const core::ffi::c_void) -> bool {
+ (value as core::ffi::c_ulong) >= (-4095 as core::ffi::c_long) as core::ffi::c_ulong
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 04/24] erofs: add xattrs data structure in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
This patch introduces on-disk and runtime data structure of Extended
Attributes implementation in erofs_sys crate. This will be later used to
implement the op handler.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 12 +++
fs/erofs/rust/erofs_sys/xattrs.rs | 124 ++++++++++++++++++++++++++++++
2 files changed, 136 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/xattrs.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 2bd1381da5ab..6f3c12665ed6 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -25,4 +25,16 @@
pub(crate) mod errnos;
pub(crate) mod superblock;
+pub(crate) mod xattrs;
pub(crate) use errnos::Errno;
+
+/// Helper macro to round up or down a number.
+#[macro_export]
+macro_rules! round {
+ (UP, $x: expr, $y: expr) => {
+ ($x + $y - 1) / $y * $y
+ };
+ (DOWN, $x: expr, $y: expr) => {
+ ($x / $y) * $y
+ };
+}
diff --git a/fs/erofs/rust/erofs_sys/xattrs.rs b/fs/erofs/rust/erofs_sys/xattrs.rs
new file mode 100644
index 000000000000..d1a110ef10dd
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/xattrs.rs
@@ -0,0 +1,124 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use alloc::vec::Vec;
+
+/// The header of the xattr entry index.
+/// This is used to describe the superblock's xattrs collection.
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub(crate) struct XAttrSharedEntrySummary {
+ pub(crate) name_filter: u32,
+ pub(crate) shared_count: u8,
+ pub(crate) reserved: [u8; 7],
+}
+
+impl From<[u8; 12]> for XAttrSharedEntrySummary {
+ fn from(value: [u8; 12]) -> Self {
+ Self {
+ name_filter: u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
+ shared_count: value[4],
+ reserved: value[5..12].try_into().unwrap(),
+ }
+ }
+}
+
+pub(crate) const XATTR_ENTRY_SUMMARY_BUF: [u8; 12] = [0u8; 12];
+
+/// Represented as a inmemory memory entry index header used by SuperBlockInfo.
+pub(crate) struct XAttrSharedEntries {
+ pub(crate) name_filter: u32,
+ pub(crate) shared_indexes: Vec<u32>,
+}
+
+/// Represents the name index for infixes or prefixes.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct XattrNameIndex(u8);
+
+impl core::cmp::PartialEq<u8> for XattrNameIndex {
+ fn eq(&self, other: &u8) -> bool {
+ if self.0 & EROFS_XATTR_LONG_PREFIX != 0 {
+ self.0 & EROFS_XATTR_LONG_MASK == *other
+ } else {
+ self.0 == *other
+ }
+ }
+}
+
+impl XattrNameIndex {
+ pub(crate) fn is_long(&self) -> bool {
+ self.0 & EROFS_XATTR_LONG_PREFIX != 0
+ }
+}
+
+impl From<u8> for XattrNameIndex {
+ fn from(value: u8) -> Self {
+ Self(value)
+ }
+}
+
+#[allow(clippy::from_over_into)]
+impl Into<usize> for XattrNameIndex {
+ fn into(self) -> usize {
+ if self.0 & EROFS_XATTR_LONG_PREFIX != 0 {
+ (self.0 & EROFS_XATTR_LONG_MASK) as usize
+ } else {
+ self.0 as usize
+ }
+ }
+}
+
+/// This is on-disk representation of xattrs entry header.
+/// This is used to describe one extended attribute.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct XAttrEntryHeader {
+ pub(crate) suffix_len: u8,
+ pub(crate) name_index: XattrNameIndex,
+ pub(crate) value_len: u16,
+}
+
+impl From<[u8; 4]> for XAttrEntryHeader {
+ fn from(value: [u8; 4]) -> Self {
+ Self {
+ suffix_len: value[0],
+ name_index: value[1].into(),
+ value_len: u16::from_le_bytes(value[2..4].try_into().unwrap()),
+ }
+ }
+}
+
+/// Xattr Common Infix holds the prefix index in the first byte and all the common infix data in
+/// the rest of the bytes.
+pub(crate) struct XAttrInfix(pub(crate) Vec<u8>);
+
+impl XAttrInfix {
+ fn prefix_index(&self) -> u8 {
+ self.0[0]
+ }
+ fn name(&self) -> &[u8] {
+ &self.0[1..]
+ }
+}
+
+pub(crate) const EROFS_XATTR_LONG_PREFIX: u8 = 0x80;
+pub(crate) const EROFS_XATTR_LONG_MASK: u8 = EROFS_XATTR_LONG_PREFIX - 1;
+
+/// Supported xattr prefixes
+pub(crate) const EROFS_XATTRS_PREFIXS: [&[u8]; 7] = [
+ b"",
+ b"user.",
+ b"system.posix_acl_access",
+ b"system.posix_acl_default",
+ b"trusted.",
+ b"",
+ b"security.",
+];
+
+/// Represents the value of an xattr entry or the size of it if the buffer is present in the query.
+#[derive(Debug)]
+pub(crate) enum XAttrValue {
+ Buffer(usize),
+ Vec(Vec<u8>),
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 04/24] erofs: add xattrs data structure in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
This patch introduces on-disk and runtime data structure of Extended
Attributes implementation in erofs_sys crate. This will be later used to
implement the op handler.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 12 +++
fs/erofs/rust/erofs_sys/xattrs.rs | 124 ++++++++++++++++++++++++++++++
2 files changed, 136 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/xattrs.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 2bd1381da5ab..6f3c12665ed6 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -25,4 +25,16 @@
pub(crate) mod errnos;
pub(crate) mod superblock;
+pub(crate) mod xattrs;
pub(crate) use errnos::Errno;
+
+/// Helper macro to round up or down a number.
+#[macro_export]
+macro_rules! round {
+ (UP, $x: expr, $y: expr) => {
+ ($x + $y - 1) / $y * $y
+ };
+ (DOWN, $x: expr, $y: expr) => {
+ ($x / $y) * $y
+ };
+}
diff --git a/fs/erofs/rust/erofs_sys/xattrs.rs b/fs/erofs/rust/erofs_sys/xattrs.rs
new file mode 100644
index 000000000000..d1a110ef10dd
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/xattrs.rs
@@ -0,0 +1,124 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use alloc::vec::Vec;
+
+/// The header of the xattr entry index.
+/// This is used to describe the superblock's xattrs collection.
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub(crate) struct XAttrSharedEntrySummary {
+ pub(crate) name_filter: u32,
+ pub(crate) shared_count: u8,
+ pub(crate) reserved: [u8; 7],
+}
+
+impl From<[u8; 12]> for XAttrSharedEntrySummary {
+ fn from(value: [u8; 12]) -> Self {
+ Self {
+ name_filter: u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
+ shared_count: value[4],
+ reserved: value[5..12].try_into().unwrap(),
+ }
+ }
+}
+
+pub(crate) const XATTR_ENTRY_SUMMARY_BUF: [u8; 12] = [0u8; 12];
+
+/// Represented as a inmemory memory entry index header used by SuperBlockInfo.
+pub(crate) struct XAttrSharedEntries {
+ pub(crate) name_filter: u32,
+ pub(crate) shared_indexes: Vec<u32>,
+}
+
+/// Represents the name index for infixes or prefixes.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct XattrNameIndex(u8);
+
+impl core::cmp::PartialEq<u8> for XattrNameIndex {
+ fn eq(&self, other: &u8) -> bool {
+ if self.0 & EROFS_XATTR_LONG_PREFIX != 0 {
+ self.0 & EROFS_XATTR_LONG_MASK == *other
+ } else {
+ self.0 == *other
+ }
+ }
+}
+
+impl XattrNameIndex {
+ pub(crate) fn is_long(&self) -> bool {
+ self.0 & EROFS_XATTR_LONG_PREFIX != 0
+ }
+}
+
+impl From<u8> for XattrNameIndex {
+ fn from(value: u8) -> Self {
+ Self(value)
+ }
+}
+
+#[allow(clippy::from_over_into)]
+impl Into<usize> for XattrNameIndex {
+ fn into(self) -> usize {
+ if self.0 & EROFS_XATTR_LONG_PREFIX != 0 {
+ (self.0 & EROFS_XATTR_LONG_MASK) as usize
+ } else {
+ self.0 as usize
+ }
+ }
+}
+
+/// This is on-disk representation of xattrs entry header.
+/// This is used to describe one extended attribute.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct XAttrEntryHeader {
+ pub(crate) suffix_len: u8,
+ pub(crate) name_index: XattrNameIndex,
+ pub(crate) value_len: u16,
+}
+
+impl From<[u8; 4]> for XAttrEntryHeader {
+ fn from(value: [u8; 4]) -> Self {
+ Self {
+ suffix_len: value[0],
+ name_index: value[1].into(),
+ value_len: u16::from_le_bytes(value[2..4].try_into().unwrap()),
+ }
+ }
+}
+
+/// Xattr Common Infix holds the prefix index in the first byte and all the common infix data in
+/// the rest of the bytes.
+pub(crate) struct XAttrInfix(pub(crate) Vec<u8>);
+
+impl XAttrInfix {
+ fn prefix_index(&self) -> u8 {
+ self.0[0]
+ }
+ fn name(&self) -> &[u8] {
+ &self.0[1..]
+ }
+}
+
+pub(crate) const EROFS_XATTR_LONG_PREFIX: u8 = 0x80;
+pub(crate) const EROFS_XATTR_LONG_MASK: u8 = EROFS_XATTR_LONG_PREFIX - 1;
+
+/// Supported xattr prefixes
+pub(crate) const EROFS_XATTRS_PREFIXS: [&[u8]; 7] = [
+ b"",
+ b"user.",
+ b"system.posix_acl_access",
+ b"system.posix_acl_default",
+ b"trusted.",
+ b"",
+ b"security.",
+];
+
+/// Represents the value of an xattr entry or the size of it if the buffer is present in the query.
+#[derive(Debug)]
+pub(crate) enum XAttrValue {
+ Buffer(usize),
+ Vec(Vec<u8>),
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 05/24] erofs: add inode data structure in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
This patch introduces the same on-disk erofs data structure
in rust and also introduces multiple helpers for inode i_format
and chunk_indexing and later can be used to implement map_blocks.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/inode.rs | 291 +++++++++++++++++++++++++++++++
2 files changed, 292 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/inode.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 6f3c12665ed6..34267ec7772d 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -24,6 +24,7 @@
pub(crate) type PosixResult<T> = Result<T, Errno>;
pub(crate) mod errnos;
+pub(crate) mod inode;
pub(crate) mod superblock;
pub(crate) mod xattrs;
pub(crate) use errnos::Errno;
diff --git a/fs/erofs/rust/erofs_sys/inode.rs b/fs/erofs/rust/erofs_sys/inode.rs
new file mode 100644
index 000000000000..1762023e97f8
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/inode.rs
@@ -0,0 +1,291 @@
+use super::xattrs::*;
+use super::*;
+use core::ffi::*;
+use core::mem::size_of;
+
+/// Represents the compact bitfield of the Erofs Inode format.
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub(crate) struct Format(u16);
+
+pub(crate) const INODE_VERSION_MASK: u16 = 0x1;
+pub(crate) const INODE_VERSION_BIT: u16 = 0;
+
+pub(crate) const INODE_LAYOUT_BIT: u16 = 1;
+pub(crate) const INODE_LAYOUT_MASK: u16 = 0x7;
+
+/// Helper macro to extract property from the bitfield.
+macro_rules! extract {
+ ($name: expr, $bit: expr, $mask: expr) => {
+ ($name >> $bit) & ($mask)
+ };
+}
+
+/// The Version of the Inode which represents whether this inode is extended or compact.
+/// Extended inodes have more infos about nlinks + mtime.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) enum Version {
+ Compat,
+ Extended,
+ Unknown,
+}
+
+/// Represents the data layout backed by the Inode.
+/// As Documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inode-data-layouts
+#[repr(C)]
+#[derive(Clone, Copy, PartialEq)]
+pub(crate) enum Layout {
+ FlatPlain,
+ CompressedFull,
+ FlatInline,
+ CompressedCompact,
+ Chunk,
+ Unknown,
+}
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub(crate) enum Type {
+ Regular,
+ Directory,
+ Link,
+ Character,
+ Block,
+ Fifo,
+ Socket,
+ Unknown,
+}
+
+/// This is format extracted from i_format bit representation.
+/// This includes various infos and specs about the inode.
+impl Format {
+ pub(crate) fn version(&self) -> Version {
+ match extract!(self.0, INODE_VERSION_BIT, INODE_VERSION_MASK) {
+ 0 => Version::Compat,
+ 1 => Version::Extended,
+ _ => Version::Unknown,
+ }
+ }
+
+ pub(crate) fn layout(&self) -> Layout {
+ match extract!(self.0, INODE_LAYOUT_BIT, INODE_LAYOUT_MASK) {
+ 0 => Layout::FlatPlain,
+ 1 => Layout::CompressedFull,
+ 2 => Layout::FlatInline,
+ 3 => Layout::CompressedCompact,
+ 4 => Layout::Chunk,
+ _ => Layout::Unknown,
+ }
+ }
+}
+
+/// Represents the compact inode which resides on-disk.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct CompactInodeInfo {
+ pub(crate) i_format: Format,
+ pub(crate) i_xattr_icount: u16,
+ pub(crate) i_mode: u16,
+ pub(crate) i_nlink: u16,
+ pub(crate) i_size: u32,
+ pub(crate) i_reserved: [u8; 4],
+ pub(crate) i_u: [u8; 4],
+ pub(crate) i_ino: u32,
+ pub(crate) i_uid: u16,
+ pub(crate) i_gid: u16,
+ pub(crate) i_reserved2: [u8; 4],
+}
+
+/// Represents the extended inode which resides on-disk.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct ExtendedInodeInfo {
+ pub(crate) i_format: Format,
+ pub(crate) i_xattr_icount: u16,
+ pub(crate) i_mode: u16,
+ pub(crate) i_reserved: [u8; 2],
+ pub(crate) i_size: u64,
+ pub(crate) i_u: [u8; 4],
+ pub(crate) i_ino: u32,
+ pub(crate) i_uid: u32,
+ pub(crate) i_gid: u32,
+ pub(crate) i_mtime: u64,
+ pub(crate) i_mtime_nsec: u32,
+ pub(crate) i_nlink: u32,
+ pub(crate) i_reserved2: [u8; 16],
+}
+
+/// Represents the inode info which is either compact or extended.
+#[derive(Clone, Copy)]
+pub(crate) enum InodeInfo {
+ Extended(ExtendedInodeInfo),
+ Compact(CompactInodeInfo),
+}
+
+pub(crate) const CHUNK_BLKBITS_MASK: u16 = 0x1f;
+pub(crate) const CHUNK_FORMAT_INDEX_BIT: u16 = 0x20;
+
+/// Represents on-disk chunk index of the file backing inode.
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct ChunkIndex {
+ pub(crate) advise: u16,
+ pub(crate) device_id: u16,
+ pub(crate) blkaddr: u32,
+}
+
+impl From<[u8; 8]> for ChunkIndex {
+ fn from(u: [u8; 8]) -> Self {
+ let advise = u16::from_le_bytes([u[0], u[1]]);
+ let device_id = u16::from_le_bytes([u[2], u[3]]);
+ let blkaddr = u32::from_le_bytes([u[4], u[5], u[6], u[7]]);
+ ChunkIndex {
+ advise,
+ device_id,
+ blkaddr,
+ }
+ }
+}
+
+/// Chunk format used for indicating the chunkbits and chunkindex.
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct ChunkFormat(pub(crate) u16);
+
+impl ChunkFormat {
+ pub(crate) fn is_chunkindex(&self) -> bool {
+ self.0 & CHUNK_FORMAT_INDEX_BIT != 0
+ }
+ pub(crate) fn chunkbits(&self) -> u16 {
+ self.0 & CHUNK_BLKBITS_MASK
+ }
+}
+
+/// Represents the inode spec which is either data or device.
+#[derive(Clone, Copy, Debug)]
+#[repr(u32)]
+pub(crate) enum Spec {
+ Chunk(ChunkFormat),
+ RawBlk(u32),
+ Device(u32),
+ CompressedBlocks(u32),
+ Unknown,
+}
+
+/// Convert the spec from the format of the inode based on the layout.
+impl From<(&[u8; 4], Layout)> for Spec {
+ fn from(value: (&[u8; 4], Layout)) -> Self {
+ match value.1 {
+ Layout::FlatInline | Layout::FlatPlain => Spec::RawBlk(u32::from_le_bytes(*value.0)),
+ Layout::CompressedFull | Layout::CompressedCompact => {
+ Spec::CompressedBlocks(u32::from_le_bytes(*value.0))
+ }
+ Layout::Chunk => Self::Chunk(ChunkFormat(u16::from_le_bytes([value.0[0], value.0[1]]))),
+ // We don't support compressed inlines or compressed chunks currently.
+ _ => Spec::Unknown,
+ }
+ }
+}
+
+/// Helper functions for Inode Info.
+impl InodeInfo {
+ const S_IFMT: u16 = 0o170000;
+ const S_IFSOCK: u16 = 0o140000;
+ const S_IFLNK: u16 = 0o120000;
+ const S_IFREG: u16 = 0o100000;
+ const S_IFBLK: u16 = 0o60000;
+ const S_IFDIR: u16 = 0o40000;
+ const S_IFCHR: u16 = 0o20000;
+ const S_IFIFO: u16 = 0o10000;
+ const S_ISUID: u16 = 0o4000;
+ const S_ISGID: u16 = 0o2000;
+ const S_ISVTX: u16 = 0o1000;
+ pub(crate) fn ino(&self) -> u32 {
+ match self {
+ Self::Extended(extended) => extended.i_ino,
+ Self::Compact(compact) => compact.i_ino,
+ }
+ }
+
+ pub(crate) fn format(&self) -> Format {
+ match self {
+ Self::Extended(extended) => extended.i_format,
+ Self::Compact(compact) => compact.i_format,
+ }
+ }
+
+ pub(crate) fn file_size(&self) -> Off {
+ match self {
+ Self::Extended(extended) => extended.i_size,
+ Self::Compact(compact) => compact.i_size as u64,
+ }
+ }
+
+ pub(crate) fn inode_size(&self) -> Off {
+ match self {
+ Self::Extended(_) => 64,
+ Self::Compact(_) => 32,
+ }
+ }
+
+ pub(crate) fn spec(&self) -> Spec {
+ let mode = match self {
+ Self::Extended(extended) => extended.i_mode,
+ Self::Compact(compact) => compact.i_mode,
+ };
+
+ let u = match self {
+ Self::Extended(extended) => &extended.i_u,
+ Self::Compact(compact) => &compact.i_u,
+ };
+
+ match mode & 0o170000 {
+ 0o40000 | 0o100000 | 0o120000 => Spec::from((u, self.format().layout())),
+ // We don't support device inodes currently.
+ _ => Spec::Unknown,
+ }
+ }
+
+ pub(crate) fn inode_type(&self) -> Type {
+ let mode = match self {
+ Self::Extended(extended) => extended.i_mode,
+ Self::Compact(compact) => compact.i_mode,
+ };
+ match mode & Self::S_IFMT {
+ Self::S_IFDIR => Type::Directory, // Directory
+ Self::S_IFREG => Type::Regular, // Regular File
+ Self::S_IFLNK => Type::Link, // Symbolic Link
+ Self::S_IFIFO => Type::Fifo, // FIFO
+ Self::S_IFSOCK => Type::Socket, // Socket
+ Self::S_IFBLK => Type::Block, // Block
+ Self::S_IFCHR => Type::Character, // Character
+ _ => Type::Unknown,
+ }
+ }
+
+ pub(crate) fn xattr_size(&self) -> Off {
+ match self {
+ Self::Extended(extended) => {
+ size_of::<XAttrSharedEntrySummary>() as Off
+ + (size_of::<c_int>() as Off) * (extended.i_xattr_icount as Off - 1)
+ }
+ Self::Compact(_) => 0,
+ }
+ }
+
+ pub(crate) fn xattr_count(&self) -> u16 {
+ match self {
+ Self::Extended(extended) => extended.i_xattr_icount,
+ Self::Compact(compact) => compact.i_xattr_icount,
+ }
+ }
+}
+
+pub(crate) type CompactInodeInfoBuf = [u8; size_of::<CompactInodeInfo>()];
+pub(crate) type ExtendedInodeInfoBuf = [u8; size_of::<ExtendedInodeInfo>()];
+pub(crate) const DEFAULT_INODE_BUF: ExtendedInodeInfoBuf = [0; size_of::<ExtendedInodeInfo>()];
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 05/24] erofs: add inode data structure in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
This patch introduces the same on-disk erofs data structure
in rust and also introduces multiple helpers for inode i_format
and chunk_indexing and later can be used to implement map_blocks.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/inode.rs | 291 +++++++++++++++++++++++++++++++
2 files changed, 292 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/inode.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 6f3c12665ed6..34267ec7772d 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -24,6 +24,7 @@
pub(crate) type PosixResult<T> = Result<T, Errno>;
pub(crate) mod errnos;
+pub(crate) mod inode;
pub(crate) mod superblock;
pub(crate) mod xattrs;
pub(crate) use errnos::Errno;
diff --git a/fs/erofs/rust/erofs_sys/inode.rs b/fs/erofs/rust/erofs_sys/inode.rs
new file mode 100644
index 000000000000..1762023e97f8
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/inode.rs
@@ -0,0 +1,291 @@
+use super::xattrs::*;
+use super::*;
+use core::ffi::*;
+use core::mem::size_of;
+
+/// Represents the compact bitfield of the Erofs Inode format.
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub(crate) struct Format(u16);
+
+pub(crate) const INODE_VERSION_MASK: u16 = 0x1;
+pub(crate) const INODE_VERSION_BIT: u16 = 0;
+
+pub(crate) const INODE_LAYOUT_BIT: u16 = 1;
+pub(crate) const INODE_LAYOUT_MASK: u16 = 0x7;
+
+/// Helper macro to extract property from the bitfield.
+macro_rules! extract {
+ ($name: expr, $bit: expr, $mask: expr) => {
+ ($name >> $bit) & ($mask)
+ };
+}
+
+/// The Version of the Inode which represents whether this inode is extended or compact.
+/// Extended inodes have more infos about nlinks + mtime.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) enum Version {
+ Compat,
+ Extended,
+ Unknown,
+}
+
+/// Represents the data layout backed by the Inode.
+/// As Documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inode-data-layouts
+#[repr(C)]
+#[derive(Clone, Copy, PartialEq)]
+pub(crate) enum Layout {
+ FlatPlain,
+ CompressedFull,
+ FlatInline,
+ CompressedCompact,
+ Chunk,
+ Unknown,
+}
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub(crate) enum Type {
+ Regular,
+ Directory,
+ Link,
+ Character,
+ Block,
+ Fifo,
+ Socket,
+ Unknown,
+}
+
+/// This is format extracted from i_format bit representation.
+/// This includes various infos and specs about the inode.
+impl Format {
+ pub(crate) fn version(&self) -> Version {
+ match extract!(self.0, INODE_VERSION_BIT, INODE_VERSION_MASK) {
+ 0 => Version::Compat,
+ 1 => Version::Extended,
+ _ => Version::Unknown,
+ }
+ }
+
+ pub(crate) fn layout(&self) -> Layout {
+ match extract!(self.0, INODE_LAYOUT_BIT, INODE_LAYOUT_MASK) {
+ 0 => Layout::FlatPlain,
+ 1 => Layout::CompressedFull,
+ 2 => Layout::FlatInline,
+ 3 => Layout::CompressedCompact,
+ 4 => Layout::Chunk,
+ _ => Layout::Unknown,
+ }
+ }
+}
+
+/// Represents the compact inode which resides on-disk.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct CompactInodeInfo {
+ pub(crate) i_format: Format,
+ pub(crate) i_xattr_icount: u16,
+ pub(crate) i_mode: u16,
+ pub(crate) i_nlink: u16,
+ pub(crate) i_size: u32,
+ pub(crate) i_reserved: [u8; 4],
+ pub(crate) i_u: [u8; 4],
+ pub(crate) i_ino: u32,
+ pub(crate) i_uid: u16,
+ pub(crate) i_gid: u16,
+ pub(crate) i_reserved2: [u8; 4],
+}
+
+/// Represents the extended inode which resides on-disk.
+/// This is documented in https://erofs.docs.kernel.org/en/latest/core_ondisk.html#inodes
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub(crate) struct ExtendedInodeInfo {
+ pub(crate) i_format: Format,
+ pub(crate) i_xattr_icount: u16,
+ pub(crate) i_mode: u16,
+ pub(crate) i_reserved: [u8; 2],
+ pub(crate) i_size: u64,
+ pub(crate) i_u: [u8; 4],
+ pub(crate) i_ino: u32,
+ pub(crate) i_uid: u32,
+ pub(crate) i_gid: u32,
+ pub(crate) i_mtime: u64,
+ pub(crate) i_mtime_nsec: u32,
+ pub(crate) i_nlink: u32,
+ pub(crate) i_reserved2: [u8; 16],
+}
+
+/// Represents the inode info which is either compact or extended.
+#[derive(Clone, Copy)]
+pub(crate) enum InodeInfo {
+ Extended(ExtendedInodeInfo),
+ Compact(CompactInodeInfo),
+}
+
+pub(crate) const CHUNK_BLKBITS_MASK: u16 = 0x1f;
+pub(crate) const CHUNK_FORMAT_INDEX_BIT: u16 = 0x20;
+
+/// Represents on-disk chunk index of the file backing inode.
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct ChunkIndex {
+ pub(crate) advise: u16,
+ pub(crate) device_id: u16,
+ pub(crate) blkaddr: u32,
+}
+
+impl From<[u8; 8]> for ChunkIndex {
+ fn from(u: [u8; 8]) -> Self {
+ let advise = u16::from_le_bytes([u[0], u[1]]);
+ let device_id = u16::from_le_bytes([u[2], u[3]]);
+ let blkaddr = u32::from_le_bytes([u[4], u[5], u[6], u[7]]);
+ ChunkIndex {
+ advise,
+ device_id,
+ blkaddr,
+ }
+ }
+}
+
+/// Chunk format used for indicating the chunkbits and chunkindex.
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct ChunkFormat(pub(crate) u16);
+
+impl ChunkFormat {
+ pub(crate) fn is_chunkindex(&self) -> bool {
+ self.0 & CHUNK_FORMAT_INDEX_BIT != 0
+ }
+ pub(crate) fn chunkbits(&self) -> u16 {
+ self.0 & CHUNK_BLKBITS_MASK
+ }
+}
+
+/// Represents the inode spec which is either data or device.
+#[derive(Clone, Copy, Debug)]
+#[repr(u32)]
+pub(crate) enum Spec {
+ Chunk(ChunkFormat),
+ RawBlk(u32),
+ Device(u32),
+ CompressedBlocks(u32),
+ Unknown,
+}
+
+/// Convert the spec from the format of the inode based on the layout.
+impl From<(&[u8; 4], Layout)> for Spec {
+ fn from(value: (&[u8; 4], Layout)) -> Self {
+ match value.1 {
+ Layout::FlatInline | Layout::FlatPlain => Spec::RawBlk(u32::from_le_bytes(*value.0)),
+ Layout::CompressedFull | Layout::CompressedCompact => {
+ Spec::CompressedBlocks(u32::from_le_bytes(*value.0))
+ }
+ Layout::Chunk => Self::Chunk(ChunkFormat(u16::from_le_bytes([value.0[0], value.0[1]]))),
+ // We don't support compressed inlines or compressed chunks currently.
+ _ => Spec::Unknown,
+ }
+ }
+}
+
+/// Helper functions for Inode Info.
+impl InodeInfo {
+ const S_IFMT: u16 = 0o170000;
+ const S_IFSOCK: u16 = 0o140000;
+ const S_IFLNK: u16 = 0o120000;
+ const S_IFREG: u16 = 0o100000;
+ const S_IFBLK: u16 = 0o60000;
+ const S_IFDIR: u16 = 0o40000;
+ const S_IFCHR: u16 = 0o20000;
+ const S_IFIFO: u16 = 0o10000;
+ const S_ISUID: u16 = 0o4000;
+ const S_ISGID: u16 = 0o2000;
+ const S_ISVTX: u16 = 0o1000;
+ pub(crate) fn ino(&self) -> u32 {
+ match self {
+ Self::Extended(extended) => extended.i_ino,
+ Self::Compact(compact) => compact.i_ino,
+ }
+ }
+
+ pub(crate) fn format(&self) -> Format {
+ match self {
+ Self::Extended(extended) => extended.i_format,
+ Self::Compact(compact) => compact.i_format,
+ }
+ }
+
+ pub(crate) fn file_size(&self) -> Off {
+ match self {
+ Self::Extended(extended) => extended.i_size,
+ Self::Compact(compact) => compact.i_size as u64,
+ }
+ }
+
+ pub(crate) fn inode_size(&self) -> Off {
+ match self {
+ Self::Extended(_) => 64,
+ Self::Compact(_) => 32,
+ }
+ }
+
+ pub(crate) fn spec(&self) -> Spec {
+ let mode = match self {
+ Self::Extended(extended) => extended.i_mode,
+ Self::Compact(compact) => compact.i_mode,
+ };
+
+ let u = match self {
+ Self::Extended(extended) => &extended.i_u,
+ Self::Compact(compact) => &compact.i_u,
+ };
+
+ match mode & 0o170000 {
+ 0o40000 | 0o100000 | 0o120000 => Spec::from((u, self.format().layout())),
+ // We don't support device inodes currently.
+ _ => Spec::Unknown,
+ }
+ }
+
+ pub(crate) fn inode_type(&self) -> Type {
+ let mode = match self {
+ Self::Extended(extended) => extended.i_mode,
+ Self::Compact(compact) => compact.i_mode,
+ };
+ match mode & Self::S_IFMT {
+ Self::S_IFDIR => Type::Directory, // Directory
+ Self::S_IFREG => Type::Regular, // Regular File
+ Self::S_IFLNK => Type::Link, // Symbolic Link
+ Self::S_IFIFO => Type::Fifo, // FIFO
+ Self::S_IFSOCK => Type::Socket, // Socket
+ Self::S_IFBLK => Type::Block, // Block
+ Self::S_IFCHR => Type::Character, // Character
+ _ => Type::Unknown,
+ }
+ }
+
+ pub(crate) fn xattr_size(&self) -> Off {
+ match self {
+ Self::Extended(extended) => {
+ size_of::<XAttrSharedEntrySummary>() as Off
+ + (size_of::<c_int>() as Off) * (extended.i_xattr_icount as Off - 1)
+ }
+ Self::Compact(_) => 0,
+ }
+ }
+
+ pub(crate) fn xattr_count(&self) -> u16 {
+ match self {
+ Self::Extended(extended) => extended.i_xattr_icount,
+ Self::Compact(compact) => compact.i_xattr_icount,
+ }
+ }
+}
+
+pub(crate) type CompactInodeInfoBuf = [u8; size_of::<CompactInodeInfo>()];
+pub(crate) type ExtendedInodeInfoBuf = [u8; size_of::<ExtendedInodeInfo>()];
+pub(crate) const DEFAULT_INODE_BUF: ExtendedInodeInfoBuf = [0; size_of::<ExtendedInodeInfo>()];
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 06/24] erofs: add alloc_helper in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
In normal rust, heap related operations are infallible meaning
that they do not throw errors and Rust will panic in usermode instead.
However in kernel, it will throw AllocError this module helps to
bridge the gaps and returns Errno universally.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/alloc_helper.rs | 35 +++++++++++++++++++++++++
2 files changed, 36 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/alloc_helper.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 34267ec7772d..c6fd7f78ac97 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -23,6 +23,7 @@
/// to avoid naming conflicts.
pub(crate) type PosixResult<T> = Result<T, Errno>;
+pub(crate) mod alloc_helper;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/alloc_helper.rs b/fs/erofs/rust/erofs_sys/alloc_helper.rs
new file mode 100644
index 000000000000..05ef2018d379
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/alloc_helper.rs
@@ -0,0 +1,35 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+/// This module provides helper functions for the alloc crate
+/// Note that in linux kernel, the allocation is fallible however in userland it is not.
+/// Since most of the functions depend on infallible allocation, here we provide helper functions
+/// so that most of codes don't need to be changed.
+
+#[cfg(CONFIG_EROFS_FS = "y")]
+use kernel::prelude::*;
+
+#[cfg(not(CONFIG_EROFS_FS = "y"))]
+use alloc::vec;
+
+use super::*;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
+pub(crate) fn push_vec<T>(v: &mut Vec<T>, value: T) -> PosixResult<()> {
+ v.push(value, GFP_KERNEL)
+ .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(()))
+}
+
+pub(crate) fn extend_from_slice<T: Clone>(v: &mut Vec<T>, slice: &[T]) -> PosixResult<()> {
+ v.extend_from_slice(slice, GFP_KERNEL)
+ .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(()))
+}
+
+pub(crate) fn heap_alloc<T>(value: T) -> PosixResult<Box<T>> {
+ Box::new(value, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v))
+}
+
+pub(crate) fn vec_with_capacity<T: Default + Clone>(capacity: usize) -> PosixResult<Vec<T>> {
+ Vec::with_capacity(capacity, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v))
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 06/24] erofs: add alloc_helper in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
In normal rust, heap related operations are infallible meaning
that they do not throw errors and Rust will panic in usermode instead.
However in kernel, it will throw AllocError this module helps to
bridge the gaps and returns Errno universally.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/alloc_helper.rs | 35 +++++++++++++++++++++++++
2 files changed, 36 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/alloc_helper.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 34267ec7772d..c6fd7f78ac97 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -23,6 +23,7 @@
/// to avoid naming conflicts.
pub(crate) type PosixResult<T> = Result<T, Errno>;
+pub(crate) mod alloc_helper;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/alloc_helper.rs b/fs/erofs/rust/erofs_sys/alloc_helper.rs
new file mode 100644
index 000000000000..05ef2018d379
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/alloc_helper.rs
@@ -0,0 +1,35 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+/// This module provides helper functions for the alloc crate
+/// Note that in linux kernel, the allocation is fallible however in userland it is not.
+/// Since most of the functions depend on infallible allocation, here we provide helper functions
+/// so that most of codes don't need to be changed.
+
+#[cfg(CONFIG_EROFS_FS = "y")]
+use kernel::prelude::*;
+
+#[cfg(not(CONFIG_EROFS_FS = "y"))]
+use alloc::vec;
+
+use super::*;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
+pub(crate) fn push_vec<T>(v: &mut Vec<T>, value: T) -> PosixResult<()> {
+ v.push(value, GFP_KERNEL)
+ .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(()))
+}
+
+pub(crate) fn extend_from_slice<T: Clone>(v: &mut Vec<T>, slice: &[T]) -> PosixResult<()> {
+ v.extend_from_slice(slice, GFP_KERNEL)
+ .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(()))
+}
+
+pub(crate) fn heap_alloc<T>(value: T) -> PosixResult<Box<T>> {
+ Box::new(value, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v))
+}
+
+pub(crate) fn vec_with_capacity<T: Default + Clone>(capacity: usize) -> PosixResult<Vec<T>> {
+ Vec::with_capacity(capacity, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v))
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 07/24] erofs: add data abstraction in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
Introduce Buffer, Source, Backend traits.
Implement Uncompressed Backend and RefBuffer to be
used in future data operations.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/data.rs | 62 +++++++++++++++++++
fs/erofs/rust/erofs_sys/data/backends.rs | 4 ++
.../erofs_sys/data/backends/uncompressed.rs | 39 ++++++++++++
4 files changed, 106 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/data.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index c6fd7f78ac97..8cca2cd9b75f 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -24,6 +24,7 @@
pub(crate) type PosixResult<T> = Result<T, Errno>;
pub(crate) mod alloc_helper;
+pub(crate) mod data;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs
new file mode 100644
index 000000000000..284c8b1f3bd4
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data.rs
@@ -0,0 +1,62 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+pub(crate) mod backends;
+use super::*;
+
+/// Represent some sort of generic data source. This cound be file, memory or even network.
+/// Note that users should never use this directly please use backends instead.
+pub(crate) trait Source {
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64>;
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>>;
+}
+
+/// Represents a generic data access backend that is backed by some sort of data source.
+/// This often has temporary buffers to decompress the data from the data source.
+/// The method signatures are the same as those of the Source trait.
+pub(crate) trait Backend {
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64>;
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>>;
+}
+
+/// Represents a buffer trait which can yield its internal reference or be casted as an iterator of
+/// DirEntries.
+pub(crate) trait Buffer {
+ fn content(&self) -> &[u8];
+}
+
+/// Represents a buffer that holds a reference to a slice of data that
+/// is borrowed from the thin air.
+pub(crate) struct RefBuffer<'a> {
+ buf: &'a [u8],
+ start: usize,
+ len: usize,
+ put_buf: fn(*mut core::ffi::c_void),
+}
+
+impl<'a> Buffer for RefBuffer<'a> {
+ fn content(&self) -> &[u8] {
+ &self.buf[self.start..self.start + self.len]
+ }
+}
+
+impl<'a> RefBuffer<'a> {
+ pub(crate) fn new(
+ buf: &'a [u8],
+ start: usize,
+ len: usize,
+ put_buf: fn(*mut core::ffi::c_void),
+ ) -> Self {
+ Self {
+ buf,
+ start,
+ len,
+ put_buf,
+ }
+ }
+}
+
+impl<'a> Drop for RefBuffer<'a> {
+ fn drop(&mut self) {
+ (self.put_buf)(self.buf.as_ptr() as *mut core::ffi::c_void)
+ }
+}
diff --git a/fs/erofs/rust/erofs_sys/data/backends.rs b/fs/erofs/rust/erofs_sys/data/backends.rs
new file mode 100644
index 000000000000..3249f1af8be7
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/backends.rs
@@ -0,0 +1,4 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod uncompressed;
diff --git a/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs b/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
new file mode 100644
index 000000000000..c1b1a60258f8
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
@@ -0,0 +1,39 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+
+pub(crate) struct UncompressedBackend<T>
+where
+ T: Source,
+{
+ source: T,
+}
+
+impl<T> Backend for UncompressedBackend<T>
+where
+ T: Source,
+{
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64> {
+ self.source.fill(data, offset)
+ }
+
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>> {
+ self.source.as_buf(offset, len)
+ }
+}
+
+impl<T: Source> UncompressedBackend<T> {
+ pub(crate) fn new(source: T) -> Self {
+ Self { source }
+ }
+}
+
+impl<T> From<T> for UncompressedBackend<T>
+where
+ T: Source,
+{
+ fn from(value: T) -> Self {
+ Self::new(value)
+ }
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 07/24] erofs: add data abstraction in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
Introduce Buffer, Source, Backend traits.
Implement Uncompressed Backend and RefBuffer to be
used in future data operations.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/data.rs | 62 +++++++++++++++++++
fs/erofs/rust/erofs_sys/data/backends.rs | 4 ++
.../erofs_sys/data/backends/uncompressed.rs | 39 ++++++++++++
4 files changed, 106 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/data.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index c6fd7f78ac97..8cca2cd9b75f 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -24,6 +24,7 @@
pub(crate) type PosixResult<T> = Result<T, Errno>;
pub(crate) mod alloc_helper;
+pub(crate) mod data;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs
new file mode 100644
index 000000000000..284c8b1f3bd4
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data.rs
@@ -0,0 +1,62 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+pub(crate) mod backends;
+use super::*;
+
+/// Represent some sort of generic data source. This cound be file, memory or even network.
+/// Note that users should never use this directly please use backends instead.
+pub(crate) trait Source {
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64>;
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>>;
+}
+
+/// Represents a generic data access backend that is backed by some sort of data source.
+/// This often has temporary buffers to decompress the data from the data source.
+/// The method signatures are the same as those of the Source trait.
+pub(crate) trait Backend {
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64>;
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>>;
+}
+
+/// Represents a buffer trait which can yield its internal reference or be casted as an iterator of
+/// DirEntries.
+pub(crate) trait Buffer {
+ fn content(&self) -> &[u8];
+}
+
+/// Represents a buffer that holds a reference to a slice of data that
+/// is borrowed from the thin air.
+pub(crate) struct RefBuffer<'a> {
+ buf: &'a [u8],
+ start: usize,
+ len: usize,
+ put_buf: fn(*mut core::ffi::c_void),
+}
+
+impl<'a> Buffer for RefBuffer<'a> {
+ fn content(&self) -> &[u8] {
+ &self.buf[self.start..self.start + self.len]
+ }
+}
+
+impl<'a> RefBuffer<'a> {
+ pub(crate) fn new(
+ buf: &'a [u8],
+ start: usize,
+ len: usize,
+ put_buf: fn(*mut core::ffi::c_void),
+ ) -> Self {
+ Self {
+ buf,
+ start,
+ len,
+ put_buf,
+ }
+ }
+}
+
+impl<'a> Drop for RefBuffer<'a> {
+ fn drop(&mut self) {
+ (self.put_buf)(self.buf.as_ptr() as *mut core::ffi::c_void)
+ }
+}
diff --git a/fs/erofs/rust/erofs_sys/data/backends.rs b/fs/erofs/rust/erofs_sys/data/backends.rs
new file mode 100644
index 000000000000..3249f1af8be7
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/backends.rs
@@ -0,0 +1,4 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod uncompressed;
diff --git a/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs b/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
new file mode 100644
index 000000000000..c1b1a60258f8
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/backends/uncompressed.rs
@@ -0,0 +1,39 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+
+pub(crate) struct UncompressedBackend<T>
+where
+ T: Source,
+{
+ source: T,
+}
+
+impl<T> Backend for UncompressedBackend<T>
+where
+ T: Source,
+{
+ fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult<u64> {
+ self.source.fill(data, offset)
+ }
+
+ fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult<RefBuffer<'a>> {
+ self.source.as_buf(offset, len)
+ }
+}
+
+impl<T: Source> UncompressedBackend<T> {
+ pub(crate) fn new(source: T) -> Self {
+ Self { source }
+ }
+}
+
+impl<T> From<T> for UncompressedBackend<T>
+where
+ T: Source,
+{
+ fn from(value: T) -> Self {
+ Self::new(value)
+ }
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 08/24] erofs: add device data structure in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
This patch introduce device data structure in Rust.
It can later support chunk based block maps.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/devices.rs | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/devices.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 8cca2cd9b75f..f1a1e491caec 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -25,6 +25,7 @@
pub(crate) mod alloc_helper;
pub(crate) mod data;
+pub(crate) mod devices;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/devices.rs b/fs/erofs/rust/erofs_sys/devices.rs
new file mode 100644
index 000000000000..097676ee8720
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/devices.rs
@@ -0,0 +1,28 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use alloc::vec::Vec;
+
+/// Device specification.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct DeviceSpec {
+ pub(crate) tags: [u8; 64],
+ pub(crate) blocks: u32,
+ pub(crate) mapped_blocks: u32,
+}
+
+/// Device slot.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub(crate) struct DeviceSlot {
+ tags: [u8; 64],
+ blocks: u32,
+ mapped_blocks: u32,
+ reserved: [u8; 56],
+}
+
+/// Device information.
+pub(crate) struct DeviceInfo {
+ pub(crate) mask: u16,
+ pub(crate) specs: Vec<DeviceSpec>,
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 08/24] erofs: add device data structure in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
This patch introduce device data structure in Rust.
It can later support chunk based block maps.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys.rs | 1 +
fs/erofs/rust/erofs_sys/devices.rs | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/devices.rs
diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs
index 8cca2cd9b75f..f1a1e491caec 100644
--- a/fs/erofs/rust/erofs_sys.rs
+++ b/fs/erofs/rust/erofs_sys.rs
@@ -25,6 +25,7 @@
pub(crate) mod alloc_helper;
pub(crate) mod data;
+pub(crate) mod devices;
pub(crate) mod errnos;
pub(crate) mod inode;
pub(crate) mod superblock;
diff --git a/fs/erofs/rust/erofs_sys/devices.rs b/fs/erofs/rust/erofs_sys/devices.rs
new file mode 100644
index 000000000000..097676ee8720
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/devices.rs
@@ -0,0 +1,28 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use alloc::vec::Vec;
+
+/// Device specification.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct DeviceSpec {
+ pub(crate) tags: [u8; 64],
+ pub(crate) blocks: u32,
+ pub(crate) mapped_blocks: u32,
+}
+
+/// Device slot.
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub(crate) struct DeviceSlot {
+ tags: [u8; 64],
+ blocks: u32,
+ mapped_blocks: u32,
+ reserved: [u8; 56],
+}
+
+/// Device information.
+pub(crate) struct DeviceInfo {
+ pub(crate) mask: u16,
+ pub(crate) specs: Vec<DeviceSpec>,
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 09/24] erofs: add continuous iterators in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
This patch adds a special iterator that is capable of iterating over a
memory region in the granularity of a common page. This can be later
used to read device buffer or fast symlink.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys/data.rs | 2 +
fs/erofs/rust/erofs_sys/data/raw_iters.rs | 6 ++
.../rust/erofs_sys/data/raw_iters/ref_iter.rs | 68 +++++++++++++++++++
.../rust/erofs_sys/data/raw_iters/traits.rs | 13 ++++
4 files changed, 89 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs
index 284c8b1f3bd4..483f3204ce42 100644
--- a/fs/erofs/rust/erofs_sys/data.rs
+++ b/fs/erofs/rust/erofs_sys/data.rs
@@ -1,6 +1,8 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
pub(crate) mod backends;
+pub(crate) mod raw_iters;
+use super::superblock::*;
use super::*;
/// Represent some sort of generic data source. This cound be file, memory or even network.
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters.rs b/fs/erofs/rust/erofs_sys/data/raw_iters.rs
new file mode 100644
index 000000000000..8f3bd250d252
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters.rs
@@ -0,0 +1,6 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod ref_iter;
+mod traits;
+pub(crate) use traits::*;
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs b/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
new file mode 100644
index 000000000000..5aa2b7f44f3d
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
@@ -0,0 +1,68 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+use super::*;
+
+/// Continous Ref Buffer Iterator which iterates over a range of disk addresses within the
+/// the temp block size. Since the temp block is always the same size as page and it will not
+/// overflow.
+pub(crate) struct ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ sb: &'a SuperBlock,
+ backend: &'a B,
+ offset: Off,
+ len: Off,
+}
+
+impl<'a, B> ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ pub(crate) fn new(sb: &'a SuperBlock, backend: &'a B, offset: Off, len: Off) -> Self {
+ Self {
+ sb,
+ backend,
+ offset,
+ len,
+ }
+ }
+}
+
+impl<'a, B> Iterator for ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ type Item = PosixResult<RefBuffer<'a>>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.len == 0 {
+ return None;
+ }
+ let accessor = self.sb.blk_access(self.offset);
+ let len = accessor.len.min(self.len);
+ let result: Option<Self::Item> = self.backend.as_buf(self.offset, len).map_or_else(
+ |e| Some(Err(e)),
+ |buf| {
+ self.offset += len;
+ self.len -= len;
+ Some(Ok(buf))
+ },
+ );
+ result
+ }
+}
+
+impl<'a, B> ContinuousBufferIter<'a> for ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ fn advance_off(&mut self, offset: Off) {
+ self.offset += offset;
+ self.len -= offset
+ }
+ fn eof(&self) -> bool {
+ self.len == 0
+ }
+}
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
new file mode 100644
index 000000000000..90b6a51658a9
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
@@ -0,0 +1,13 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+
+/// Represents a basic iterator over a range of bytes from data backends.
+/// Note that this is skippable and can be used to move the iterator's cursor forward.
+pub(crate) trait ContinuousBufferIter<'a>:
+ Iterator<Item = PosixResult<RefBuffer<'a>>>
+{
+ fn advance_off(&mut self, offset: Off);
+ fn eof(&self) -> bool;
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 09/24] erofs: add continuous iterators in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
This patch adds a special iterator that is capable of iterating over a
memory region in the granularity of a common page. This can be later
used to read device buffer or fast symlink.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys/data.rs | 2 +
fs/erofs/rust/erofs_sys/data/raw_iters.rs | 6 ++
.../rust/erofs_sys/data/raw_iters/ref_iter.rs | 68 +++++++++++++++++++
.../rust/erofs_sys/data/raw_iters/traits.rs | 13 ++++
4 files changed, 89 insertions(+)
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
create mode 100644 fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs
index 284c8b1f3bd4..483f3204ce42 100644
--- a/fs/erofs/rust/erofs_sys/data.rs
+++ b/fs/erofs/rust/erofs_sys/data.rs
@@ -1,6 +1,8 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
pub(crate) mod backends;
+pub(crate) mod raw_iters;
+use super::superblock::*;
use super::*;
/// Represent some sort of generic data source. This cound be file, memory or even network.
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters.rs b/fs/erofs/rust/erofs_sys/data/raw_iters.rs
new file mode 100644
index 000000000000..8f3bd250d252
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters.rs
@@ -0,0 +1,6 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+pub(crate) mod ref_iter;
+mod traits;
+pub(crate) use traits::*;
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs b/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
new file mode 100644
index 000000000000..5aa2b7f44f3d
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs
@@ -0,0 +1,68 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+use super::*;
+
+/// Continous Ref Buffer Iterator which iterates over a range of disk addresses within the
+/// the temp block size. Since the temp block is always the same size as page and it will not
+/// overflow.
+pub(crate) struct ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ sb: &'a SuperBlock,
+ backend: &'a B,
+ offset: Off,
+ len: Off,
+}
+
+impl<'a, B> ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ pub(crate) fn new(sb: &'a SuperBlock, backend: &'a B, offset: Off, len: Off) -> Self {
+ Self {
+ sb,
+ backend,
+ offset,
+ len,
+ }
+ }
+}
+
+impl<'a, B> Iterator for ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ type Item = PosixResult<RefBuffer<'a>>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.len == 0 {
+ return None;
+ }
+ let accessor = self.sb.blk_access(self.offset);
+ let len = accessor.len.min(self.len);
+ let result: Option<Self::Item> = self.backend.as_buf(self.offset, len).map_or_else(
+ |e| Some(Err(e)),
+ |buf| {
+ self.offset += len;
+ self.len -= len;
+ Some(Ok(buf))
+ },
+ );
+ result
+ }
+}
+
+impl<'a, B> ContinuousBufferIter<'a> for ContinuousRefIter<'a, B>
+where
+ B: Backend,
+{
+ fn advance_off(&mut self, offset: Off) {
+ self.offset += offset;
+ self.len -= offset
+ }
+ fn eof(&self) -> bool {
+ self.len == 0
+ }
+}
diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
new file mode 100644
index 000000000000..90b6a51658a9
--- /dev/null
+++ b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs
@@ -0,0 +1,13 @@
+// Copyright 2024 Yiyang Wu
+// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+
+use super::super::*;
+
+/// Represents a basic iterator over a range of bytes from data backends.
+/// Note that this is skippable and can be used to move the iterator's cursor forward.
+pub(crate) trait ContinuousBufferIter<'a>:
+ Iterator<Item = PosixResult<RefBuffer<'a>>>
+{
+ fn advance_off(&mut self, offset: Off);
+ fn eof(&self) -> bool;
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [RFC PATCH 10/24] erofs: add device_infos implementation in Rust
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 13:55 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: linux-fsdevel, rust-for-linux
Add device_infos implementation in rust. It will later be used
to be put inside the SuperblockInfo. This mask and spec can later
be used to chunk-based image file block mapping.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys/devices.rs | 47 ++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/fs/erofs/rust/erofs_sys/devices.rs b/fs/erofs/rust/erofs_sys/devices.rs
index 097676ee8720..7495164c7bd0 100644
--- a/fs/erofs/rust/erofs_sys/devices.rs
+++ b/fs/erofs/rust/erofs_sys/devices.rs
@@ -1,6 +1,10 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+use super::alloc_helper::*;
+use super::data::raw_iters::*;
+use super::data::*;
+use super::*;
use alloc::vec::Vec;
/// Device specification.
@@ -21,8 +25,51 @@ pub(crate) struct DeviceSlot {
reserved: [u8; 56],
}
+impl From<[u8; 128]> for DeviceSlot {
+ fn from(data: [u8; 128]) -> Self {
+ Self {
+ tags: data[0..64].try_into().unwrap(),
+ blocks: u32::from_le_bytes([data[64], data[65], data[66], data[67]]),
+ mapped_blocks: u32::from_le_bytes([data[68], data[69], data[70], data[71]]),
+ reserved: data[72..128].try_into().unwrap(),
+ }
+ }
+}
+
/// Device information.
pub(crate) struct DeviceInfo {
pub(crate) mask: u16,
pub(crate) specs: Vec<DeviceSpec>,
}
+
+pub(crate) fn get_device_infos<'a>(
+ iter: &mut (dyn ContinuousBufferIter<'a> + 'a),
+) -> PosixResult<DeviceInfo> {
+ let mut specs = Vec::new();
+ for data in iter {
+ let buffer = data?;
+ let mut cur: usize = 0;
+ let len = buffer.content().len();
+ while cur + 128 <= len {
+ let slot_data: [u8; 128] = buffer.content()[cur..cur + 128].try_into().unwrap();
+ let slot = DeviceSlot::from(slot_data);
+ cur += 128;
+ push_vec(
+ &mut specs,
+ DeviceSpec {
+ tags: slot.tags,
+ blocks: slot.blocks,
+ mapped_blocks: slot.mapped_blocks,
+ },
+ )?;
+ }
+ }
+
+ let mask = if specs.is_empty() {
+ 0
+ } else {
+ (1 << (specs.len().ilog2() + 1)) - 1
+ };
+
+ Ok(DeviceInfo { mask, specs })
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [RFC PATCH 10/24] erofs: add device_infos implementation in Rust
@ 2024-09-16 13:55 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 13:55 UTC (permalink / raw)
To: linux-erofs; +Cc: rust-for-linux, linux-fsdevel
Add device_infos implementation in rust. It will later be used
to be put inside the SuperblockInfo. This mask and spec can later
be used to chunk-based image file block mapping.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/rust/erofs_sys/devices.rs | 47 ++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/fs/erofs/rust/erofs_sys/devices.rs b/fs/erofs/rust/erofs_sys/devices.rs
index 097676ee8720..7495164c7bd0 100644
--- a/fs/erofs/rust/erofs_sys/devices.rs
+++ b/fs/erofs/rust/erofs_sys/devices.rs
@@ -1,6 +1,10 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
+use super::alloc_helper::*;
+use super::data::raw_iters::*;
+use super::data::*;
+use super::*;
use alloc::vec::Vec;
/// Device specification.
@@ -21,8 +25,51 @@ pub(crate) struct DeviceSlot {
reserved: [u8; 56],
}
+impl From<[u8; 128]> for DeviceSlot {
+ fn from(data: [u8; 128]) -> Self {
+ Self {
+ tags: data[0..64].try_into().unwrap(),
+ blocks: u32::from_le_bytes([data[64], data[65], data[66], data[67]]),
+ mapped_blocks: u32::from_le_bytes([data[68], data[69], data[70], data[71]]),
+ reserved: data[72..128].try_into().unwrap(),
+ }
+ }
+}
+
/// Device information.
pub(crate) struct DeviceInfo {
pub(crate) mask: u16,
pub(crate) specs: Vec<DeviceSpec>,
}
+
+pub(crate) fn get_device_infos<'a>(
+ iter: &mut (dyn ContinuousBufferIter<'a> + 'a),
+) -> PosixResult<DeviceInfo> {
+ let mut specs = Vec::new();
+ for data in iter {
+ let buffer = data?;
+ let mut cur: usize = 0;
+ let len = buffer.content().len();
+ while cur + 128 <= len {
+ let slot_data: [u8; 128] = buffer.content()[cur..cur + 128].try_into().unwrap();
+ let slot = DeviceSlot::from(slot_data);
+ cur += 128;
+ push_vec(
+ &mut specs,
+ DeviceSpec {
+ tags: slot.tags,
+ blocks: slot.blocks,
+ mapped_blocks: slot.mapped_blocks,
+ },
+ )?;
+ }
+ }
+
+ let mask = if specs.is_empty() {
+ 0
+ } else {
+ (1 << (specs.len().ilog2() + 1)) - 1
+ };
+
+ Ok(DeviceInfo { mask, specs })
+}
--
2.46.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [RFC PATCH 00/24] erofs: introduce Rust implementation
2024-09-16 13:55 ` Yiyang Wu
@ 2024-09-16 14:04 ` Yiyang Wu
-1 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu via Linux-erofs @ 2024-09-16 14:04 UTC (permalink / raw)
To: linux-erofs, linux-fsdevel, rust-for-linux
On Mon, Sep 16, 2024 at 09:55:17PM GMT, Yiyang Wu via Linux-erofs wrote:
> Greetings,
>
> So here is a patchset to add Rust skeleton codes to the current EROFS
> implementation. The implementation is deeply inspired by the current C
> implementation, and it's based on a generic erofs_sys crate[1] written
> by me. The purpose is to potentially replace some of C codes to make
> to make full use of Rust's safety features and better
> optimization guarantees.
Utterly sorry for my mistake.
I forgot CC the LKML when copying the mailing list
so i interrupt the patch sending.
Just delete the first one and use the second patchset,
and it should be OK.
Best Regards
Yiyang Wu,
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [RFC PATCH 00/24] erofs: introduce Rust implementation
@ 2024-09-16 14:04 ` Yiyang Wu
0 siblings, 0 replies; 26+ messages in thread
From: Yiyang Wu @ 2024-09-16 14:04 UTC (permalink / raw)
To: linux-erofs, linux-fsdevel, rust-for-linux
On Mon, Sep 16, 2024 at 09:55:17PM GMT, Yiyang Wu via Linux-erofs wrote:
> Greetings,
>
> So here is a patchset to add Rust skeleton codes to the current EROFS
> implementation. The implementation is deeply inspired by the current C
> implementation, and it's based on a generic erofs_sys crate[1] written
> by me. The purpose is to potentially replace some of C codes to make
> to make full use of Rust's safety features and better
> optimization guarantees.
Utterly sorry for my mistake.
I forgot CC the LKML when copying the mailing list
so i interrupt the patch sending.
Just delete the first one and use the second patchset,
and it should be OK.
Best Regards
Yiyang Wu,
^ permalink raw reply [flat|nested] 26+ messages in thread