From: Yiyang Wu <toolmanp@tlmp.cc>
To: linux-erofs@lists.ozlabs.org
Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org,
LKML <linux-kernel@vger.kernel.org>
Subject: [RFC PATCH 23/24] erofs: implement xattrs operations in Rust
Date: Mon, 16 Sep 2024 21:56:33 +0800 [thread overview]
Message-ID: <20240916135634.98554-24-toolmanp@tlmp.cc> (raw)
In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc>
This patch adds xattrs for erofs_sys crate and will later be used to
implement xattr handler in Rust.
Signed-off-by: Yiyang Wu <toolmanp@tlmp.cc>
---
fs/erofs/inode_rs.rs | 7 +-
fs/erofs/rust/erofs_sys/inode.rs | 1 +
fs/erofs/rust/erofs_sys/operations.rs | 27 ++++
fs/erofs/rust/erofs_sys/superblock.rs | 141 +++++++++++++++++++++
fs/erofs/rust/erofs_sys/superblock/mem.rs | 13 +-
fs/erofs/rust/erofs_sys/xattrs.rs | 148 ++++++++++++++++++++++
fs/erofs/rust/kinode.rs | 6 +
7 files changed, 341 insertions(+), 2 deletions(-)
diff --git a/fs/erofs/inode_rs.rs b/fs/erofs/inode_rs.rs
index 5cca2ae581ac..a79d1157b910 100644
--- a/fs/erofs/inode_rs.rs
+++ b/fs/erofs/inode_rs.rs
@@ -48,8 +48,13 @@ fn try_fill_inode(k_inode: NonNull<inode>, nid: Nid) -> PosixResult<()> {
let erofs_inode: &mut KernelInode = unsafe {
&mut *(container_of!(k_inode.as_ptr(), KernelInode, k_inode) as *mut KernelInode)
};
- erofs_inode.info.write(sbi.filesystem.read_inode_info(nid)?);
+ let info = sbi.filesystem.read_inode_info(nid)?;
erofs_inode.nid.write(nid);
+ erofs_inode.shared_entries.write(
+ sbi.filesystem
+ .read_inode_xattrs_shared_entries(nid, &info)?,
+ );
+ erofs_inode.info.write(info);
Ok(())
}
/// Exported as fill_inode additional fill inode
diff --git a/fs/erofs/rust/erofs_sys/inode.rs b/fs/erofs/rust/erofs_sys/inode.rs
index 1ecd6147a126..eb3c2144cad8 100644
--- a/fs/erofs/rust/erofs_sys/inode.rs
+++ b/fs/erofs/rust/erofs_sys/inode.rs
@@ -299,6 +299,7 @@ pub(crate) trait Inode: Sized {
fn new(_sb: &SuperBlock, info: InodeInfo, nid: Nid) -> Self;
fn info(&self) -> &InodeInfo;
fn nid(&self) -> Nid;
+ fn xattrs_shared_entries(&self) -> &XAttrSharedEntries;
}
/// Represents the error which occurs when trying to convert the inode.
diff --git a/fs/erofs/rust/erofs_sys/operations.rs b/fs/erofs/rust/erofs_sys/operations.rs
index 070ba20908a2..292bfbc7b72c 100644
--- a/fs/erofs/rust/erofs_sys/operations.rs
+++ b/fs/erofs/rust/erofs_sys/operations.rs
@@ -1,9 +1,16 @@
// 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::inode::*;
use super::superblock::*;
+use super::xattrs::*;
use super::*;
+use alloc::vec::Vec;
+
+use crate::round;
pub(crate) fn read_inode<'a, I, C>(
filesystem: &'a dyn FileSystem<I>,
@@ -33,3 +40,23 @@ pub(crate) fn dir_lookup<'a, I, C>(
read_inode(filesystem, collection, nid)
})
}
+
+pub(crate) fn get_xattr_infixes<'a>(
+ iter: &mut (dyn ContinuousBufferIter<'a> + 'a),
+) -> PosixResult<Vec<XAttrInfix>> {
+ let mut result: Vec<XAttrInfix> = Vec::new();
+ for data in iter {
+ let buffer = data?;
+ let buf = buffer.content();
+ let len = buf.len();
+ let mut cur: usize = 0;
+ while cur <= len {
+ let mut infix: Vec<u8> = Vec::new();
+ let size = u16::from_le_bytes([buf[cur], buf[cur + 1]]) as usize;
+ extend_from_slice(&mut infix, &buf[cur + 2..cur + 2 + size])?;
+ push_vec(&mut result, XAttrInfix(infix))?;
+ cur = round!(UP, cur + 2 + size, 4);
+ }
+ }
+ Ok(result)
+}
diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs
index 403ffdeb4573..6ea59058446e 100644
--- a/fs/erofs/rust/erofs_sys/superblock.rs
+++ b/fs/erofs/rust/erofs_sys/superblock.rs
@@ -3,14 +3,17 @@
pub(crate) mod mem;
use alloc::boxed::Box;
+use alloc::vec::Vec;
use core::mem::size_of;
+use super::alloc_helper::*;
use super::data::raw_iters::*;
use super::data::*;
use super::devices::*;
use super::dir::*;
use super::inode::*;
use super::map::*;
+use super::xattrs::*;
use super::*;
use crate::round;
@@ -346,6 +349,144 @@ fn fill_dentries(
}
Ok(())
}
+ // Extended attributes goes here.
+ fn xattr_infixes(&self) -> &Vec<XAttrInfix>;
+ // Currently we eagerly initialized all xattrs;
+ fn read_inode_xattrs_shared_entries(
+ &self,
+ nid: Nid,
+ info: &InodeInfo,
+ ) -> PosixResult<XAttrSharedEntries> {
+ let sb = self.superblock();
+ let mut offset = sb.iloc(nid) + info.inode_size();
+ let mut buf = XATTR_ENTRY_SUMMARY_BUF;
+ let mut indexes: Vec<u32> = Vec::new();
+ self.backend().fill(&mut buf, offset)?;
+
+ let header: XAttrSharedEntrySummary = XAttrSharedEntrySummary::from(buf);
+ offset += size_of::<XAttrSharedEntrySummary>() as Off;
+ for buf in self.continuous_iter(offset, (header.shared_count << 2) as Off)? {
+ let data = buf?;
+ extend_from_slice(&mut indexes, unsafe {
+ core::slice::from_raw_parts(
+ data.content().as_ptr().cast(),
+ data.content().len() >> 2,
+ )
+ })?;
+ }
+
+ Ok(XAttrSharedEntries {
+ name_filter: header.name_filter,
+ shared_indexes: indexes,
+ })
+ }
+ fn get_xattr(
+ &self,
+ inode: &I,
+ index: u32,
+ name: &[u8],
+ buffer: &mut Option<&mut [u8]>,
+ ) -> PosixResult<XAttrValue> {
+ let sb = self.superblock();
+ let shared_count = inode.xattrs_shared_entries().shared_indexes.len();
+ let inline_offset = sb.iloc(inode.nid())
+ + inode.info().inode_size() as Off
+ + size_of::<XAttrSharedEntrySummary>() as Off
+ + 4 * shared_count as Off;
+
+ let inline_len = inode.info().xattr_size()
+ - size_of::<XAttrSharedEntrySummary>() as Off
+ - shared_count as Off * 4;
+
+ if let Some(mut inline_provider) =
+ SkippableContinuousIter::try_new(self.continuous_iter(inline_offset, inline_len)?)?
+ {
+ while !inline_provider.eof() {
+ let header = inline_provider.get_entry_header()?;
+ match inline_provider.query_xattr_value(
+ self.xattr_infixes(),
+ &header,
+ name,
+ index,
+ buffer,
+ ) {
+ Ok(value) => return Ok(value),
+ Err(e) => {
+ if e != ENODATA {
+ return Err(e);
+ }
+ }
+ }
+ }
+ }
+
+ for entry_index in inode.xattrs_shared_entries().shared_indexes.iter() {
+ let mut shared_provider = SkippableContinuousIter::try_new(self.continuous_iter(
+ sb.blkpos(self.superblock().xattr_blkaddr) + (*entry_index as Off) * 4,
+ u64::MAX,
+ )?)?
+ .unwrap();
+ let header = shared_provider.get_entry_header()?;
+ match shared_provider.query_xattr_value(
+ self.xattr_infixes(),
+ &header,
+ name,
+ index,
+ buffer,
+ ) {
+ Ok(value) => return Ok(value),
+ Err(e) => {
+ if e != ENODATA {
+ return Err(e);
+ }
+ }
+ }
+ }
+
+ Err(ENODATA)
+ }
+
+ fn list_xattrs(&self, inode: &I, buffer: &mut [u8]) -> PosixResult<usize> {
+ let sb = self.superblock();
+ let shared_count = inode.xattrs_shared_entries().shared_indexes.len();
+ let inline_offset = sb.iloc(inode.nid())
+ + inode.info().inode_size() as Off
+ + size_of::<XAttrSharedEntrySummary>() as Off
+ + shared_count as Off * 4;
+ let mut offset = 0;
+ let inline_len = inode.info().xattr_size()
+ - size_of::<XAttrSharedEntrySummary>() as Off
+ - shared_count as Off * 4;
+
+ if let Some(mut inline_provider) =
+ SkippableContinuousIter::try_new(self.continuous_iter(inline_offset, inline_len)?)?
+ {
+ while !inline_provider.eof() {
+ let header = inline_provider.get_entry_header()?;
+ offset += inline_provider.get_xattr_key(
+ self.xattr_infixes(),
+ &header,
+ &mut buffer[offset..],
+ )?;
+ inline_provider.skip_xattr_value(&header)?;
+ }
+ }
+
+ for index in inode.xattrs_shared_entries().shared_indexes.iter() {
+ let mut shared_provider = SkippableContinuousIter::try_new(self.continuous_iter(
+ sb.blkpos(self.superblock().xattr_blkaddr) + (*index as Off) * 4,
+ u64::MAX,
+ )?)?
+ .unwrap();
+ let header = shared_provider.get_entry_header()?;
+ offset += shared_provider.get_xattr_key(
+ self.xattr_infixes(),
+ &header,
+ &mut buffer[offset..],
+ )?;
+ }
+ Ok(offset)
+ }
}
pub(crate) struct SuperblockInfo<I, C, T>
diff --git a/fs/erofs/rust/erofs_sys/superblock/mem.rs b/fs/erofs/rust/erofs_sys/superblock/mem.rs
index 5756dc08744c..c8af3cb5e56e 100644
--- a/fs/erofs/rust/erofs_sys/superblock/mem.rs
+++ b/fs/erofs/rust/erofs_sys/superblock/mem.rs
@@ -1,8 +1,8 @@
// Copyright 2024 Yiyang Wu
// SPDX-License-Identifier: MIT or GPL-2.0-or-later
-use super::alloc_helper::*;
use super::data::raw_iters::ref_iter::*;
+use super::operations::*;
use super::*;
// Memory Mapped Device/File so we need to have some external lifetime on the backend trait.
@@ -16,6 +16,7 @@ pub(crate) struct KernelFileSystem<B>
backend: B,
sb: SuperBlock,
device_info: DeviceInfo,
+ infixes: Vec<XAttrInfix>,
}
impl<I, B> FileSystem<I> for KernelFileSystem<B>
@@ -58,6 +59,9 @@ fn continuous_iter<'a>(
fn device_info(&self) -> &DeviceInfo {
&self.device_info
}
+ fn xattr_infixes(&self) -> &Vec<XAttrInfix> {
+ &self.infixes
+ }
}
impl<B> KernelFileSystem<B>
@@ -68,6 +72,12 @@ pub(crate) fn try_new(backend: B) -> PosixResult<Self> {
let mut buf = SUPERBLOCK_EMPTY_BUF;
backend.fill(&mut buf, EROFS_SUPER_OFFSET)?;
let sb: SuperBlock = buf.into();
+ let infixes = get_xattr_infixes(&mut ContinuousRefIter::new(
+ &sb,
+ &backend,
+ sb.xattr_prefix_start as Off,
+ sb.xattr_prefix_count as Off * 4,
+ ))?;
let device_info = get_device_infos(&mut ContinuousRefIter::new(
&sb,
&backend,
@@ -78,6 +88,7 @@ pub(crate) fn try_new(backend: B) -> PosixResult<Self> {
backend,
sb,
device_info,
+ infixes,
})
}
}
diff --git a/fs/erofs/rust/erofs_sys/xattrs.rs b/fs/erofs/rust/erofs_sys/xattrs.rs
index d1a110ef10dd..c97640731562 100644
--- a/fs/erofs/rust/erofs_sys/xattrs.rs
+++ b/fs/erofs/rust/erofs_sys/xattrs.rs
@@ -1,7 +1,13 @@
// 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::*;
+use crate::round;
+
use alloc::vec::Vec;
+use core::mem::size_of;
/// The header of the xattr entry index.
/// This is used to describe the superblock's xattrs collection.
@@ -122,3 +128,145 @@ pub(crate) enum XAttrValue {
Buffer(usize),
Vec(Vec<u8>),
}
+
+/// An iterator to read xattrs by comparing the entry's name one by one and reads its value
+/// correspondingly.
+pub(crate) trait XAttrEntriesProvider {
+ fn get_entry_header(&mut self) -> PosixResult<XAttrEntryHeader>;
+ fn get_xattr_key(
+ &mut self,
+ pfs: &[XAttrInfix],
+ header: &XAttrEntryHeader,
+ buffer: &mut [u8],
+ ) -> PosixResult<usize>;
+ fn query_xattr_value(
+ &mut self,
+ pfs: &[XAttrInfix],
+ header: &XAttrEntryHeader,
+ name: &[u8],
+ index: u32,
+ buffer: &mut Option<&mut [u8]>,
+ ) -> PosixResult<XAttrValue>;
+ fn skip_xattr_value(&mut self, header: &XAttrEntryHeader) -> PosixResult<()>;
+}
+impl<'a> XAttrEntriesProvider for SkippableContinuousIter<'a> {
+ fn get_entry_header(&mut self) -> PosixResult<XAttrEntryHeader> {
+ let mut buf: [u8; 4] = [0; 4];
+ self.read(&mut buf).map(|_| XAttrEntryHeader::from(buf))
+ }
+
+ fn get_xattr_key(
+ &mut self,
+ ifs: &[XAttrInfix],
+ header: &XAttrEntryHeader,
+ buffer: &mut [u8],
+ ) -> PosixResult<usize> {
+ let mut cur = if header.name_index.is_long() {
+ let if_index: usize = header.name_index.into();
+ let infix: &XAttrInfix = ifs.get(if_index).unwrap();
+
+ let pf_index = infix.prefix_index();
+ let prefix = EROFS_XATTRS_PREFIXS[pf_index as usize];
+ let plen = prefix.len();
+
+ buffer[..plen].copy_from_slice(&prefix[..plen]);
+ buffer[plen..infix.name().len() + plen].copy_from_slice(infix.name());
+
+ plen + infix.name().len()
+ } else {
+ let pf_index: usize = header.name_index.into();
+ let prefix = EROFS_XATTRS_PREFIXS[pf_index];
+ let plen = prefix.len();
+ buffer[..plen].copy_from_slice(&prefix[..plen]);
+ plen
+ };
+
+ self.read(&mut buffer[cur..cur + header.suffix_len as usize])?;
+ cur += header.suffix_len as usize;
+ buffer[cur] = b'\0';
+ Ok(cur + 1)
+ }
+
+ fn query_xattr_value(
+ &mut self,
+ ifs: &[XAttrInfix],
+ header: &XAttrEntryHeader,
+ name: &[u8],
+ index: u32,
+ buffer: &mut Option<&mut [u8]>,
+ ) -> PosixResult<XAttrValue> {
+ let xattr_size = round!(
+ UP,
+ header.suffix_len as Off + header.value_len as Off,
+ size_of::<XAttrEntryHeader>() as Off
+ );
+
+ let cur = if header.name_index.is_long() {
+ let if_index: usize = header.name_index.into();
+
+ if if_index >= ifs.len() {
+ return Err(ENODATA);
+ }
+
+ let infix = ifs.get(if_index).unwrap();
+ let ilen = infix.name().len();
+
+ let pf_index = infix.prefix_index();
+
+ if pf_index >= EROFS_XATTRS_PREFIXS.len() as u8 {
+ return Err(ENODATA);
+ }
+
+ if index != pf_index as u32
+ || name.len() != ilen + header.suffix_len as usize
+ || name[..ilen] != *infix.name()
+ {
+ return Err(ENODATA);
+ }
+ ilen
+ } else {
+ let pf_index: usize = header.name_index.into();
+ if pf_index >= EROFS_XATTRS_PREFIXS.len() {
+ return Err(ENODATA);
+ }
+
+ if pf_index != index as usize || header.suffix_len as usize != name.len() {
+ return Err(ENODATA);
+ }
+ 0
+ };
+
+ match self.try_cmp(&name[cur..]) {
+ Ok(()) => match buffer.as_mut() {
+ Some(b) => {
+ if b.len() < header.value_len as usize {
+ return Err(ERANGE);
+ }
+ self.read(&mut b[..header.value_len as usize])?;
+ Ok(XAttrValue::Buffer(header.value_len as usize))
+ }
+ None => {
+ let mut b: Vec<u8> = vec_with_capacity(header.value_len as usize)?;
+ self.read(&mut b)?;
+ Ok(XAttrValue::Vec(b))
+ }
+ },
+ Err(skip_err) => match skip_err {
+ SkipCmpError::NotEqual(nvalue) => {
+ self.skip(xattr_size - nvalue)?;
+ Err(ENODATA)
+ }
+ SkipCmpError::PosixError(e) => Err(e),
+ },
+ }
+ }
+ fn skip_xattr_value(&mut self, header: &XAttrEntryHeader) -> PosixResult<()> {
+ self.skip(
+ round!(
+ UP,
+ header.suffix_len as Off + header.value_len as Off,
+ size_of::<XAttrEntryHeader>() as Off
+ ) - header.suffix_len as Off,
+ )
+ }
+}
diff --git a/fs/erofs/rust/kinode.rs b/fs/erofs/rust/kinode.rs
index fac72bd8b6b3..a4bea228ddc0 100644
--- a/fs/erofs/rust/kinode.rs
+++ b/fs/erofs/rust/kinode.rs
@@ -11,6 +11,7 @@
use super::erofs_sys::errnos::*;
use super::erofs_sys::inode::*;
use super::erofs_sys::superblock::*;
+use super::erofs_sys::xattrs::*;
use super::erofs_sys::*;
extern "C" {
@@ -22,6 +23,7 @@
pub(crate) struct KernelInode {
pub(crate) info: MaybeUninit<InodeInfo>,
pub(crate) nid: MaybeUninit<Nid>,
+ pub(crate) shared_entries: MaybeUninit<XAttrSharedEntries>,
pub(crate) k_inode: MaybeUninit<inode>,
pub(crate) k_opaque: MaybeUninit<*mut c_void>,
}
@@ -31,6 +33,7 @@ fn new(_sb: &SuperBlock, _info: InodeInfo, _nid: Nid) -> Self {
Self {
info: MaybeUninit::uninit(),
nid: MaybeUninit::uninit(),
+ shared_entries: MaybeUninit::uninit(),
k_inode: MaybeUninit::uninit(),
k_opaque: MaybeUninit::uninit(),
}
@@ -41,6 +44,9 @@ fn nid(&self) -> Nid {
fn info(&self) -> &InodeInfo {
unsafe { self.info.assume_init_ref() }
}
+ fn xattrs_shared_entries(&self) -> &XAttrSharedEntries {
+ unsafe { self.shared_entries.assume_init_ref() }
+ }
}
pub(crate) struct KernelInodeCollection {
--
2.46.0
next prev parent reply other threads:[~2024-09-16 13:57 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-16 13:56 [RFC PATCH 00/24] erofs: introduce Rust implementation Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 01/24] erofs: lift up erofs_fill_inode to global Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 02/24] erofs: add superblock data structure in Rust Yiyang Wu
2024-09-16 17:55 ` Greg KH
2024-09-17 0:18 ` Gao Xiang
2024-09-17 5:34 ` Greg KH
2024-09-17 5:45 ` Gao Xiang
2024-09-17 5:27 ` Yiyang Wu
2024-09-17 5:39 ` Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 03/24] erofs: add Errno " Yiyang Wu
2024-09-16 17:51 ` Greg KH
2024-09-16 23:45 ` Gao Xiang
2024-09-20 2:49 ` [PATCH RESEND 0/1] rust: introduce declare_err! autogeneration Yiyang Wu
2024-09-20 2:49 ` [PATCH RESEND 1/1] rust: error: auto-generate error declarations Yiyang Wu
2024-09-20 2:57 ` [RFC PATCH 03/24] erofs: add Errno in Rust Yiyang Wu
2024-09-16 20:01 ` Gary Guo
2024-09-16 23:58 ` Gao Xiang
2024-09-19 13:45 ` Benno Lossin
2024-09-19 15:13 ` Gao Xiang
2024-09-19 19:36 ` Benno Lossin
2024-09-20 0:49 ` Gao Xiang
2024-09-21 8:37 ` Greg Kroah-Hartman
2024-09-21 9:29 ` Gao Xiang
2024-09-25 15:48 ` Ariel Miculas
2024-09-25 16:35 ` Gao Xiang
2024-09-25 21:45 ` Ariel Miculas
2024-09-26 0:40 ` Gao Xiang
2024-09-26 1:04 ` Gao Xiang
2024-09-26 8:10 ` Ariel Miculas
2024-09-26 8:25 ` Gao Xiang
2024-09-26 9:51 ` Ariel Miculas
2024-09-26 10:46 ` Gao Xiang
2024-09-26 11:01 ` Ariel Miculas
2024-09-26 11:05 ` Gao Xiang
2024-09-26 11:23 ` Gao Xiang
2024-09-26 12:50 ` Ariel Miculas
2024-09-27 2:18 ` Gao Xiang
2024-09-26 8:48 ` Gao Xiang
2024-09-16 13:56 ` [RFC PATCH 04/24] erofs: add xattrs data structure " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 05/24] erofs: add inode " Yiyang Wu
2024-09-18 13:04 ` [External Mail][RFC " Huang Jianan
2024-09-16 13:56 ` [RFC PATCH 06/24] erofs: add alloc_helper " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 07/24] erofs: add data abstraction " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 08/24] erofs: add device data structure " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 09/24] erofs: add continuous iterators " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 10/24] erofs: add device_infos implementation " Yiyang Wu
2024-09-21 9:44 ` Jianan Huang
2024-09-16 13:56 ` [RFC PATCH 11/24] erofs: add map data structure " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 12/24] erofs: add directory entry " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 13/24] erofs: add runtime filesystem and inode " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 14/24] erofs: add block mapping capability " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 15/24] erofs: add iter methods in filesystem " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 16/24] erofs: implement dir and inode operations " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 17/24] erofs: introduce Rust SBI to C Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 18/24] erofs: introduce iget alternative " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 19/24] erofs: introduce namei " Yiyang Wu
2024-09-16 17:08 ` Al Viro
2024-09-17 6:48 ` Yiyang Wu
2024-09-17 7:14 ` Gao Xiang
2024-09-17 7:31 ` Al Viro
2024-09-17 7:44 ` Al Viro
2024-09-17 8:08 ` Gao Xiang
2024-09-17 22:22 ` Al Viro
2024-09-17 8:06 ` Gao Xiang
2024-09-16 13:56 ` [RFC PATCH 20/24] erofs: introduce readdir " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 21/24] erofs: introduce erofs_map_blocks " Yiyang Wu
2024-09-16 13:56 ` [RFC PATCH 22/24] erofs: add skippable iters in Rust Yiyang Wu
2024-09-16 13:56 ` Yiyang Wu [this message]
2024-09-16 13:56 ` [RFC PATCH 24/24] erofs: introduce xattrs replacement to C Yiyang Wu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240916135634.98554-24-toolmanp@tlmp.cc \
--to=toolmanp@tlmp.cc \
--cc=linux-erofs@lists.ozlabs.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rust-for-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).