From patchwork Mon Sep 16 13:56:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805457 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4D9B5156F57; Mon, 16 Sep 2024 13:56:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495002; cv=none; b=tn0hSgVFUKf8dyEvfZ9tDTTCTM8ys2VskwNMIOguUcpCQxePOqnzuxZUYZ/l92ELUUxKnG40dNOz1PITOvdM1h/ZNKrYY6g23wPA+8f1eAoZkHGcZSp5A55QIFEFDfpqMZ0vU/MSOS0lrwF9Op7k6+dPaBYFCoWE+V9SrgjQNGw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495002; c=relaxed/simple; bh=82Pe3spVi8IHf0iaRSv2lTfetUa49rokuqEYMW7OxSA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I61giSfErZgswwK8kh2ff25Gb26Xxwvg4PHL1tZpP5Momy4fe9KlA1F+TIKzBtfIDNxRC5+E/73qu5J8OCG+SPv6ABFXVHvtB57MiM6cppW4lqrEVHJt5BIqEy8ThP8U0W37DVGhTiRjTORDSQ1o4rdDT+Fp6UEMZDIvaFXwAvs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=b/wTow6m; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="b/wTow6m" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 0B2F069839; Mon, 16 Sep 2024 09:56:38 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495000; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=wrfeI6c5Fy2/wr4QW/RT84D3Z/gYFwXLPq/0MCJKzS4=; b=b/wTow6mW0pOJ3SLs4zdqnSvHOdwRM0/wdgLDvfxyE4lsB8GyguL7sAgA+xYYDLNTmQihH 7ygxxN4fyFCXoJ+tUXTs4fVSdbyr0AqIv60ObsXlONL5RpEblVyzOlurHAcuGYpXMIPBnF XO/4Gk/f1Ptz3jGeS+dkc0aoqHc1RGiNYM6z5Tesui+jAGQLiGFs3Y+EHQCBSnq88FHD4c oOxVuvXQwUMfkOK3DTv4FbdHv+Cxmzv+c/7abQbrqbHDAbqRSglrwuRcUJwWO/Gi5S6GFT wzL8ysO2z7HjFBxJOG4sRxcCPECdkMxop4zKibbhekbjBeCxhuqNcLH9oGGRNw== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 01/24] erofs: lift up erofs_fill_inode to global Date: Mon, 16 Sep 2024 21:56:11 +0800 Message-ID: <20240916135634.98554-2-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Lift up erofs_fill_inode as a global symbol so that rust_helpers can use it for better compatibility. Signed-off-by: Yiyang Wu --- 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, From patchwork Mon Sep 16 13:56:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805458 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 69BD5157E61; Mon, 16 Sep 2024 13:56:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495005; cv=none; b=LzM6M/5g79cgiTNIM4vfZO9goXz8tnIe5Hmep/CxIJTXvI2/XWj7z1sc2QeG8bCAlWDTflI0/zCu+OWGtyKvctMLxu2Fvwh/ozIhXWW93570rsP8zhprTPnbOmnpmVtuXBWcAK29xQbTzOQx6yWa+cuEqxh+94gpqir+ml5FKmc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495005; c=relaxed/simple; bh=d/XOj0hoNuU9nqfS2fwNSQ1cJ90NqcO0hLBokdH7oBY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KhXMD1TjYJMbbZ9bweDnBT4z1cJ9rvZkjbrLBgsoLde1DuUR8h4ptj36c/EGU8xfpmGigtztSxiReWuFGQl7dRWISzi8fdloAnoLrDbXRxIIoDgwnZoSRbwBKFVbbvE0++eWfw3RwcGs2cXOlav8lDWOVWNWBtC5U9YyReCD5eU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=EXrdKMbP; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="EXrdKMbP" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 1A8176983D; Mon, 16 Sep 2024 09:56:40 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495002; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=eiSTaIp2oxZp3XntcBK5EeEI9ViTxMs6XcQ702Or/vY=; b=EXrdKMbPRSLWjUM9rpjDioPo1pyJcUduJGi9/DcPSUznc4+n3PK+QocMh5/3zd5PEb+T1I YRcB2n2fyzAcWZwwf1x8r2KQmlq6J4K5JQvfg4s+6GGtMZsBRkedc66rf1mDJIKEQ/X5hP pkDmgPNP4cuhtoSUWOoBzpATRGIYwu0Ik16Pm7SIcU03oydEj7wY68Y//2CZPg1pSF59FC lTGyi9FjWi9q1YWpDnxQiLyvRugQXGa5w2I4jlum9qaViG9tL16UoCpoEL+oezba+vps0Q dBRUkamfzg3bffUqyoJzfRAhdgDJB7KyE0fXR+BcuA1OYY5yVbxV72L5+vAJ8Q== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 02/24] erofs: add superblock data structure in Rust Date: Mon, 16 Sep 2024 21:56:12 +0800 Message-ID: <20240916135634.98554-3-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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 { + 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::()]; +pub(crate) const SUPERBLOCK_EMPTY_BUF: SuperBlockBuf = [0; size_of::()]; + +/// 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; From patchwork Mon Sep 16 13:56:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805459 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4FF80158DDD; Mon, 16 Sep 2024 13:56:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495006; cv=none; b=OFMnZR+mRS5vuJZUVUpg0PzYR9MYvbAGbkkhU6/nYSTGZI+7ncz4XN6Tg2YhrETDutSvnU/T+WYI+/Oj4lFWLEOMV1XpmK8seFjYWuxwLoiG9f71Rbk8mtZVrN2CFeXrtqPpZSzz1hBcIrQuTCcSpm1AMhYsgTXkSsnRCuTHsdE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495006; c=relaxed/simple; bh=vQLgpg+Uh6AnmzozA6msIhCQdsV7m8apo306xrKuq7U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hG+pziZRATBw/fFMTk/CMp2Jw/g/RHd0BBPEZtlGhRQzJMidWQoxh+TAa8Q2EOlFjiXiWn7sYapR6aKHiqyXpO05bxre8foJFG12pkDzr//JDDkea3bwTzy6ahGy37Ou352MP/64zSmZbY/0ujNymEgFaAxFwV+dwCMucdJOnEw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=dOn95zGg; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="dOn95zGg" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 2BDBE697C4; Mon, 16 Sep 2024 09:56:42 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495004; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=ZuP3bujGZDBP75xkwLAFw1ksH6b/fY1knDKclkC/wOs=; b=dOn95zGgGjKt7hhDZ/QhlPGv4twioBTmFU8v4vBHGWJjuHNLqPrYPL1TRlgHiKOGVaANQe Q0ROqoKukjjsVleRpzwOv+M7aNYBZRAMuyhTCCVsvncV2qitG3sEcIAOC5FbD4LxPgTSr1 kj7IJZ/E1PaonivKJ/WYVOMJZ+QNtxCmx/M9iQjZAcaMlEO3CR86kj96DHe38DrIGRYCq5 /Zf4JCwL7D2AkvHRjDTRe1hAnf9csJZ0ASj/QLPGQaINfa9Ad3DGhLlGEOwoWRoZROPghe nO8XCSuw9cTM4FiRSldvUDIf/mgPCQirncjyff85I72LFQqoEMwkpQ7DFIULXw== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 03/24] erofs: add Errno in Rust Date: Mon, 16 Sep 2024 21:56:13 +0800 Message-ID: <20240916135634.98554-4-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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 = Result; + +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 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 for i32 { + fn from(value: Errno) -> Self { + -(value as i32) + } +} + +/// Replacement for ERR_PTR in Linux Kernel. +impl From 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 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 +} From patchwork Mon Sep 16 13:56:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805460 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 268C91598EE; Mon, 16 Sep 2024 13:56:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495008; cv=none; b=Mr8UKBBoZlJUqmKnaw78UO6BKXeoFNSi5Lkd7PRgOzfg86gRxxkvOeli2bXuNFk6fmv+56tDKX1c9p0zXI6q90Plo+37XhpBWXEA660b5o8pCa5iwd9/UX7m1iCsd3Y3ino4pBer3/ZRGKuNsSJGM/jXTDy/jcNXt9ajkuYsLZ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495008; c=relaxed/simple; bh=T87qpgWUFMOH9vDZIIusulZhnKGgYdYoqiUWGJAD3JA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W0EPds3ZZJSnLglVw1LjiifZPYVNWFF30LrLRKSasuqOIEswqmv/hP5D57wT1M/pCFflwiRnAVRmug0GZssjwW3NLprm2jcNND4CQR0HPI3oQPVjI7EHZIHb+jZz2zILBlFIhOhWS/F20PASoclhk2Kqy9coSnbdfJtdw+e+ixw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=hMZLfuz+; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="hMZLfuz+" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 1A48569845; Mon, 16 Sep 2024 09:56:44 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495006; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=eYDsY4wqAO9NUWwayzJIYghS8a27BSxppsolaWA5lxs=; b=hMZLfuz+nzJ0b6NMqN/03JZBQ3BFcQ4AI/0MLge1ZfqiOD2kbyf35nTCJBxIzbnPeiRDjE nxyk31w8mGG0xDkJTUYl5NJgnnHcxatIUOQE3L9ZAvMgK582501s7ggAxJxtJ/+Yb9wBwU siG/Xy6r+u0CCcZUhYDIQgr9yHsOvstInV+BzE7j3BGytCQN1Mc7AS5+fIDbevxDRLkW8W DPwjegcm9Zsrg+6VcIpzt7jyphg9tvoU4xBwY2MayUAIJt2v7CTocYDaRMdU8F668wH9u7 h9+9JHR/tT7GhX7aqjrAz/0LI0QIMWqcDF4xXIA58gbGkS2A3orsyImH1dbabQ== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 04/24] erofs: add xattrs data structure in Rust Date: Mon, 16 Sep 2024 21:56:14 +0800 Message-ID: <20240916135634.98554-5-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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, +} + +/// Represents the name index for infixes or prefixes. +#[repr(C)] +#[derive(Clone, Copy)] +pub(crate) struct XattrNameIndex(u8); + +impl core::cmp::PartialEq 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 for XattrNameIndex { + fn from(value: u8) -> Self { + Self(value) + } +} + +#[allow(clippy::from_over_into)] +impl Into 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); + +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), +} From patchwork Mon Sep 16 13:56:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805461 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5350215AD96; Mon, 16 Sep 2024 13:56:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495011; cv=none; b=oBKRJPFMkCd9djlkKKx/g5hQ/QOywSAyROIk4HE6zemSAZsEoB062OFhTruQcRXIvNTjINMzo2BEBjWZeTs+urrDjBuuVCZqfD4LiQ0QN8dy4lhHtoDH6dv+/kkydsflfycJb4c0Ad1PS28wajBBZj8kZl7Gd7GWq+uTU85csBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495011; c=relaxed/simple; bh=+GE0m90lwhlb9OljwVtEQsDCa+zy3VtJ1xGQMp1f3Pc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LiC7jHtUnRY+vqz9NuQlC/4NSiswY6CTVdp1yQDDfucpN3CD0++AGQIuJXHh87A7/kNlw8Ptin6gsZqqdTbMA9QHfXDqWji0Y2SKGONV6iSaqW17n7JeAFdfOB25p0N9XZkf8OlCcF6eGVR5FNer/KIAl7hxFxwq9IThO6yPX40= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=h2GVWAST; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="h2GVWAST" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 142B66984E; Mon, 16 Sep 2024 09:56:46 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495008; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=3lB7vMUDAoeBGlHx0db3VH42iw8zhtpQjBkF7LrP3EU=; b=h2GVWASTJojpiXbZ3KpUm3pheSuuyx/JanOK1t7Ybvtvqmp3+KVE1DHEHRd0TFyN9fhgMp eUGeq008fBE+5C6wnxcZwwHN4ZBKplzgWbF95ymWTg3duKL92DzWAWc9UQqApkWQvuIDeG gg2jXnIPZf3GVARjUk/HXee5uTZ+pwWgFF0XvcGOhX+a3z8grxTrGDfo1IlBv4JhszOb+L baOaTpLxv6kdiDcpeAXPDCvVeXliIEnvtZ8y43PCjjHeEu5g4qhZa8mM4IpiAr0KMLndQg Mj5u6MYFpRjxuY0Cd6hoVsshWsKiTe+Hb18JdsoOV0p+Lwa5JErTZ2bUO883uA== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 05/24] erofs: add inode data structure in Rust Date: Mon, 16 Sep 2024 21:56:15 +0800 Message-ID: <20240916135634.98554-6-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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 = Result; 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::() as Off + + (size_of::() 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::()]; +pub(crate) type ExtendedInodeInfoBuf = [u8; size_of::()]; +pub(crate) const DEFAULT_INODE_BUF: ExtendedInodeInfoBuf = [0; size_of::()]; From patchwork Mon Sep 16 13:56:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805462 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C54D615B0F4; Mon, 16 Sep 2024 13:56:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495012; cv=none; b=Hwaj8ezTxt5IhdkJ+NFOLNE2t7yIysoKwzUl9qLIRLLhm24D8ntUcxgbnbGDd2BJQCJ5EI3d0wMc0l504NGb7hSyRurIVStN6S4cpvvHDKdWMccG4dq5ouejfKtfDbZ2HfRUTq4QtOYGCF05Rdwt0blDwBPuFX6si1Q9zFhWr3A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495012; c=relaxed/simple; bh=nfHK1i9ph1376F4QA3EYzyMqATO930veypDKTSAKBl4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B6/kqnubb0suw2PX8g5Vd0mrvYfCXLbpUwu363n/7u1V2/YZMOZjL0tVz5xby45zDRmYUnmRoPMPohxDnsdWb6GVSBCYPlErjudTNe+VjidekaRcwMzxOkfvdEN6FTS5BxSK62avA508fZDZgBo7OJ6IVZDcgkcLl9v2FwGubX8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=hYA3YLAk; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="hYA3YLAk" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 0652F698D9; Mon, 16 Sep 2024 09:56:48 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495010; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=fUBtB1guKBDyxePSsjzX2NyUyWv+dPs0ZXuq7FSRkmE=; b=hYA3YLAkGlfGNv/YjBVf4oINn07DQc3ryRFl4VhpDnrr268EyrbbQwq3nScNcWl/lTLpCV sIneI5zNeXEbBT1RHindRWghQsNWkOduHtBUjELOArq/fRqh05I0eYuCd+ConAUC3+Cur/ V9on9OFM7by6VA9r6e+0CiQ2pqw7hNTDw2ejivQ8nZkqca29/K+50uFeO+59pg0azjc45y x/4xqKbVSXeFDMPj+ZI5gnulA1qGKDbK1FSdH8gfuCOhO9p9dLLV+T1MHsaMuSI51Orc+k ZUpEWSINDnW/xapVt8YxlBpq3mlTF+2T73Rj0Z+UChcyVuqtZ5OAAVmvVpoSWg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 06/24] erofs: add alloc_helper in Rust Date: Mon, 16 Sep 2024 21:56:16 +0800 Message-ID: <20240916135634.98554-7-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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 = Result; +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(v: &mut Vec, value: T) -> PosixResult<()> { + v.push(value, GFP_KERNEL) + .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(())) +} + +pub(crate) fn extend_from_slice(v: &mut Vec, slice: &[T]) -> PosixResult<()> { + v.extend_from_slice(slice, GFP_KERNEL) + .map_or_else(|_| Err(Errno::ENOMEM), |_| Ok(())) +} + +pub(crate) fn heap_alloc(value: T) -> PosixResult> { + Box::new(value, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v)) +} + +pub(crate) fn vec_with_capacity(capacity: usize) -> PosixResult> { + Vec::with_capacity(capacity, GFP_KERNEL).map_or_else(|_| Err(Errno::ENOMEM), |v| Ok(v)) +} From patchwork Mon Sep 16 13:56:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805463 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 019BD15B54E; Mon, 16 Sep 2024 13:56:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495014; cv=none; b=gNFiS4/ENmVqZ712RBkXz+iNgLwjht8RV5kgYtL0rPrne3fTqJr0bncUL97mGdEauKNJeUwMvIoEOJ9m/2ehIKBWyMMc5G1h5asK0LgxosXBjQHjgi6tggvNPZVl0k+4c9OdgMsQ97twtJ1j4zb7trCVzCAuNvcBYIvrp7mkkvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495014; c=relaxed/simple; bh=H9qZQ6sPOX6lomGbiY5NWabke+KIbETnJDwauhJvUys=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bf2Qm/wf7pQlIrcSpez4YWgjOvyRZy3OftaQf0H6tqj+S7BS+4k9HxO+1WHEcX4CYBkdG8xyjCVjH5J5uDywTKivqM/J/EgHQ+5ZaJbBWPbSiclGhVjRs0HmIOnltWw0fdgEDaAPniY2N5ZjDyJwnxguPcRJg+BK/gjIAmhvN1E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=LAMjNb0+; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="LAMjNb0+" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id DE5A469845; Mon, 16 Sep 2024 09:56:50 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495012; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=RkMMOXQTsmanQe52UgGZbvf6dLNC+ICFQfOIzTuSzMo=; b=LAMjNb0+UX4m/k3RsK6wT8HZizF4XRS4pWMkT3XIpMeyZODYVcCr/cX08ee6ki7sDofY8K wKyFuPiNDpIQv6dZXjCjd5/Mgb49MBfsF8oeaD7EpIq9Pk56a8U9P8wq47/FNco/Q4rNMC gayBmAMNRRRiqDIDvPo8PkkGYrkJ2mK0SilBw3emy2ULWn07fEFQE4vAxkahSmLGK37N0o 8nswnBd+Oe/o8El8ukDg+Xy2DL1Nb7CMMly5UVuoHsol4D4Qce6LsbTd1/07PST8V3e2K9 OYrMX0k7gIOgqGTpau4Pb4C0vsm56chcwnIDNyJs7NLLD/lHWXEq+52xoKY2ww== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 07/24] erofs: add data abstraction in Rust Date: Mon, 16 Sep 2024 21:56:17 +0800 Message-ID: <20240916135634.98554-8-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Introduce Buffer, Source, Backend traits. Implement Uncompressed Backend and RefBuffer to be used in future data operations. Signed-off-by: Yiyang Wu --- 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 = Result; 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; + fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult>; +} + +/// 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; + fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult>; +} + +/// 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 +where + T: Source, +{ + source: T, +} + +impl Backend for UncompressedBackend +where + T: Source, +{ + fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult { + self.source.fill(data, offset) + } + + fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult> { + self.source.as_buf(offset, len) + } +} + +impl UncompressedBackend { + pub(crate) fn new(source: T) -> Self { + Self { source } + } +} + +impl From for UncompressedBackend +where + T: Source, +{ + fn from(value: T) -> Self { + Self::new(value) + } +} From patchwork Mon Sep 16 13:56:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805464 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 186F015C128; Mon, 16 Sep 2024 13:56:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495016; cv=none; b=boYl/+neym6MGFtvdaq2Ym361Md9g9nmma9FtvG68PPtnNR85UzVRkRvNyhFiu+9C6D10s52K4dAXU1TVxco6VBiFInGySy3YZDZMIh20lV1LlwFooOI0JQQb0AJVC+Xn0agvrsKNssr6UnALxVg88iorvNddxFrv/IUw9fh7aM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495016; c=relaxed/simple; bh=0c66dwnUGs7UBAhZ/nX2CQVs5yJOB4tBeg1XqoqkzKE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CRFsmY+zPPURyWhXLeysYX+dPvsEuGBZJNWvvgADUZgRDxOhnKyevPd15eGblgnwZhQ79uLirzoNAvX0pDMir0tihZ11eVOrPMD1M6gMlPES0I1ETf8a0NjnRfMGPjo0SDRpcv2A+qJaR9WCPtSo4Xz72pfH+s22zlQlVYXK8I0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=gntO7RG+; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="gntO7RG+" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D356F697C4; Mon, 16 Sep 2024 09:56:52 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495014; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=RpwAvNBL1BrrWM3+ylO6h2C6ZxDk5XDbbYWzUi+PA6A=; b=gntO7RG+naT7UAbmN9YrOU7lFOnX6O7m9wdBElz71oXY/SvrFQPdgeh91hNsJqCtn6pwy4 50ZUtxmlhVTf5oHnbw9y3C35Twg+2gajp9ksrcy777rB/12VpaL3VeI1voDg2npj+iyKUP uZT1Bt+vRqHJft7wmTCzNk6IW9qlTpu/oUGSFnEBM2Z+2YDAbQc9pFBxtn/nqVS1PDSMHG VRUdsVTxGTiUZ9I5Tc5kEbPwyBGnhzauQanUdZXaQB8xpL53OheHsEcVQIFviGCznCDSX9 8iv9jVzAoYzTupEffpGl6bB0lSLXlJbrLfjayGtXQYCJT6jEEi4JozVGHjRHyg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 08/24] erofs: add device data structure in Rust Date: Mon, 16 Sep 2024 21:56:18 +0800 Message-ID: <20240916135634.98554-9-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduce device data structure in Rust. It can later support chunk based block maps. Signed-off-by: Yiyang Wu --- 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, +} From patchwork Mon Sep 16 13:56:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805465 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CCE7515CD4A; Mon, 16 Sep 2024 13:56:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495018; cv=none; b=AohSeG95OCS2slzLcp6+nMudB5RxACvLNlMf3VenxJcyEHUesnE6+KcvkDHiE5CB95APv9p6EtcYYgo8W7UOJFvMAgY6cKIiXR6l2UoDK519b2sEmRAZYSS0gleHrh8Z22nPzVliqY1vnuuoi8dbPvUe8PJXk96gvDAJe1NNa8Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495018; c=relaxed/simple; bh=C6bzJ0ahOVi4Lz5NDHXNa2g12EqOHhJgzseFPgoTZoI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AT/RfU86s52CG39tUb7OuStpSihueosk/sPG3SRf1ctvBWWCTFuL9jTyOojfkxl4eRKsMZa3brKHTerxAjOv/DZReIS6Zovww2ggCBN/uymnhsBv7QsbbWrpYHBDXogW1Q+y8FgQYk1Mk5V5dDfSwvA4EcJ8BMft8tmc39Kf25k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=OI84jiwE; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="OI84jiwE" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C2F7F6984E; Mon, 16 Sep 2024 09:56:54 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495016; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=CeM2RxQ3ayEheLUMCn9fl9h9UhYePHokORV1b9tMe8Y=; b=OI84jiwEAZ7ZEOLluM+fIqX1Srps1RtOtX3VqfVlm4NGXwfbaD373VS/xNCdDmM/hiGYDZ OHX/N0Vj2xsYcLKNElDkLkxxhMbOocc0YXu8NiK8WHl784LfdiZ3VeREs4qZgrGs6gcrCr 5SQ4cQOXbMAAWxSGTv6DB9kQD61+qf/9K9eBUDSMatJxLDWSaO4VsSF76v9Rj5+M+tvaEZ uvJYeTYhvh+ddlt/XjZ447m9WCXe1xX/gZKjvoJKGVc4+fL9qq5n35kSNdvH/dj/Xrf2Ni xyAHcPUesRUNe95B9viv+6x83gLqH4DrrdC8RgHWYKqQZy13ntEZzFiynr/o2g== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 09/24] erofs: add continuous iterators in Rust Date: Mon, 16 Sep 2024 21:56:19 +0800 Message-ID: <20240916135634.98554-10-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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>; + fn next(&mut self) -> Option { + 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.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>> +{ + fn advance_off(&mut self, offset: Off); + fn eof(&self) -> bool; +} From patchwork Mon Sep 16 13:56:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805466 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8306B15DBD5; Mon, 16 Sep 2024 13:56:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495019; cv=none; b=OxlZ0lP6tdks5EOD6jE3OJqXKeOokZ+oWPckfLhPE9VFE+xS+A0nvRNOt2w31zIM8Ic05VDGCXzb/08n9VlVBOhSXc2WzE6eO72SM5VfJ5KTkhSzG81Qn4iY4nVlAcoZzhQ+mmoxx0BioFV/0wTjGNRDCvzf8GwJoNh4UUmZhd4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495019; c=relaxed/simple; bh=C1ZrNRNACCjWx55UqgSqRNkayTakd+sKpVAO9zBzvsI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UJiENmube0xBvHem3HvNBUe8QGEn3X0RK7f+LXEsCQ17nUwHhnsadSM/pJALmj4F79LogF1FN1yd+IVN5LW48jaauvMSlBZvKsraKYKkiG7Svx2zd9AK2ltpAmA8W2J1ifJGJAOmsKugzjvM9l8M8W/EthcHZtYr4ldzL3vmEmY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=XH3Ah7t4; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="XH3Ah7t4" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id A8826697C4; Mon, 16 Sep 2024 09:56:56 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495017; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=TBJTDvYko+/iIPJGn9oa9UFP8352ieqw0qlVnvGk9ME=; b=XH3Ah7t4SBLcqo+8KnSh3HxrmkPHlBuTAmP7b3h1yVUBwKksZ+Ubxa+W/3dK8WnR4GYFaL fBCj01ajrvkvrX08TAB+rwGc3lzQOezj1NI79z0vMMGUJEwwQ+6JxMT1zql4dCuUD1+xSw qI7Wmb8+Jyi+AP/kSlIrKORBBr2mQDOefsvGjp3DK3MWPdi7fu1UboTPapiwZiZQ25hgF8 aYe8WwCKZ3wOx+zqwq2vMNlaA8q0ldf3rwl8aiGiwQ4AKIGttuOZjn6mhE3QEfT51kJGdB cNsjRcklTvhCC9480oSqXyWn7Z7wLyCQR4JjeKroaq8Cg2hZK2UfxOP0StKvZg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 10/24] erofs: add device_infos implementation in Rust Date: Mon, 16 Sep 2024 21:56:20 +0800 Message-ID: <20240916135634.98554-11-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 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 --- 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, } + +pub(crate) fn get_device_infos<'a>( + iter: &mut (dyn ContinuousBufferIter<'a> + 'a), +) -> PosixResult { + 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 }) +} From patchwork Mon Sep 16 13:56:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805467 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54199161311; Mon, 16 Sep 2024 13:57:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495021; cv=none; b=GnQC4X4oW5Bi5IotDC9Klg/J+Q9kPbdGJEsqY+JWKaHri5xA85fzXTVxOq8VW9p6CVmFaNGMe3dq1Ad8kSBP5pjhaGqBc5D2dlp1fMrcp+IVRI98nPgf2dCTO+BN7aIVWANpHePb2UnGQ/wita1FmUz0m4KDbXhT4iN1Za7z27A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495021; c=relaxed/simple; bh=zTenHNDq1t83FwjgBfBRxwlMMD2Xhmw6ZkqOIIf8dik=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L3rWgRXU8qbRkNKNX5tQAyL13erKjvPz4QOX5WZEzarRzdtp2qg2hK92jjD+xu9syzqBXR6UhsRYQY5PQw/1OpfD3qpSRijuCm+q7kkgbWQZULolPdwusy/M0jM3l/KJr7P6PCW/rTrI0xyRkimHDP2p78O8pgqjwNzNvseZLUo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=CFSckmI4; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="CFSckmI4" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 93C2F69845; Mon, 16 Sep 2024 09:56:58 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495019; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=F4hCBD/QFnbrfenytYFFJtYuvUkCDWy+jx5tXlowPUM=; b=CFSckmI4MUIPR9slBm8hO8DjCiZn8m3HjPaYgOVerbk8DEmUgIw9uVE85dm47JHVK0OQRI 7MYVXmNEFJPIsUqwcQSjbSDy9kw0KiMRFJI3H8Sz5YX+L+ej0GwV0nO3CoNFUn3k5VxnSK 8qCd3dKrDlY0aHo/90jKK/JJPfpi9WEFuS6Fy7eBnf38yI19S8LRwlIX6JVJJdAEHoKHDN WxP4HdUszJkuV08+XnKywMarGNMRm+QUOaaHev8dWlo5IcOJ8vIVc95+MfymXlzX/NKIvu K74GHUrHa3tW2dGbB7fbdK7GPji0+dCARhAzmPwA7yOy8HCN76mzygKk7gA5YA== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 11/24] erofs: add map data structure in Rust Date: Mon, 16 Sep 2024 21:56:21 +0800 Message-ID: <20240916135634.98554-12-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduce core map flags and runtime map data structure in Rust. This will later be used to do iomapping. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys.rs | 1 + fs/erofs/rust/erofs_sys/map.rs | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 fs/erofs/rust/erofs_sys/map.rs diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs index f1a1e491caec..15ed65866097 100644 --- a/fs/erofs/rust/erofs_sys.rs +++ b/fs/erofs/rust/erofs_sys.rs @@ -28,6 +28,7 @@ pub(crate) mod devices; pub(crate) mod errnos; pub(crate) mod inode; +pub(crate) mod map; pub(crate) mod superblock; pub(crate) mod xattrs; pub(crate) use errnos::Errno; diff --git a/fs/erofs/rust/erofs_sys/map.rs b/fs/erofs/rust/erofs_sys/map.rs new file mode 100644 index 000000000000..757e8083c8f1 --- /dev/null +++ b/fs/erofs/rust/erofs_sys/map.rs @@ -0,0 +1,45 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use super::*; +pub(crate) const MAP_MAPPED: u32 = 0x0001; +pub(crate) const MAP_META: u32 = 0x0002; +pub(crate) const MAP_ENCODED: u32 = 0x0004; +pub(crate) const MAP_FULL_MAPPED: u32 = 0x0008; +pub(crate) const MAP_FRAGMENT: u32 = 0x0010; +pub(crate) const MAP_PARTIAL_REF: u32 = 0x0020; + +#[derive(Debug, Default)] +#[repr(C)] +pub(crate) struct Segment { + pub(crate) start: Off, + pub(crate) len: Off, +} + +#[derive(Debug, Default)] +#[repr(C)] +pub(crate) struct Map { + pub(crate) logical: Segment, + pub(crate) physical: Segment, + pub(crate) device_id: u16, + pub(crate) algorithm_format: u16, + pub(crate) map_type: MapType, +} + +#[derive(Debug, Default)] +pub(crate) enum MapType { + Meta, + #[default] + Normal, +} + +impl From for u32 { + fn from(value: MapType) -> Self { + match value { + MapType::Meta => MAP_META | MAP_MAPPED, + MapType::Normal => MAP_MAPPED, + } + } +} + +pub(crate) type MapResult = PosixResult; From patchwork Mon Sep 16 13:56:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805468 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F4001662F7; Mon, 16 Sep 2024 13:57:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495023; cv=none; b=vCImqFP9q0CiTTYTK5CsdNLXhZXrWu2gX2KIwy84Ypt3xJ8turF+6OFfzLN3l62/8fOW2uqRoOh6dAtGGHC2EYRehqnDyoo2n2M2TnJtYL0LvBvf4CdphjZ7IX/6RpYksgw2BBe+0UTyWaeHqdcE3K/1VzHDdQwu8aDv/ql+Xk0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495023; c=relaxed/simple; bh=r1kk9No5ipZSuvASJgNj7Q/8wv6E1PJMOtbpvnAfHEM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WyhOlCTXA5zqCdZrR4+S9kkL3iHM03LYV8ND8sQeeXrX76dh2ecjIsCJSi1P1wy6IB0Gcv+rzu5hddq66RqOUHUDNrC2EvMP9W8wD9QOLlfzhXuEmQx4wapKPNmpSZox81GZin4gfh++JYi+Pr5GKnM45+d3bXxW2w2p+Lcac7M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=JzgW3RT9; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="JzgW3RT9" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 76A4A697C4; Mon, 16 Sep 2024 09:57:00 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495021; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=aIuZG5PEljHDXPUlgWsVRtI4LVnRy+jfg4KsDBMADu4=; b=JzgW3RT9D4Z5Zx0GeV99WrpnWZLJKf6cD4UwQVruHRKjSt1IWDApdXssW522GAGu85TKJE szMUzWXMfWY4d+6AlArsH21f89D7DGFxIvxS/ynohg2VJN7VbuRLb3s9z6GsTSDB9k9tyY SxKljzY3Y8TrYD8aWuprNrCBpCZ6u5Ph/OdJ3hcLwdUnBO2mN6/rjkCh95g2TIXSUJIoQd QtMVozhUxBW1K0sVzTjCtcYV1bQz0R9qzMPS6+GcsCH5guI40E/ucfP7+HzmeppU8W5pDA nEfyy0mEsmcOhPs3p0CpuD1N6FYdbonSJ4n1spG/+ncP73znZUy0DRoF4cblwg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 12/24] erofs: add directory entry data structure in Rust Date: Mon, 16 Sep 2024 21:56:22 +0800 Message-ID: <20240916135634.98554-13-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch adds DirentDesc and DirCollection in Rust. It will later be used as helper to read_dir and lookup operations. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys.rs | 1 + fs/erofs/rust/erofs_sys/dir.rs | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 fs/erofs/rust/erofs_sys/dir.rs diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs index 15ed65866097..65dc563986c3 100644 --- a/fs/erofs/rust/erofs_sys.rs +++ b/fs/erofs/rust/erofs_sys.rs @@ -26,6 +26,7 @@ pub(crate) mod alloc_helper; pub(crate) mod data; pub(crate) mod devices; +pub(crate) mod dir; pub(crate) mod errnos; pub(crate) mod inode; pub(crate) mod map; diff --git a/fs/erofs/rust/erofs_sys/dir.rs b/fs/erofs/rust/erofs_sys/dir.rs new file mode 100644 index 000000000000..d4255582b7c0 --- /dev/null +++ b/fs/erofs/rust/erofs_sys/dir.rs @@ -0,0 +1,98 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +/// On-disk Directory Descriptor Format for EROFS +/// Documented on [EROFS Directory](https://erofs.docs.kernel.org/en/latest/core_ondisk.html#directories) +use core::mem::size_of; + +#[repr(C, packed)] +#[derive(Debug, Clone, Copy)] +pub(crate) struct DirentDesc { + pub(crate) nid: u64, + pub(crate) nameoff: u16, + pub(crate) file_type: u8, + pub(crate) reserved: u8, +} + +/// In memory representation of a real directory entry. +#[derive(Debug, Clone, Copy)] +pub(crate) struct Dirent<'a> { + pub(crate) desc: DirentDesc, + pub(crate) name: &'a [u8], +} + +impl From<[u8; size_of::()]> for DirentDesc { + fn from(data: [u8; size_of::()]) -> Self { + Self { + nid: u64::from_le_bytes([ + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], + ]), + nameoff: u16::from_le_bytes([data[8], data[9]]), + file_type: data[10], + reserved: data[11], + } + } +} + +/// Create a collection of directory entries from a buffer. +/// This is a helper struct to iterate over directory entries. +pub(crate) struct DirCollection<'a> { + data: &'a [u8], + offset: usize, + total: usize, +} + +impl<'a> DirCollection<'a> { + pub(crate) fn new(buffer: &'a [u8]) -> Self { + let desc: &DirentDesc = unsafe { &*(buffer.as_ptr() as *const DirentDesc) }; + Self { + data: buffer, + offset: 0, + total: desc.nameoff as usize / core::mem::size_of::(), + } + } + pub(crate) fn dirent(&self, index: usize) -> Option> { + let descs: &'a [[u8; size_of::()]] = + unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.total) }; + if index >= self.total { + None + } else if index == self.total - 1 { + let desc = DirentDesc::from(descs[index]); + let len = self.data.len() - desc.nameoff as usize; + Some(Dirent { + desc, + name: &self.data[desc.nameoff as usize..(desc.nameoff as usize) + len], + }) + } else { + let desc = DirentDesc::from(descs[index]); + let next_desc = DirentDesc::from(descs[index + 1]); + let len = (next_desc.nameoff - desc.nameoff) as usize; + Some(Dirent { + desc, + name: &self.data[desc.nameoff as usize..(desc.nameoff as usize) + len], + }) + } + } + pub(crate) fn skip_dir(&mut self, offset: usize) { + self.offset += offset; + } + pub(crate) fn total(&self) -> usize { + self.total + } +} + +impl<'a> Iterator for DirCollection<'a> { + type Item = Dirent<'a>; + fn next(&mut self) -> Option { + self.dirent(self.offset).map(|x| { + self.offset += 1; + x + }) + } +} + +impl<'a> Dirent<'a> { + pub(crate) fn dirname(&self) -> &'a [u8] { + self.name + } +} From patchwork Mon Sep 16 13:56:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805469 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CD398161311; Mon, 16 Sep 2024 13:57:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495026; cv=none; b=eVweZvUTroDPXHrfQ9eDp1yrkJ+JIhi0uexI6SCcMxLZw9N6w+yCuKk1Pec4kS/IE2jSuxPlT9t6faV2Drv0wMUo1CNvBG0fExpfK/QbEIKgMuzxd35a2espDDeLfrX8qZ2pKt/JCnEWoL/JefOPlcSwzCRZbaHNPiOVwSY5t4w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495026; c=relaxed/simple; bh=thAKuJKPAaj7I8jAuK8ni1T0YwtD+G1RkQ1emCE4WFk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LCgrSwNqr5LfPik8IfcB0muz1r9YOpHWU/h+mJ3N40aYB4ib98BA1H8e/s4tMiHhKRhPRgGRXq9Jzp6gLnGhsv4+nBx/lWBa6QTpMjivSM5pweoSwLzHY1Gg//s0XBCrQ9Oltpr4AGvQcYk1qz7pTUEGpDTDprEoVi7JdKPmzyI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=iyxMeTP5; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="iyxMeTP5" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 8F3BE69845; Mon, 16 Sep 2024 09:57:02 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495023; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=oxWofg5jFESfQHz5d/1PUd3uyHaReZ7JPHv+SO4oHUc=; b=iyxMeTP5+BeKjggayRCKmeQUH2EEpYvSo6si5ckLvAx3IFNHLw9orOVtF/5k9sS1xTNxP2 xDg5HPPzRtAT4f5oSlGe3pFT7hCBW3swBEWilBYcGsnmbIqlpBj5QzD4B7EQPiKLPAdwGE aBNbuB4H6TdmePHGOvjutbgLPqxk5ZxDXU4Po9tQpNl6esC99WbYe1JDaBNF+UQkdsz301 otoIKDnWnHIMjIdTFeZJgV+9aZjoilrigqC/p9w/+sMU4YFPjjUhpsgpePnxXlEwgYo/8P C/yC5mX36jvzDdpoAP1Ml6convjyt8zt/rmEWxaujFcYHc8WW1/PtFreMWBCfg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 13/24] erofs: add runtime filesystem and inode in Rust Date: Mon, 16 Sep 2024 21:56:23 +0800 Message-ID: <20240916135634.98554-14-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces Filesystem Trait and Inode trait in Rust. It also implements a memory backed filesystem in Rust which can be later hooks up the metabuf system in erofs. This patch also comes with a InodeCollection trait which can be later be hooked up with the iget5_locked. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys.rs | 2 +- fs/erofs/rust/erofs_sys/inode.rs | 106 ++++++++++++++++++++++ fs/erofs/rust/erofs_sys/superblock.rs | 42 ++++++++- fs/erofs/rust/erofs_sys/superblock/mem.rs | 61 +++++++++++++ 4 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 fs/erofs/rust/erofs_sys/superblock/mem.rs diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs index 65dc563986c3..20c0aa81a800 100644 --- a/fs/erofs/rust/erofs_sys.rs +++ b/fs/erofs/rust/erofs_sys.rs @@ -32,7 +32,7 @@ pub(crate) mod map; pub(crate) mod superblock; pub(crate) mod xattrs; -pub(crate) use errnos::Errno; +pub(crate) use errnos::{Errno, Errno::*}; /// Helper macro to round up or down a number. #[macro_export] diff --git a/fs/erofs/rust/erofs_sys/inode.rs b/fs/erofs/rust/erofs_sys/inode.rs index 1762023e97f8..1ecd6147a126 100644 --- a/fs/erofs/rust/erofs_sys/inode.rs +++ b/fs/erofs/rust/erofs_sys/inode.rs @@ -1,3 +1,7 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use super::superblock::*; use super::xattrs::*; use super::*; use core::ffi::*; @@ -289,3 +293,105 @@ pub(crate) fn xattr_count(&self) -> u16 { pub(crate) type CompactInodeInfoBuf = [u8; size_of::()]; pub(crate) type ExtendedInodeInfoBuf = [u8; size_of::()]; pub(crate) const DEFAULT_INODE_BUF: ExtendedInodeInfoBuf = [0; size_of::()]; + +/// The inode trait which represents the inode in the filesystem. +pub(crate) trait Inode: Sized { + fn new(_sb: &SuperBlock, info: InodeInfo, nid: Nid) -> Self; + fn info(&self) -> &InodeInfo; + fn nid(&self) -> Nid; +} + +/// Represents the error which occurs when trying to convert the inode. +#[derive(Debug)] +pub(crate) enum InodeError { + VersionError, + PosixError(Errno), +} + +impl TryFrom for CompactInodeInfo { + type Error = InodeError; + fn try_from(value: CompactInodeInfoBuf) -> Result { + let inode: CompactInodeInfo = Self { + i_format: Format(u16::from_le_bytes([value[0], value[1]])), + i_xattr_icount: u16::from_le_bytes([value[2], value[3]]), + i_mode: u16::from_le_bytes([value[4], value[5]]), + i_nlink: u16::from_le_bytes([value[6], value[7]]), + i_size: u32::from_le_bytes([value[8], value[9], value[10], value[11]]), + i_reserved: value[12..16].try_into().unwrap(), + i_u: value[16..20].try_into().unwrap(), + i_ino: u32::from_le_bytes([value[20], value[21], value[22], value[23]]), + i_uid: u16::from_le_bytes([value[24], value[25]]), + i_gid: u16::from_le_bytes([value[26], value[27]]), + i_reserved2: value[28..32].try_into().unwrap(), + }; + let ifmt = &inode.i_format; + match ifmt.version() { + Version::Compat => Ok(inode), + Version::Extended => Err(InodeError::VersionError), + _ => Err(InodeError::PosixError(EOPNOTSUPP)), + } + } +} + +impl TryFrom<(&dyn FileSystem, Nid)> for InodeInfo +where + I: Inode, +{ + type Error = Errno; + fn try_from(value: (&dyn FileSystem, Nid)) -> Result { + let f = value.0; + let sb = f.superblock(); + let nid = value.1; + let offset = sb.iloc(nid); + let accessor = sb.blk_access(offset); + let mut buf: ExtendedInodeInfoBuf = DEFAULT_INODE_BUF; + f.backend().fill(&mut buf[0..32], offset)?; + let compact_buf: CompactInodeInfoBuf = buf[0..32].try_into().unwrap(); + let r: Result = CompactInodeInfo::try_from(compact_buf); + match r { + Ok(compact) => Ok(InodeInfo::Compact(compact)), + Err(e) => match e { + InodeError::VersionError => { + let gotten = (sb.blksz() - accessor.off + 32).min(64); + f.backend() + .fill(&mut buf[32..(32 + gotten).min(64) as usize], offset + 32)?; + + if gotten < 32 { + f.backend().fill( + &mut buf[(32 + gotten) as usize..64], + sb.blkpos(sb.blknr(offset) + 1), + )?; + } + Ok(InodeInfo::Extended(ExtendedInodeInfo { + i_format: Format(u16::from_le_bytes([buf[0], buf[1]])), + i_xattr_icount: u16::from_le_bytes([buf[2], buf[3]]), + i_mode: u16::from_le_bytes([buf[4], buf[5]]), + i_reserved: buf[6..8].try_into().unwrap(), + i_size: u64::from_le_bytes([ + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15], + ]), + i_u: buf[16..20].try_into().unwrap(), + i_ino: u32::from_le_bytes([buf[20], buf[21], buf[22], buf[23]]), + i_uid: u32::from_le_bytes([buf[24], buf[25], buf[26], buf[27]]), + i_gid: u32::from_le_bytes([buf[28], buf[29], buf[30], buf[31]]), + i_mtime: u64::from_le_bytes([ + buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39], + ]), + i_mtime_nsec: u32::from_le_bytes([buf[40], buf[41], buf[42], buf[43]]), + i_nlink: u32::from_le_bytes([buf[44], buf[45], buf[46], buf[47]]), + i_reserved2: buf[48..64].try_into().unwrap(), + })) + } + InodeError::PosixError(e) => Err(e), + }, + } + } +} + +/// Represents the inode collection which is a hashmap of inodes. +pub(crate) trait InodeCollection { + type I: Inode + Sized; + + fn iget(&mut self, nid: Nid, filesystem: &dyn FileSystem) + -> PosixResult<&mut Self::I>; +} diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs index 213be6dbc553..940ab0b03a26 100644 --- a/fs/erofs/rust/erofs_sys/superblock.rs +++ b/fs/erofs/rust/erofs_sys/superblock.rs @@ -1,9 +1,15 @@ // Copyright 2024 Yiyang Wu // SPDX-License-Identifier: MIT or GPL-2.0-or-later -use super::*; +pub(crate) mod mem; +use alloc::boxed::Box; use core::mem::size_of; +use super::data::*; +use super::devices::*; +use super::inode::*; +use super::*; + /// The ondisk superblock structure. #[derive(Debug, Clone, Copy, Default)] #[repr(C)] @@ -130,3 +136,37 @@ pub(crate) fn iloc(&self, nid: Nid) -> Off { self.blkpos(self.meta_blkaddr) + ((nid as Off) << (5 as Off)) } } + +pub(crate) trait FileSystem +where + I: Inode, +{ + fn superblock(&self) -> &SuperBlock; + fn backend(&self) -> &dyn Backend; + fn as_filesystem(&self) -> &dyn FileSystem; + fn device_info(&self) -> &DeviceInfo; +} + +pub(crate) struct SuperblockInfo +where + I: Inode, + C: InodeCollection, +{ + pub(crate) filesystem: Box>, + pub(crate) inodes: C, + pub(crate) opaque: T, +} + +impl SuperblockInfo +where + I: Inode, + C: InodeCollection, +{ + pub(crate) fn new(fs: Box>, c: C, opaque: T) -> Self { + Self { + filesystem: fs, + inodes: c, + opaque, + } + } +} diff --git a/fs/erofs/rust/erofs_sys/superblock/mem.rs b/fs/erofs/rust/erofs_sys/superblock/mem.rs new file mode 100644 index 000000000000..12bf797bd1e3 --- /dev/null +++ b/fs/erofs/rust/erofs_sys/superblock/mem.rs @@ -0,0 +1,61 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use super::data::raw_iters::ref_iter::*; +use super::*; + +// Memory Mapped Device/File so we need to have some external lifetime on the backend trait. +// Note that we do not want the lifetime to infect the MemFileSystem which may have a impact on +// the content iter below. Just use HRTB to dodge the borrow checker. + +pub(crate) struct KernelFileSystem +where + B: Backend, +{ + backend: B, + sb: SuperBlock, + device_info: DeviceInfo, +} + +impl FileSystem for KernelFileSystem +where + B: Backend, + I: Inode, +{ + fn superblock(&self) -> &SuperBlock { + &self.sb + } + fn backend(&self) -> &dyn Backend { + &self.backend + } + + fn as_filesystem(&self) -> &dyn FileSystem { + self + } + + fn device_info(&self) -> &DeviceInfo { + &self.device_info + } +} + +impl KernelFileSystem +where + B: Backend, +{ + pub(crate) fn try_new(backend: B) -> PosixResult { + let mut buf = SUPERBLOCK_EMPTY_BUF; + backend.fill(&mut buf, EROFS_SUPER_OFFSET)?; + let sb: SuperBlock = buf.into(); + let device_info = get_device_infos(&mut ContinuousRefIter::new( + &sb, + &backend, + sb.devt_slotoff as Off * 128, + sb.extra_devices as Off * 128, + ))?; + Ok(Self { + backend, + sb, + device_info, + }) + } +} From patchwork Mon Sep 16 13:56:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805470 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F83516B3AC; Mon, 16 Sep 2024 13:57:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495028; cv=none; b=uZEHX5Tse1zaGkz+QBmK4P43cE8OioyEQ9XIQlEGRU7tbO3AShwkxCWk3CoOCc7qOM1OpF4wLHoPz5tyYvRuahrrJEJp6BESRHr7GjrTyK2lwzrUOFaNvJplxn92cK9wEinXZl1Zwl3u42e/MQI3RSRurO02l/uktH+URHo/dJA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495028; c=relaxed/simple; bh=VzIhTohL0KjtxsZXTKcqDwxBOs3aanECzljxZVrJ7CA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RnQA6ZmTNGQ0zBpBSeT1kbkjV70reHVBS00KOuUSZcW+eKnWh/2aFJfUMwa6yA4fS+XTv1wRyxmkqva2YlNc+hfHsSuuzmFOWzrAOt3DWrF/u9TSautgzzf0ohj9GhbCsffKhhAwYHyi2caIBsgeaFuJPDHICLLIyzzrju7eKE8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=OhDZuHKS; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="OhDZuHKS" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 9630369981; Mon, 16 Sep 2024 09:57:04 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495025; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=OlEgwvboFeWlv8zS3o2IBrRUjCWpIFBmMrHI8v0zFQI=; b=OhDZuHKSiJhuEfIz7ReFU6eFI5k+gYwPu8MhBCsYM0T+rbRh1gmc0xESMjiFWkMKIaETSE aeFmGCTipcRxNiqkaUFiBcrhcMp1evf73Hjpd0ch8pPOyiYhYktNJIX0eFU38Tes9ukbGz dJk391kNAqq8b+adb78FQt+O9/CMAY2FUShVMt/GxyRpy8vt+TQ7Qymfz3neRkBUKz+Elp EFOlAeF3mN2pPmnJzf6bKc1fSmCPQeIvXo3iBTbtPn35EhmJCQwvPTb7jyNupjdyAPVN8r Daw8vcQjXsI1uhZ7Izjwt45aelZ/hE2wUyBBlIUQELOydvanyHcIIkTQ+dDS1w== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 14/24] erofs: add block mapping capability in Rust Date: Mon, 16 Sep 2024 21:56:24 +0800 Message-ID: <20240916135634.98554-15-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Implement block mapping in rust and implement map iterators over Inode which will be used in data access. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys/map.rs | 54 +++++++++++ fs/erofs/rust/erofs_sys/superblock.rs | 129 ++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/fs/erofs/rust/erofs_sys/map.rs b/fs/erofs/rust/erofs_sys/map.rs index 757e8083c8f1..f56f31cefcd5 100644 --- a/fs/erofs/rust/erofs_sys/map.rs +++ b/fs/erofs/rust/erofs_sys/map.rs @@ -1,7 +1,10 @@ // Copyright 2024 Yiyang Wu // SPDX-License-Identifier: MIT or GPL-2.0-or-later +use super::inode::*; +use super::superblock::*; use super::*; + pub(crate) const MAP_MAPPED: u32 = 0x0001; pub(crate) const MAP_META: u32 = 0x0002; pub(crate) const MAP_ENCODED: u32 = 0x0004; @@ -43,3 +46,54 @@ fn from(value: MapType) -> Self { } pub(crate) type MapResult = PosixResult; + +/// Iterates over the data map represented by an inode. +pub(crate) struct MapIter<'a, 'b, FS, I> +where + FS: FileSystem, + I: Inode, +{ + fs: &'a FS, + inode: &'b I, + offset: Off, + len: Off, +} + +impl<'a, 'b, FS, I> MapIter<'a, 'b, FS, I> +where + FS: FileSystem, + I: Inode, +{ + pub(crate) fn new(fs: &'a FS, inode: &'b I, offset: Off) -> Self { + Self { + fs, + inode, + offset, + len: inode.info().file_size(), + } + } +} + +impl<'a, 'b, FS, I> Iterator for MapIter<'a, 'b, FS, I> +where + FS: FileSystem, + I: Inode, +{ + type Item = MapResult; + fn next(&mut self) -> Option { + if self.offset >= self.len { + None + } else { + let result = self.fs.map(self.inode, self.offset); + match result { + Ok(m) => { + let accessor = self.fs.superblock().blk_access(m.physical.start); + let len = m.physical.len.min(accessor.len); + self.offset += len; + Some(Ok(m)) + } + Err(e) => Some(Err(e)), + } + } + } +} diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs index 940ab0b03a26..fc6b3cb00b18 100644 --- a/fs/erofs/rust/erofs_sys/superblock.rs +++ b/fs/erofs/rust/erofs_sys/superblock.rs @@ -8,8 +8,11 @@ use super::data::*; use super::devices::*; use super::inode::*; +use super::map::*; use super::*; +use crate::round; + /// The ondisk superblock structure. #[derive(Debug, Clone, Copy, Default)] #[repr(C)] @@ -135,6 +138,10 @@ pub(crate) fn blk_round_up(&self, addr: Off) -> Blk { pub(crate) fn iloc(&self, nid: Nid) -> Off { self.blkpos(self.meta_blkaddr) + ((nid as Off) << (5 as Off)) } + pub(crate) fn chunk_access(&self, format: ChunkFormat, address: Off) -> Accessor { + let chunkbits = format.chunkbits() + self.blkszbits as u16; + Accessor::new(address, chunkbits as Off) + } } pub(crate) trait FileSystem @@ -145,6 +152,128 @@ pub(crate) trait FileSystem fn backend(&self) -> &dyn Backend; fn as_filesystem(&self) -> &dyn FileSystem; fn device_info(&self) -> &DeviceInfo; + fn flatmap(&self, inode: &I, offset: Off, inline: bool) -> MapResult { + let sb = self.superblock(); + let nblocks = sb.blk_round_up(inode.info().file_size()); + let blkaddr = match inode.info().spec() { + Spec::RawBlk(blkaddr) => Ok(blkaddr), + _ => Err(EUCLEAN), + }?; + + let lastblk = if inline { nblocks - 1 } else { nblocks }; + if offset < sb.blkpos(lastblk) { + let len = inode.info().file_size().min(sb.blkpos(lastblk)) - offset; + Ok(Map { + logical: Segment { start: offset, len }, + physical: Segment { + start: sb.blkpos(blkaddr) + offset, + len, + }, + algorithm_format: 0, + device_id: 0, + map_type: MapType::Normal, + }) + } else if inline { + let len = inode.info().file_size() - offset; + let accessor = sb.blk_access(offset); + Ok(Map { + logical: Segment { start: offset, len }, + physical: Segment { + start: sb.iloc(inode.nid()) + + inode.info().inode_size() + + inode.info().xattr_size() + + accessor.off, + len, + }, + algorithm_format: 0, + device_id: 0, + map_type: MapType::Meta, + }) + } else { + Err(EUCLEAN) + } + } + + fn chunk_map(&self, inode: &I, offset: Off) -> MapResult { + let sb = self.superblock(); + let chunkformat = match inode.info().spec() { + Spec::Chunk(chunkformat) => Ok(chunkformat), + _ => Err(EUCLEAN), + }?; + let accessor = sb.chunk_access(chunkformat, offset); + + if chunkformat.is_chunkindex() { + let unit = size_of::() as Off; + let pos = round!( + UP, + self.superblock().iloc(inode.nid()) + + inode.info().inode_size() + + inode.info().xattr_size() + + unit * accessor.nr, + unit + ); + let mut buf = [0u8; size_of::()]; + self.backend().fill(&mut buf, pos)?; + let chunk_index = ChunkIndex::from(buf); + if chunk_index.blkaddr == u32::MAX { + Err(EUCLEAN) + } else { + Ok(Map { + logical: Segment { + start: accessor.base + accessor.off, + len: accessor.len, + }, + physical: Segment { + start: sb.blkpos(chunk_index.blkaddr) + accessor.off, + len: accessor.len, + }, + algorithm_format: 0, + device_id: chunk_index.device_id & self.device_info().mask, + map_type: MapType::Normal, + }) + } + } else { + let unit = 4; + let pos = round!( + UP, + sb.iloc(inode.nid()) + + inode.info().inode_size() + + inode.info().xattr_size() + + unit * accessor.nr, + unit + ); + let mut buf = [0u8; 4]; + self.backend().fill(&mut buf, pos)?; + let blkaddr = u32::from_le_bytes(buf); + let len = accessor.len.min(inode.info().file_size() - offset); + if blkaddr == u32::MAX { + Err(EUCLEAN) + } else { + Ok(Map { + logical: Segment { + start: accessor.base + accessor.off, + len, + }, + physical: Segment { + start: sb.blkpos(blkaddr) + accessor.off, + len, + }, + algorithm_format: 0, + device_id: 0, + map_type: MapType::Normal, + }) + } + } + } + + fn map(&self, inode: &I, offset: Off) -> MapResult { + match inode.info().format().layout() { + Layout::FlatInline => self.flatmap(inode, offset, true), + Layout::FlatPlain => self.flatmap(inode, offset, false), + Layout::Chunk => self.chunk_map(inode, offset), + _ => todo!(), + } + } } pub(crate) struct SuperblockInfo From patchwork Mon Sep 16 13:56:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805471 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B741417A59D; Mon, 16 Sep 2024 13:57:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495030; cv=none; b=thjR2MOLM3HjxNBdtsg4enkT+m5c7tfNlort3wF/NGlyp/tCmvotFMn43cCfFd0wz83G+WJOBbn9rq17ZkwJra+6U6ZT7ZzB6aO4h+gckfG4CRCOdIHBeuwD3N1VXZ3dqTewNZ6ZjgwrKL+aszZzJlA7Gx/BzUFyQkLWT8B8v08= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495030; c=relaxed/simple; bh=YfrKy0P5t/PFVgfEJ9Oa8pP3m9ofPBgNKhmjzSJN120=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=exFt98B2J/aU0CQ/WWi4ceuMGWOVG+PKSPnKHIrKKS4mvgMhHuXhUClZJ4brH3KmmXyoAFHWYV9MGFudE8ZjwIRI+cqrw5qP/nSiNDeLaqg9aFhN4zwudax1KCkJN10EGU9mwyY7nZsixpqxpOAFNiS+Q5Cp1XREb7s4QKwGgXU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=g8obcaLK; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="g8obcaLK" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7CD5769989; Mon, 16 Sep 2024 09:57:06 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495027; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=bCX/VGnpSaFf2bcuOvskzF/4BX9NNeVk1l0oyYrgTyQ=; b=g8obcaLKn83twIxtsW1bMKexchJ/MixNaNHqV9/9wVbN1Tm0XJI+GQOH/h+dJ0gXl+uX7P 7xEc4xBpK51y0PKnnS4/Ma7hE99UXXOx7ap0tAZcH9XaV3UtgfAojztOBAoCnvX/XThgaL MxKJNTvonxSeZQ4cikSnniS8pN4cmaMlU0svNBht1nckie5xXQMSKQfeKr4Q+ILgP6Nbpi 7ZzdyLcmeRasnDv7/ROCWkaxoMufdke1WjhW5g8pTWWtQFc8Gou3JqwYHnM7Oer5rWrhgZ jD1dcmCu80OQR4cNzMMvsaFzmHW3FLjE+xnVgr7kC8EyxHAZt6ovnWDlORqLTQ== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 15/24] erofs: add iter methods in filesystem in Rust Date: Mon, 16 Sep 2024 21:56:25 +0800 Message-ID: <20240916135634.98554-16-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Implement mapped iter that uses the MapIter and can yield data that is backed by EROFS inode. Implement continuous_iter and mapped_iter for filesystem which can returns an iterator that yields raw data. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys/data.rs | 2 + .../rust/erofs_sys/data/raw_iters/ref_iter.rs | 63 +++++++++++++++++++ .../rust/erofs_sys/data/raw_iters/traits.rs | 4 ++ fs/erofs/rust/erofs_sys/superblock.rs | 13 ++++ fs/erofs/rust/erofs_sys/superblock/mem.rs | 22 +++++++ 5 files changed, 104 insertions(+) diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs index 483f3204ce42..21630673c24e 100644 --- a/fs/erofs/rust/erofs_sys/data.rs +++ b/fs/erofs/rust/erofs_sys/data.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT or GPL-2.0-or-later pub(crate) mod backends; pub(crate) mod raw_iters; +use super::inode::*; +use super::map::*; use super::superblock::*; use super::*; 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 index 5aa2b7f44f3d..d39c9523b628 100644 --- a/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs +++ b/fs/erofs/rust/erofs_sys/data/raw_iters/ref_iter.rs @@ -4,6 +4,69 @@ use super::super::*; use super::*; +pub(crate) struct RefMapIter<'a, 'b, FS, B, I> +where + FS: FileSystem, + B: Backend, + I: Inode, +{ + sb: &'a SuperBlock, + backend: &'a B, + map_iter: MapIter<'a, 'b, FS, I>, +} + +impl<'a, 'b, FS, B, I> RefMapIter<'a, 'b, FS, B, I> +where + FS: FileSystem, + B: Backend, + I: Inode, +{ + pub(crate) fn new( + sb: &'a SuperBlock, + backend: &'a B, + map_iter: MapIter<'a, 'b, FS, I>, + ) -> Self { + Self { + sb, + backend, + map_iter, + } + } +} + +impl<'a, 'b, FS, B, I> Iterator for RefMapIter<'a, 'b, FS, B, I> +where + FS: FileSystem, + B: Backend, + I: Inode, +{ + type Item = PosixResult>; + fn next(&mut self) -> Option { + match self.map_iter.next() { + Some(map) => match map { + Ok(m) => { + let accessor = self.sb.blk_access(m.physical.start); + let len = m.physical.len.min(accessor.len); + match self.backend.as_buf(m.physical.start, len) { + Ok(buf) => Some(Ok(buf)), + Err(e) => Some(Err(e)), + } + } + Err(e) => Some(Err(e)), + }, + None => None, + } + } +} + +impl<'a, 'b, FS, B, I> BufferMapIter<'a> for RefMapIter<'a, 'b, FS, B, I> +where + FS: FileSystem, + B: Backend, + I: Inode, +{ +} + /// 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. diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs index 90b6a51658a9..531e970cdb49 100644 --- a/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs +++ b/fs/erofs/rust/erofs_sys/data/raw_iters/traits.rs @@ -3,6 +3,10 @@ use super::super::*; +/// Represents a basic iterator over a range of bytes from data backends. +/// The access order is guided by the block maps from the filesystem. +pub(crate) trait BufferMapIter<'a>: Iterator>> {} + /// 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>: diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs index fc6b3cb00b18..f60657eff3d6 100644 --- a/fs/erofs/rust/erofs_sys/superblock.rs +++ b/fs/erofs/rust/erofs_sys/superblock.rs @@ -5,6 +5,7 @@ use alloc::boxed::Box; use core::mem::size_of; +use super::data::raw_iters::*; use super::data::*; use super::devices::*; use super::inode::*; @@ -274,6 +275,18 @@ fn map(&self, inode: &I, offset: Off) -> MapResult { _ => todo!(), } } + + fn mapped_iter<'b, 'a: 'b>( + &'a self, + inode: &'b I, + offset: Off, + ) -> PosixResult + 'b>>; + + fn continuous_iter<'a>( + &'a self, + offset: Off, + len: Off, + ) -> PosixResult + 'a>>; } pub(crate) struct SuperblockInfo diff --git a/fs/erofs/rust/erofs_sys/superblock/mem.rs b/fs/erofs/rust/erofs_sys/superblock/mem.rs index 12bf797bd1e3..5756dc08744c 100644 --- a/fs/erofs/rust/erofs_sys/superblock/mem.rs +++ b/fs/erofs/rust/erofs_sys/superblock/mem.rs @@ -1,6 +1,7 @@ // 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::*; @@ -33,6 +34,27 @@ fn as_filesystem(&self) -> &dyn FileSystem { self } + fn mapped_iter<'b, 'a: 'b>( + &'a self, + inode: &'b I, + offset: Off, + ) -> PosixResult + 'b>> { + heap_alloc(RefMapIter::new( + &self.sb, + &self.backend, + MapIter::new(self, inode, offset), + )) + .map(|v| v as Box + 'b>) + } + fn continuous_iter<'a>( + &'a self, + offset: Off, + len: Off, + ) -> PosixResult + 'a>> { + heap_alloc(ContinuousRefIter::new(&self.sb, &self.backend, offset, len)) + .map(|v| v as Box + 'a>) + } + fn device_info(&self) -> &DeviceInfo { &self.device_info } From patchwork Mon Sep 16 13:56:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805472 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3EEA717B514; Mon, 16 Sep 2024 13:57:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495031; cv=none; b=svgrGTsjpv0XG5LcIzWnBysHtDkPAmZboNGmJ9xtuLvtBE2whBQbu6BJNP//Bm/0MfRdqiLY+4p7IM2uzN0U/I42FZLgOzOs8MP+qSaoypuLClPe1SXduLuNJSawDriePXcu+nnfYnlHsCbDdIVem7nwOCtJYcdneR4+W+UmSUY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495031; c=relaxed/simple; bh=jUiK35jhCNKwNtLZmWNbheSdEs1dR8byw40iyQ24itA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GmW8ozwXHi/U2rPKQtcEzjd1UNEQF+BmrtoNeNY+onX1BQj0huV8J+jVoKsmeSbg+j4PzaUiVrjUFEZ5Q07NlAL7NLKwOOnJXvSlJxFK6AxyGztRgRqnBWvGJAdreKQ0WWbU6hDVJ37in0FhCHdTKX1szBCccMZqPb/ivkosuIY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=ZXh9ANSe; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="ZXh9ANSe" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7576069845; Mon, 16 Sep 2024 09:57:08 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495029; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=IJeFyOgl8nOrg6bU4FPruU0g/Xx5Ar0E77i2j4pU4gE=; b=ZXh9ANSeQAemFI4eZL3sOh1Z2/r3EKl6hlzBLpgjMPgsxzAe+kNNa64a9MdPQqqYmHRJsl 3mBfx2PEAAQLsqHMGWmquqyme73AJoHHVz5iaVNcAYIqdRqV9a7B/kuw8mNrEFOkuRo5Zh rHWXcuY1hgx0yHt4EXAbSnG1tWurs72jBfpkJmHx6EI4we2UTFs+gunmnMG+DkvI3pBqUx zxoOFTdsPOxVTivfHCHMiacs26ZpzMZDkcjFGCxqvnZAjNp1vHPBaTdLo+qCF9om8mL6WW pTt3MbFU9KdB++Cq1L41srGGKE0GIpVdsXkZaAd70XTtDaTC2QFnVqocbpQpJw== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 16/24] erofs: implement dir and inode operations in Rust Date: Mon, 16 Sep 2024 21:56:26 +0800 Message-ID: <20240916135634.98554-17-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 Implement dir ops and inode ops in Rust. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys.rs | 1 + fs/erofs/rust/erofs_sys/data.rs | 4 ++ fs/erofs/rust/erofs_sys/operations.rs | 35 ++++++++++++++++ fs/erofs/rust/erofs_sys/superblock.rs | 59 +++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 fs/erofs/rust/erofs_sys/operations.rs diff --git a/fs/erofs/rust/erofs_sys.rs b/fs/erofs/rust/erofs_sys.rs index 20c0aa81a800..8c08ac347b2b 100644 --- a/fs/erofs/rust/erofs_sys.rs +++ b/fs/erofs/rust/erofs_sys.rs @@ -30,6 +30,7 @@ pub(crate) mod errnos; pub(crate) mod inode; pub(crate) mod map; +pub(crate) mod operations; pub(crate) mod superblock; pub(crate) mod xattrs; pub(crate) use errnos::{Errno, Errno::*}; diff --git a/fs/erofs/rust/erofs_sys/data.rs b/fs/erofs/rust/erofs_sys/data.rs index 21630673c24e..67bb66ce9efb 100644 --- a/fs/erofs/rust/erofs_sys/data.rs +++ b/fs/erofs/rust/erofs_sys/data.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT or GPL-2.0-or-later pub(crate) mod backends; pub(crate) mod raw_iters; +use super::dir::*; use super::inode::*; use super::map::*; use super::superblock::*; @@ -26,6 +27,9 @@ pub(crate) trait Backend { /// DirEntries. pub(crate) trait Buffer { fn content(&self) -> &[u8]; + fn iter_dir(&self) -> DirCollection<'_> { + DirCollection::new(self.content()) + } } /// Represents a buffer that holds a reference to a slice of data that diff --git a/fs/erofs/rust/erofs_sys/operations.rs b/fs/erofs/rust/erofs_sys/operations.rs new file mode 100644 index 000000000000..070ba20908a2 --- /dev/null +++ b/fs/erofs/rust/erofs_sys/operations.rs @@ -0,0 +1,35 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use super::inode::*; +use super::superblock::*; +use super::*; + +pub(crate) fn read_inode<'a, I, C>( + filesystem: &'a dyn FileSystem, + collection: &'a mut C, + nid: Nid, +) -> PosixResult<&'a mut I> +where + I: Inode, + C: InodeCollection, +{ + collection.iget(nid, filesystem) +} + +pub(crate) fn dir_lookup<'a, I, C>( + filesystem: &'a dyn FileSystem, + collection: &'a mut C, + inode: &I, + name: &str, +) -> PosixResult<&'a mut I> +where + I: Inode, + C: InodeCollection, +{ + filesystem + .find_nid(inode, name)? + .map_or(Err(Errno::ENOENT), |nid| { + read_inode(filesystem, collection, nid) + }) +} diff --git a/fs/erofs/rust/erofs_sys/superblock.rs b/fs/erofs/rust/erofs_sys/superblock.rs index f60657eff3d6..403ffdeb4573 100644 --- a/fs/erofs/rust/erofs_sys/superblock.rs +++ b/fs/erofs/rust/erofs_sys/superblock.rs @@ -8,6 +8,7 @@ use super::data::raw_iters::*; use super::data::*; use super::devices::*; +use super::dir::*; use super::inode::*; use super::map::*; use super::*; @@ -287,6 +288,64 @@ fn continuous_iter<'a>( offset: Off, len: Off, ) -> PosixResult + 'a>>; + + // Inode related goes here. + fn read_inode_info(&self, nid: Nid) -> PosixResult { + (self.as_filesystem(), nid).try_into() + } + + fn find_nid(&self, inode: &I, name: &str) -> PosixResult> { + for buf in self.mapped_iter(inode, 0)? { + for dirent in buf?.iter_dir() { + if dirent.dirname() == name.as_bytes() { + return Ok(Some(dirent.desc.nid)); + } + } + } + Ok(None) + } + + // Readdir related goes here. + fn fill_dentries( + &self, + inode: &I, + offset: Off, + emitter: &mut dyn FnMut(Dirent<'_>, Off), + ) -> PosixResult<()> { + let sb = self.superblock(); + let accessor = sb.blk_access(offset); + if offset > inode.info().file_size() { + return Err(EUCLEAN); + } + + let map_offset = round!(DOWN, offset, sb.blksz()); + let blk_offset = round!(UP, accessor.off, size_of::() as Off); + + let mut map_iter = self.mapped_iter(inode, map_offset)?; + let first_buf = map_iter.next().unwrap()?; + let mut collection = first_buf.iter_dir(); + + let mut pos: Off = map_offset + blk_offset; + + if blk_offset as usize / size_of::() <= collection.total() { + collection.skip_dir(blk_offset as usize / size_of::()); + for dirent in collection { + emitter(dirent, pos); + pos += size_of::() as Off; + } + } + + pos = round!(UP, pos, sb.blksz()); + + for buf in map_iter { + for dirent in buf?.iter_dir() { + emitter(dirent, pos); + pos += size_of::() as Off; + } + pos = round!(UP, pos, sb.blksz()); + } + Ok(()) + } } pub(crate) struct SuperblockInfo From patchwork Mon Sep 16 13:56:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805473 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81D031865E8; Mon, 16 Sep 2024 13:57:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495034; cv=none; b=hdXf4ZzqzWfp97Y2YwP4WwghtUVH97+JjXVCdEm2Js3jcRF25TDIInuMvoXSc6Y3COl6psDwCD/NarGYiqr2ODIkqRtwB8i1D4v6o71QsTXZ/oSUnSbDN/F7eO9p/WxM0Xjogr7dM4Is7NgBp0op2m66KADQ+2rxxTbDz2e4FxU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495034; c=relaxed/simple; bh=6iXHljAK6tlqf4i2wUsDyPPM5fCbgqrUvGbagJ/EIHU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QvdAo5N+nsR8KZf/2E8GxlT/itF8ooAYSX6tGFQHliX3Z9SBabj0WMVPduAZlEk0v6p2qp3P5OWqThIr2GDc9PbY2GqcwY/T0YcrkBz/u5S1Tr7qoMtNdyMiA6yh0KRvqjlgEsKes2zPIWBGH1+n2qFi+lF9kGxZ+PaEEvz2ZrU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=hJzUu1+W; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="hJzUu1+W" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 5A7FD69981; Mon, 16 Sep 2024 09:57:10 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495031; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=9dEPmwLuzUR8D9sjyr8ry8zWG2H9N5ifoCez2qPa480=; b=hJzUu1+WiF2oeH1MPPXfSsbcCo9OHHH/SnagXtAeg1y9rjtkzc5ehMb33iZIBKPvHiINW3 Yr1SxF780YgUOqJXxdmA7Ju72fzh1Rb+T8AY0FtJic+MJcdjZOLWaVCKTBcsQq3jD5piFO cePZNJAoVjcyi/80rNgB8m+7bnIeQ9d34jQVPdqz98KPSw2twyaY+/VZiQqzhmOsb8v07+ hXe7CR8/Nch8ct/Ua/guKr7KFzGPB1DC8VsKiicYpUOwnUsnzwExF18ORlw7Hp0cBXnkXZ 0AJuVvpWIrTSq15usiB2hYfQ0Hkpot9hEaiFA22Tt8cnxNx71n/1TdCu1bMaHA== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 17/24] erofs: introduce Rust SBI to C Date: Mon, 16 Sep 2024 21:56:27 +0800 Message-ID: <20240916135634.98554-18-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces Rust opaque superblock info to C as s_fs_info. The original erofs_sb_info is embedded inside the rust opaque type and reexported by rewriting the original EROFS_SB/EROFS_I_SB macros. This patch also provides a prototype of KernelInode, KernelInodeCollection so that the code can compile and it also implements the Metabuf Data Source by hooking up the original metabuf API defined in EROFS. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 2 +- fs/erofs/internal.h | 10 ++++++ fs/erofs/rust/kinode.rs | 49 ++++++++++++++++++++++++++ fs/erofs/rust/ksources.rs | 66 ++++++++++++++++++++++++++++++++++++ fs/erofs/rust/ksuperblock.rs | 30 ++++++++++++++++ fs/erofs/rust/mod.rs | 3 ++ fs/erofs/rust_bindings.h | 12 +++++++ fs/erofs/rust_helpers.c | 31 +++++++++++++++++ fs/erofs/rust_helpers.h | 21 ++++++++++++ fs/erofs/super.c | 15 ++++++-- fs/erofs/super_rs.rs | 50 +++++++++++++++++++++++++++ 11 files changed, 285 insertions(+), 4 deletions(-) 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_bindings.h create mode 100644 fs/erofs/rust_helpers.c create mode 100644 fs/erofs/rust_helpers.h diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index fb46a2c7fb50..dfa03edbe29a 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +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 +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o rust_helpers.o diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 8674a4cb9d39..18e67219fbc8 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -20,6 +20,10 @@ #include #include "erofs_fs.h" +#ifdef CONFIG_EROFS_FS_RUST +#include "rust_bindings.h" +#endif + /* redefine pr_fmt "erofs: " */ #undef pr_fmt #define pr_fmt(fmt) "erofs: " fmt @@ -178,8 +182,14 @@ struct erofs_sb_info { char *domain_id; }; +#ifdef CONFIG_EROFS_FS_RUST +#define EROFS_SB(sb) (*(struct erofs_sb_info **)(((void *)((sb)->s_fs_info)) + \ + EROFS_SB_INFO_OFFSET_RUST)) +#define EROFS_I_SB(inode) EROFS_SB((inode)->i_sb) +#else #define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info) #define EROFS_I_SB(inode) ((struct erofs_sb_info *)(inode)->i_sb->s_fs_info) +#endif /* Mount flags set via mount options or defaults */ #define EROFS_MOUNT_XATTR_USER 0x00000010 diff --git a/fs/erofs/rust/kinode.rs b/fs/erofs/rust/kinode.rs new file mode 100644 index 000000000000..df6de40d0594 --- /dev/null +++ b/fs/erofs/rust/kinode.rs @@ -0,0 +1,49 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use core::ffi::c_void; +use core::mem::MaybeUninit; +use core::ptr::NonNull; + +use kernel::bindings::{inode, super_block}; + +use super::erofs_sys::inode::*; +use super::erofs_sys::superblock::*; +use super::erofs_sys::*; + +#[repr(C)] +pub(crate) struct KernelInode { + pub(crate) info: MaybeUninit, + pub(crate) nid: MaybeUninit, + pub(crate) k_inode: MaybeUninit, + pub(crate) k_opaque: MaybeUninit<*mut c_void>, +} + +impl Inode for KernelInode { + fn new(_sb: &SuperBlock, _info: InodeInfo, _nid: Nid) -> Self { + unimplemented!(); + } + fn nid(&self) -> Nid { + unsafe { self.nid.assume_init() } + } + fn info(&self) -> &InodeInfo { + unsafe { self.info.assume_init_ref() } + } +} + +pub(crate) struct KernelInodeCollection { + sb: NonNull, +} + +impl InodeCollection for KernelInodeCollection { + type I = KernelInode; + fn iget(&mut self, _nid: Nid, _f: &dyn FileSystem) -> PosixResult<&mut Self::I> { + unimplemented!(); + } +} + +impl KernelInodeCollection { + pub(crate) fn new(sb: NonNull) -> Self { + Self { sb } + } +} diff --git a/fs/erofs/rust/ksources.rs b/fs/erofs/rust/ksources.rs new file mode 100644 index 000000000000..08213e11239c --- /dev/null +++ b/fs/erofs/rust/ksources.rs @@ -0,0 +1,66 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later + +use core::ffi::*; +use core::ptr::NonNull; + +use super::erofs_sys::data::*; +use super::erofs_sys::errnos::*; +use super::erofs_sys::*; + +use kernel::bindings::super_block; + +extern "C" { + #[link_name = "erofs_read_metabuf_rust_helper"] + pub(crate) fn read_metabuf( + sb: NonNull, + sbi: NonNull, + offset: c_ulonglong, + ) -> *mut c_void; + #[link_name = "erofs_put_metabuf_rust_helper"] + pub(crate) fn put_metabuf(addr: NonNull); +} + +fn try_read_metabuf( + sb: NonNull, + sbi: NonNull, + offset: c_ulonglong, +) -> PosixResult> { + let ptr = unsafe { read_metabuf(sb.cast(), sbi.cast(), offset) }; + if ptr.is_null() { + Err(Errno::ENOMEM) + } else if is_value_err(ptr) { + Err(Errno::from(ptr)) + } else { + Ok(unsafe { NonNull::new_unchecked(ptr) }) + } +} + +pub(crate) struct MetabufSource { + sb: NonNull, + opaque: NonNull, +} + +impl MetabufSource { + pub(crate) fn new(sb: NonNull, opaque: NonNull) -> Self { + Self { sb, opaque } + } +} + +impl Source for MetabufSource { + fn fill(&self, data: &mut [u8], offset: Off) -> PosixResult { + self.as_buf(offset, data.len() as u64).map(|buf| { + data[..buf.content().len()].clone_from_slice(buf.content()); + buf.content().len() as Off + }) + } + fn as_buf<'a>(&'a self, offset: Off, len: Off) -> PosixResult> { + try_read_metabuf(self.sb.clone(), self.opaque.clone(), offset).map(|ptr| { + let data: &'a [u8] = + unsafe { core::slice::from_raw_parts(ptr.as_ptr() as *const u8, len as usize) }; + RefBuffer::new(data, 0, len as usize, |ptr| unsafe { + put_metabuf(NonNull::new_unchecked(ptr as *mut c_void)) + }) + }) + } +} diff --git a/fs/erofs/rust/ksuperblock.rs b/fs/erofs/rust/ksuperblock.rs new file mode 100644 index 000000000000..c1955fa136c6 --- /dev/null +++ b/fs/erofs/rust/ksuperblock.rs @@ -0,0 +1,30 @@ +// Copyright 2024 Yiyang Wu +// SPDX-License-Identifier: MIT or GPL-2.0-or-later +use super::erofs_sys::superblock::*; +use super::kinode::*; +use alloc::boxed::Box; +use core::{ffi::c_void, ptr::NonNull}; +use kernel::bindings::super_block; +use kernel::types::ForeignOwnable; + +pub(crate) type KernelOpaque = NonNull<*mut c_void>; +/// KernelSuperblockInfo defined by embedded Kernel Inode +pub(crate) type KernelSuperblockInfo = + SuperblockInfo; + +/// SAFETY: +/// Cast the c_void back to KernelSuperblockInfo. +/// This seems to be prune to some concurrency issues +/// but the fact is that only KernelInodeCollection field can have mutability. +/// However, it's backed by the original iget_locked5 and it's already preventing +/// any concurrency issues. So it's safe to be casted mutable here even if it's not backed by +/// Arc/Mutex instead of using generic method from Foreign Ownable which only provides +/// immutable reference casting which is not enough. +/// Since the pointer always live as long as this module exists, it's safe to declare it as static. +pub(crate) fn erofs_sbi(sb: NonNull) -> &'static mut KernelSuperblockInfo { + unsafe { &mut *(sb.as_ref().s_fs_info).cast::() } +} + +pub(crate) fn free_sbi(sb: NonNull) { + unsafe { Box::::from_foreign(sb.as_ref().s_fs_info) }; +} diff --git a/fs/erofs/rust/mod.rs b/fs/erofs/rust/mod.rs index e6c0731f2533..a8b66c95261c 100644 --- a/fs/erofs/rust/mod.rs +++ b/fs/erofs/rust/mod.rs @@ -2,3 +2,6 @@ // SPDX-License-Identifier: MIT or GPL-2.0-or-later pub(crate) mod erofs_sys; +pub(crate) mod kinode; +pub(crate) mod ksources; +pub(crate) mod ksuperblock; diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h new file mode 100644 index 000000000000..9695c5ed5a7c --- /dev/null +++ b/fs/erofs/rust_bindings.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-later +// EROFS Rust Bindings Before VFS Patch Sets for Rust + +#ifndef __EROFS_RUST_BINDINGS_H +#define __EROFS_RUST_BINDINGS_H + +#include + +extern const unsigned long EROFS_SB_INFO_OFFSET_RUST; +extern void *erofs_alloc_sbi_rust(struct super_block *sb); +extern void *erofs_free_sbi_rust(struct super_block *sb); +#endif diff --git a/fs/erofs/rust_helpers.c b/fs/erofs/rust_helpers.c new file mode 100644 index 000000000000..5fdc158ed9ef --- /dev/null +++ b/fs/erofs/rust_helpers.c @@ -0,0 +1,31 @@ +#include "rust_helpers.h" + +static void erofs_init_metabuf_rust_helper(struct erofs_buf *buf, + struct super_block *sb, + struct erofs_sb_info *sbi) +{ + if (erofs_is_fileio_mode(sbi)) + buf->mapping = file_inode(sbi->fdev)->i_mapping; + else if (erofs_is_fscache_mode_rust_helper(sb, sbi)) + buf->mapping = sbi->s_fscache->inode->i_mapping; + else + buf->mapping = sb->s_bdev->bd_mapping; +} + +void *erofs_read_metabuf_rust_helper(struct super_block *sb, + struct erofs_sb_info *sbi, + erofs_off_t offset) +{ + struct erofs_buf buf = __EROFS_BUF_INITIALIZER; + erofs_init_metabuf_rust_helper(&buf, sb, sbi); + return erofs_bread(&buf, offset, EROFS_KMAP); +} + +void erofs_put_metabuf_rust_helper(void *addr) +{ + erofs_put_metabuf(&(struct erofs_buf){ + .base = addr, + .page = kmap_to_page(addr), + .kmap_type = EROFS_KMAP, + }); +} diff --git a/fs/erofs/rust_helpers.h b/fs/erofs/rust_helpers.h new file mode 100644 index 000000000000..158b21438314 --- /dev/null +++ b/fs/erofs/rust_helpers.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-later +// This is a helpers collection to dodge the missing macros or inline functions in bindgen + +#ifndef __EROFS_RUST_HELPERS_H +#define __EROFS_RUST_HELPERS_H + +#include "internal.h" + +static inline bool erofs_is_fscache_mode_rust_helper(struct super_block *sb, + struct erofs_sb_info *sbi) +{ + return IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && + !erofs_is_fileio_mode(sbi) && !sb->s_bdev; +} + +void *erofs_read_metabuf_rust_helper(struct super_block *sb, + struct erofs_sb_info *sbi, + erofs_off_t offset); +void erofs_put_metabuf_rust_helper(void *addr); + +#endif diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 666873f745da..61f138a7d8e2 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -586,9 +586,12 @@ static void erofs_set_sysfs_name(struct super_block *sb) static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) { struct inode *inode; - struct erofs_sb_info *sbi = EROFS_SB(sb); + struct erofs_sb_info *sbi; int err; - +#ifdef CONFIG_EROFS_FS_RUST + sb->s_fs_info = erofs_alloc_sbi_rust(sb); +#endif + sbi = EROFS_SB(sb); sb->s_magic = EROFS_SUPER_MAGIC; sb->s_flags |= SB_RDONLY | SB_NOATIME; sb->s_maxbytes = MAX_LFS_FILESIZE; @@ -809,7 +812,13 @@ static int erofs_init_fs_context(struct fs_context *fc) static void erofs_kill_sb(struct super_block *sb) { - struct erofs_sb_info *sbi = EROFS_SB(sb); + struct erofs_sb_info *sbi; + +#ifdef CONFIG_EROFS_FS_RUST + sbi = erofs_free_sbi_rust(sb); +#else + sbi = EROFS_SB(sb); +#endif if ((IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && sbi->fsid) || sbi->fdev) kill_anon_super(sb); diff --git a/fs/erofs/super_rs.rs b/fs/erofs/super_rs.rs index 4b8cbef507e3..7041f4011d4c 100644 --- a/fs/erofs/super_rs.rs +++ b/fs/erofs/super_rs.rs @@ -7,3 +7,53 @@ #[allow(dead_code)] #[allow(missing_docs)] pub(crate) mod rust; + +use core::ffi::*; +use core::mem::offset_of; +use core::ptr::NonNull; +use kernel::{bindings::super_block, types::ForeignOwnable}; +use rust::{ + erofs_sys::{ + alloc_helper::*, + data::backends::uncompressed::*, + superblock::{mem::*, *}, + *, + }, + kinode::*, + ksources::*, + ksuperblock::*, +}; + +fn try_alloc_sbi(sb: NonNull) -> PosixResult<*const c_void> { + // We have to use heap_alloc here to erase the signature of MemFileSystem + let sbi = heap_alloc(SuperblockInfo::new( + heap_alloc(KernelFileSystem::try_new(UncompressedBackend::new( + MetabufSource::new(sb, unsafe { NonNull::new_unchecked(sb.as_ref().s_fs_info) }), + ))?)?, + KernelInodeCollection::new(sb), + // SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called. + unsafe { NonNull::new_unchecked(sb.as_ref().s_fs_info) }, + ))?; + Ok(sbi.into_foreign()) +} +/// Allocating a rust implementation of super_block_info c_void when calling from fill_super +/// operations. Though we still need to embed original superblock info inside rust implementation +/// for compatibility. This is left as it is for now. +#[no_mangle] +pub unsafe extern "C" fn erofs_alloc_sbi_rust(sb: NonNull) -> *const c_void { + try_alloc_sbi(sb).unwrap_or_else(|err| err.into()) +} + +/// Freeing a rust implementation of super_block_info c_void when calling from kill_super +/// Returning the original c_void pointer for outer C code to free. +#[no_mangle] +pub unsafe extern "C" fn erofs_free_sbi_rust(sb: NonNull) -> *const c_void { + let opaque: *const c_void = erofs_sbi(sb).opaque.as_ptr().cast(); + // This will be freed as it goes out of the scope. + free_sbi(sb); + opaque +} + +/// Used as a hint offset to be exported so that EROFS_SB can find the correct the s_fs_info. +#[no_mangle] +pub static EROFS_SB_INFO_OFFSET_RUST: c_ulong = offset_of!(KernelSuperblockInfo, opaque) as c_ulong; From patchwork Mon Sep 16 13:56:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805474 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27528188017; Mon, 16 Sep 2024 13:57:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495036; cv=none; b=ousqriap/SBqG6+cuBd9HKaktk4hg+9EdDlw9HwpbMzZEhN2uk09hmEY7YOMr0wSMzckYWZFuhqev6JoyOwrUWH/gbpYJaHS2n8lHS/6IMEAtKYp4IKddkkiwiFwolf+xcFX7addK0aJpwrH9Y0H99lCet83tFCz24zCIYQcBvs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495036; c=relaxed/simple; bh=OzFT3rPtlk61UGvleBzAz4/qOlkHVP0IYWbCKlZDrLo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BL7FWiPbB405v7VbIteqsTDrPnHWMZhhaq6NQT6jUdQ7onwr0vhJ9n0wgwQP7bFfnX3eE0K0K1++EpJA760PVQCe8kvcu6zmcNjeTAbxTkHBGGGvNjOFT0BMtSAGYvp1O1Ltk61sxrwGKPXyYDCKzx4qnTRnFCzA/tqphyJLuTg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=B2bQYZ9Q; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="B2bQYZ9Q" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 56F7A69845; Mon, 16 Sep 2024 09:57:12 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495033; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=jPcHYzXLLC1yFU/qCQqga7ARoLByMqJwxrzsY3R4Kho=; b=B2bQYZ9QMRfXNJ53KJENNVh3g2BJuojQBnV3SzMkxgWlKIBEbSTLq1EWYLuXD8ccGgB0kR 5Z/3pYlo2I/b4xota/3wQ6kMeL5DZGI4HO/kRt0oVpqnP1zWKGuc+7sGwcMIuCUDMDyMS6 5Cy28SnN89zZSi3Mg4NTnfrX0oRDjY2oJahLa4G+likn++UUCNlZarGnfm5Fx5KPUtfOyX mVed3kTevO+60gsX3IqPnBDWuyuTGm3rnOOygEE2ECtQp1aARtny7ijJQHvbB5jBs8pWI2 +0xNxlS05sGeOfDNvppWDtN2WoOpsXEEeRXcEcB0tyzu5+0EagITGtFFQi20/w== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 18/24] erofs: introduce iget alternative to C Date: Mon, 16 Sep 2024 21:56:28 +0800 Message-ID: <20240916135634.98554-19-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces iget and fast symlink alternative written in Rust. After this patch, erofs_iget can be replaced with erofs_iget_rust. Iget related test and set are lifted after this patch as rust_helpers.c will also use it to port the iget_locked to Rust. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 2 +- fs/erofs/inode.c | 8 ++++-- fs/erofs/inode_rs.rs | 59 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/internal.h | 33 ++++++++++++++++++++++ fs/erofs/rust/kinode.rs | 29 +++++++++++++++++--- fs/erofs/rust_bindings.h | 12 ++++++++ fs/erofs/rust_helpers.c | 55 +++++++++++++++++++++++++++++++++++++ fs/erofs/rust_helpers.h | 4 ++- fs/erofs/super.c | 34 ++++++++++++++++++----- 9 files changed, 220 insertions(+), 16 deletions(-) create mode 100644 fs/erofs/inode_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index dfa03edbe29a..46de6f490ca2 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +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 rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o rust_helpers.o diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c index d2fd51fcebd2..b8467272a670 100644 --- a/fs/erofs/inode.c +++ b/fs/erofs/inode.c @@ -269,7 +269,7 @@ int erofs_fill_inode(struct inode *inode) * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down * so that it will fit. */ -static ino_t erofs_squash_ino(erofs_nid_t nid) +ino_t erofs_squash_ino(erofs_nid_t nid) { ino_t ino = (ino_t)nid; @@ -278,12 +278,12 @@ static ino_t erofs_squash_ino(erofs_nid_t nid) return ino; } -static int erofs_iget5_eq(struct inode *inode, void *opaque) +int erofs_iget5_eq(struct inode *inode, void *opaque) { return EROFS_I(inode)->nid == *(erofs_nid_t *)opaque; } -static int erofs_iget5_set(struct inode *inode, void *opaque) +int erofs_iget5_set(struct inode *inode, void *opaque) { const erofs_nid_t nid = *(erofs_nid_t *)opaque; @@ -292,6 +292,7 @@ static int erofs_iget5_set(struct inode *inode, void *opaque) return 0; } +#ifndef CONFIG_EROFS_FS_RUST struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid) { struct inode *inode; @@ -312,6 +313,7 @@ struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid) } return inode; } +#endif int erofs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, diff --git a/fs/erofs/inode_rs.rs b/fs/erofs/inode_rs.rs new file mode 100644 index 000000000000..5cca2ae581ac --- /dev/null +++ b/fs/erofs/inode_rs.rs @@ -0,0 +1,59 @@ +// 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; + +use core::ffi::*; +use core::mem::{offset_of, size_of}; +use core::ptr::NonNull; +use kernel::bindings::{inode, super_block}; +use kernel::container_of; +use rust::{ + erofs_sys::{operations::*, *}, + kinode::*, + ksuperblock::erofs_sbi, +}; + +/// Used as a size hint to be exported to kmem_caceh_create +#[no_mangle] +pub static EROFS_INODE_SIZE_RUST: c_uint = size_of::() as c_uint; + +/// Used as a hint offset to be exported so EROFS_VFS_I to find the embedded the vfs inode. +#[no_mangle] +pub static EROFS_VFS_INODE_OFFSET_RUST: c_ulong = offset_of!(KernelInode, k_inode) as c_ulong; + +/// Used as a hint offset to be exported to EROFS_I to find the embedded c side erofs_inode. +#[no_mangle] +pub static EROFS_I_OFFSET_RUST: c_long = + offset_of!(KernelInode, k_opaque) as c_long - offset_of!(KernelInode, k_inode) as c_long; + +/// Exported as iget replacement +#[no_mangle] +pub unsafe extern "C" fn erofs_iget_rust(sb: NonNull, nid: Nid) -> *mut c_void { + // SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called. + let sbi = erofs_sbi(sb); + read_inode(sbi.filesystem.as_ref(), &mut sbi.inodes, nid) + .map_or_else(|e| e.into(), |inode| inode.k_inode.as_mut_ptr().cast()) +} + +fn try_fill_inode(k_inode: NonNull, nid: Nid) -> PosixResult<()> { + // SAFETY: The super_block is initialized when the erofs_fill_inode_rust is called. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: k_inode is a part of KernelInode. + 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)?); + erofs_inode.nid.write(nid); + Ok(()) +} +/// Exported as fill_inode additional fill inode +#[no_mangle] +pub unsafe extern "C" fn erofs_fill_inode_rust(k_inode: NonNull, nid: Nid) -> c_int { + try_fill_inode(k_inode, nid).map_or_else(|e| i32::from(e) as c_int, |_| 0) +} diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 18e67219fbc8..42ce84783be7 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -306,10 +306,20 @@ struct erofs_inode { #endif /* CONFIG_EROFS_FS_ZIP */ }; /* the corresponding vfs inode */ +#ifndef CONFIG_EROFS_FS_RUST struct inode vfs_inode; +#endif }; +#ifdef CONFIG_EROFS_FS_RUST +#define EROFS_I(ptr) (*(struct erofs_inode **)(((void *)(ptr)) + \ + EROFS_I_OFFSET_RUST)) +#define EROFS_I_VFS(ptr) ((struct inode *)(((void *)(ptr)) + EROFS_VFS_INODE_OFFSET_RUST)) +#define EROFS_I_RUST(ptr) ((void *)(ptr) - EROFS_VFS_INODE_OFFSET_RUST) +#else #define EROFS_I(ptr) container_of(ptr, struct erofs_inode, vfs_inode) +#define EROFS_I_VFS(ptr) (&((struct erofs_inode *)(ptr))->vfs_inode) +#endif static inline erofs_off_t erofs_iloc(struct inode *inode) { @@ -427,10 +437,18 @@ 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); +ino_t erofs_squash_ino(erofs_nid_t nid); +int erofs_iget5_eq(struct inode *inode, void *opaque); +int erofs_iget5_set(struct inode *inode, void *opaque); +#ifdef CONFIG_EROFS_FS_RUST +#define erofs_iget erofs_iget_rust +#else struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid); +#endif int erofs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags); + int erofs_namei(struct inode *dir, const struct qstr *name, erofs_nid_t *nid, unsigned int *d_type); @@ -538,6 +556,21 @@ static inline struct bio *erofs_fscache_bio_alloc(struct erofs_map_dev *mdev) { static inline void erofs_fscache_submit_bio(struct bio *bio) {} #endif +#ifdef CONFIG_EROFS_FS_RUST +extern int erofs_init_rust(void); +extern void erofs_destroy_rust(void); +extern void erofs_init_inode_rust(struct inode *inode); +extern void erofs_free_inode_rust(struct inode *inode); +#else +static inline int erofs_init_rust(void) +{ + return 0; +} +static inline void erofs_destroy_rust(void) {} +static inline void erofs_init_inode_rust(struct inode *inode) {} +static inline void erofs_free_inode_rust(struct inode *inode) {} +#endif + #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ #endif /* __EROFS_INTERNAL_H */ diff --git a/fs/erofs/rust/kinode.rs b/fs/erofs/rust/kinode.rs index df6de40d0594..fac72bd8b6b3 100644 --- a/fs/erofs/rust/kinode.rs +++ b/fs/erofs/rust/kinode.rs @@ -1,16 +1,23 @@ // Copyright 2024 Yiyang Wu // SPDX-License-Identifier: MIT or GPL-2.0-or-later -use core::ffi::c_void; +use core::ffi::*; use core::mem::MaybeUninit; use core::ptr::NonNull; use kernel::bindings::{inode, super_block}; +use kernel::container_of; +use super::erofs_sys::errnos::*; use super::erofs_sys::inode::*; use super::erofs_sys::superblock::*; use super::erofs_sys::*; +extern "C" { + #[link_name = "erofs_iget_locked_rust_helper"] + fn iget_locked(sb: NonNull, nid: Nid) -> *mut c_void; +} + #[repr(C)] pub(crate) struct KernelInode { pub(crate) info: MaybeUninit, @@ -21,7 +28,12 @@ pub(crate) struct KernelInode { impl Inode for KernelInode { fn new(_sb: &SuperBlock, _info: InodeInfo, _nid: Nid) -> Self { - unimplemented!(); + Self { + info: MaybeUninit::uninit(), + nid: MaybeUninit::uninit(), + k_inode: MaybeUninit::uninit(), + k_opaque: MaybeUninit::uninit(), + } } fn nid(&self) -> Nid { unsafe { self.nid.assume_init() } @@ -37,8 +49,17 @@ pub(crate) struct KernelInodeCollection { impl InodeCollection for KernelInodeCollection { type I = KernelInode; - fn iget(&mut self, _nid: Nid, _f: &dyn FileSystem) -> PosixResult<&mut Self::I> { - unimplemented!(); + fn iget(&mut self, nid: Nid, _f: &dyn FileSystem) -> PosixResult<&mut Self::I> { + // SAFETY: iget_locked is safe to call here. + let k_inode = unsafe { iget_locked(self.sb.cast(), nid) }; + if is_value_err(k_inode.cast()) { + return Err(Errno::from(k_inode as i32)); + } else { + let erofs_inode: &mut KernelInode = + // SAFETY: iget_locked returns a valid pointer to a vfs inode and it's embedded in a KernelInode. + unsafe { &mut *(container_of!(k_inode, KernelInode, k_inode) as *mut KernelInode) }; + return Ok(erofs_inode); + } } } diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index 9695c5ed5a7c..657f109dd6e7 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -6,7 +6,19 @@ #include + +typedef u64 erofs_nid_t; +typedef u64 erofs_off_t; +/* data type for filesystem-wide blocks number */ +typedef u32 erofs_blk_t; + extern const unsigned long EROFS_SB_INFO_OFFSET_RUST; +extern const unsigned int EROFS_INODE_SIZE_RUST; +extern const unsigned long EROFS_VFS_INODE_OFFSET_RUST; +extern const long EROFS_I_OFFSET_RUST; + extern void *erofs_alloc_sbi_rust(struct super_block *sb); extern void *erofs_free_sbi_rust(struct super_block *sb); +extern int erofs_iget5_eq_rust(struct inode *inode, void *opaque); +extern struct inode *erofs_iget_rust(struct super_block *sb, erofs_nid_t nid); #endif diff --git a/fs/erofs/rust_helpers.c b/fs/erofs/rust_helpers.c index 5fdc158ed9ef..94e9153fc3ff 100644 --- a/fs/erofs/rust_helpers.c +++ b/fs/erofs/rust_helpers.c @@ -1,5 +1,7 @@ #include "rust_helpers.h" +static struct kmem_cache *erofs_inode_cachep __read_mostly; + static void erofs_init_metabuf_rust_helper(struct erofs_buf *buf, struct super_block *sb, struct erofs_sb_info *sbi) @@ -29,3 +31,56 @@ void erofs_put_metabuf_rust_helper(void *addr) .kmap_type = EROFS_KMAP, }); } + +int erofs_init_rust(void) +{ + erofs_inode_cachep = kmem_cache_create("erofs_inode", + sizeof(struct erofs_inode), 0, + SLAB_RECLAIM_ACCOUNT, NULL); + if (!erofs_inode_cachep) + return -ENOMEM; + return 0; +} + +void erofs_destroy_rust(void) +{ + if (erofs_inode_cachep) + kmem_cache_destroy(erofs_inode_cachep); +} + +void erofs_init_inode_rust(struct inode *inode) +{ + EROFS_I(inode) = kmem_cache_alloc(erofs_inode_cachep, GFP_KERNEL); +} + +void erofs_free_inode_rust(struct inode *inode) +{ + struct erofs_inode *vi = EROFS_I(inode); + if (vi) + kmem_cache_free(erofs_inode_cachep, vi); +} + +struct inode *erofs_iget_locked_rust_helper(struct super_block *sb, erofs_nid_t nid) +{ + struct inode *inode; + int err; + + inode = iget5_locked(sb, erofs_squash_ino(nid), erofs_iget5_eq, + erofs_iget5_set, &nid); + if (!inode) + return ERR_PTR(-ENOMEM); + + err = erofs_fill_inode(inode); + if(err) + goto err_out; + + err = erofs_fill_inode_rust(inode, nid); + if(err) + goto err_out; + + return inode; +err_out: + if (err) + iget_failed(inode); + return ERR_PTR(err); +} diff --git a/fs/erofs/rust_helpers.h b/fs/erofs/rust_helpers.h index 158b21438314..5bcd452f6d82 100644 --- a/fs/erofs/rust_helpers.h +++ b/fs/erofs/rust_helpers.h @@ -17,5 +17,7 @@ void *erofs_read_metabuf_rust_helper(struct super_block *sb, struct erofs_sb_info *sbi, erofs_off_t offset); void erofs_put_metabuf_rust_helper(void *addr); - +extern int erofs_fill_inode_rust(struct inode *inode, erofs_nid_t nid); +struct inode *erofs_iget_locked_rust_helper(struct super_block *sb, + erofs_nid_t nid); #endif diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 61f138a7d8e2..659502bdf5fe 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -81,22 +81,23 @@ static int erofs_superblock_csum_verify(struct super_block *sb, void *sbdata) static void erofs_inode_init_once(void *ptr) { - struct erofs_inode *vi = ptr; - - inode_init_once(&vi->vfs_inode); + inode_init_once(EROFS_I_VFS(ptr)); + erofs_init_inode_rust(EROFS_I_VFS(ptr)); } static struct inode *erofs_alloc_inode(struct super_block *sb) { - struct erofs_inode *vi = + void *ptr = alloc_inode_sb(sb, erofs_inode_cachep, GFP_KERNEL); - if (!vi) + if (!ptr) return NULL; +#ifndef CONFIG_EROFS_FS_RUST /* zero out everything except vfs_inode */ - memset(vi, 0, offsetof(struct erofs_inode, vfs_inode)); - return &vi->vfs_inode; + memset(ptr, 0, offsetof(struct erofs_inode, vfs_inode)); +#endif + return EROFS_I_VFS(ptr); } static void erofs_free_inode(struct inode *inode) @@ -106,7 +107,12 @@ static void erofs_free_inode(struct inode *inode) if (inode->i_op == &erofs_fast_symlink_iops) kfree(inode->i_link); kfree(vi->xattr_shared_xattrs); + erofs_free_inode_rust(inode); +#ifdef CONFIG_EROFS_FS_RUST + kmem_cache_free(erofs_inode_cachep, EROFS_I_RUST(inode)); +#else kmem_cache_free(erofs_inode_cachep, vi); +#endif } /* read variable-sized metadata, offset will be aligned by 4-byte */ @@ -871,13 +877,25 @@ static int __init erofs_module_init(void) erofs_check_ondisk_layout_definitions(); +#ifndef CONFIG_EROFS_FS_RUST erofs_inode_cachep = kmem_cache_create("erofs_inode", sizeof(struct erofs_inode), 0, SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT, erofs_inode_init_once); +#else + erofs_inode_cachep = kmem_cache_create("erofs_inode_rust", + EROFS_INODE_SIZE_RUST, 0, + SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT, + erofs_inode_init_once); +#endif + if (!erofs_inode_cachep) return -ENOMEM; + err = erofs_init_rust(); + if(err) + goto rust_err; + err = erofs_init_shrinker(); if (err) goto shrinker_err; @@ -904,6 +922,8 @@ static int __init erofs_module_init(void) erofs_exit_shrinker(); shrinker_err: kmem_cache_destroy(erofs_inode_cachep); +rust_err: + erofs_destroy_rust(); return err; } From patchwork Mon Sep 16 13:56:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805475 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2D0E189503; Mon, 16 Sep 2024 13:57:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495038; cv=none; b=pjQRdf+vzZqM0JRQJyd7sj1DhSsCFSpA2yJnmlIeSXW4bMaYPRsGSwUu6DToDr2B/GWIGIKies1x/oa4ZT79xqAzJocpgVbIvTGonQAZOtuUMB+mnRpTI2LXX7eV5VNUmITPPhdwS7E67d5+Gv4Def98e50QDYyk/Qkxvfsb+F0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495038; c=relaxed/simple; bh=hlsNrrmS5LmffHkBX0DY0nyvuVIEAppvHs0rSr/LvwA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vj2Ucjj1Il5W/qt6hH8H+/dLI5bmpo4pq9KUqbwcDI8cJoEMWzVaareDvS5IKlJjO1NdbqYrASdxGWxtlKcSsCzyXn8a2zPWdEKODq6zgy5vsoMmsaB8nEwu7skkW7h7mYZaHTPqYIGutR+VipJeMenS9UKh0WvsrMbPJ6Xkz48= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=JAJ4mD6Y; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="JAJ4mD6Y" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 41C9B69988; Mon, 16 Sep 2024 09:57:14 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495035; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=Wch3FBTJC/bfytZ3iSboViHurbJ2bB+wmP7ljpFHKFU=; b=JAJ4mD6Y6Dz95HshWm2ZSD8lfpBJTL8YO+qZvc6z6pWLLcAayJcjvOqvAZ7DSODgg1RgQc ulM5shkDbh8AgRooTD35bJBgF+Uy2vhjqyq483jOhgeOZruvduGSyzLXRquBzadKyq/tvC Ya2JL42DKCXPN8vGkZa0NoRvWahIqemXs8weQq6S90d6Na4+dqhn+Y0hqtJNPAvksQcJbZ wqCTmbIlhY2WVrzzTlo2bmv+hswA9svhKXfpP3brGDVigu8wuftqOodhRHkIstiSdBCXvH oQRACxgsPBmL+zDXAOu4+sBPFEMypa/XBMn0r6GIJmyy6G4pXLse+Hue6vN8Vg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 19/24] erofs: introduce namei alternative to C Date: Mon, 16 Sep 2024 21:56:29 +0800 Message-ID: <20240916135634.98554-20-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces erofs_lookup_rust and erofs_get_parent_rust written in Rust as an alternative to the original namei.c. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 2 +- fs/erofs/internal.h | 2 ++ fs/erofs/namei.c | 2 ++ fs/erofs/namei_rs.rs | 56 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/rust_bindings.h | 4 ++- fs/erofs/super.c | 2 ++ 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 fs/erofs/namei_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 46de6f490ca2..0f748f3e0ff6 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +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 inode_rs.o rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o rust_helpers.o diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 42ce84783be7..1d9dfae285d5 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -442,6 +442,8 @@ int erofs_iget5_eq(struct inode *inode, void *opaque); int erofs_iget5_set(struct inode *inode, void *opaque); #ifdef CONFIG_EROFS_FS_RUST #define erofs_iget erofs_iget_rust +#define erofs_get_parent erofs_get_parent_rust +#define erofs_lookup erofs_lookup_rust #else struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid); #endif diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c index c94d0c1608a8..f657d475c4a1 100644 --- a/fs/erofs/namei.c +++ b/fs/erofs/namei.c @@ -7,6 +7,7 @@ #include "xattr.h" #include +#ifndef CONFIG_EROFS_FS_RUST struct erofs_qstr { const unsigned char *name; const unsigned char *end; @@ -214,6 +215,7 @@ static struct dentry *erofs_lookup(struct inode *dir, struct dentry *dentry, inode = erofs_iget(dir->i_sb, nid); return d_splice_alias(inode, dentry); } +#endif const struct inode_operations erofs_dir_iops = { .lookup = erofs_lookup, diff --git a/fs/erofs/namei_rs.rs b/fs/erofs/namei_rs.rs new file mode 100644 index 000000000000..d73a0a7bee1e --- /dev/null +++ b/fs/erofs/namei_rs.rs @@ -0,0 +1,56 @@ +// 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; +use core::ffi::*; +use core::ptr::NonNull; + +use kernel::bindings::{d_obtain_alias, d_splice_alias, dentry, inode}; +use kernel::container_of; + +use rust::{erofs_sys::operations::*, kinode::*, ksuperblock::*}; + +/// Lookup function for dentry-inode lookup replacement. +#[no_mangle] +pub unsafe extern "C" fn erofs_lookup_rust( + k_inode: NonNull, + dentry: NonNull, + _flags: c_uint, +) -> *mut c_void { + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) }; + // SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: this is backed by qstr which is c representation of a valid slice. + let name = unsafe { + core::str::from_utf8_unchecked(core::slice::from_raw_parts( + dentry.as_ref().d_name.name, + dentry.as_ref().d_name.__bindgen_anon_1.__bindgen_anon_1.len as usize, + )) + }; + let k_inode: *mut inode = + dir_lookup(sbi.filesystem.as_ref(), &mut sbi.inodes, erofs_inode, name) + .map_or(core::ptr::null_mut(), |result| result.k_inode.as_mut_ptr()); + + // SAFETY: We are sure that the inner k_inode has already been initialized. + unsafe { d_splice_alias(k_inode, dentry.as_ptr()).cast() } +} + +/// Exported as a replacement of erofs_get_parent. +#[no_mangle] +pub unsafe extern "C" fn erofs_get_parent_rust(child: NonNull) -> *mut c_void { + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let k_inode = unsafe { child.as_ref().d_inode }; + // SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called. + let sbi = erofs_sbi(unsafe { NonNull::new((*k_inode).i_sb).unwrap() }); // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let inode = unsafe { &*container_of!(k_inode, KernelInode, k_inode) }; + let k_inode: *mut inode = dir_lookup(sbi.filesystem.as_ref(), &mut sbi.inodes, inode, "..") + .map_or(core::ptr::null_mut(), |result| result.k_inode.as_mut_ptr()); + // SAFETY: We are sure that the inner k_inode has already been initialized + unsafe { d_obtain_alias(k_inode).cast() } +} diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index 657f109dd6e7..b35014aa5cae 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -6,7 +6,6 @@ #include - typedef u64 erofs_nid_t; typedef u64 erofs_off_t; /* data type for filesystem-wide blocks number */ @@ -21,4 +20,7 @@ extern void *erofs_alloc_sbi_rust(struct super_block *sb); extern void *erofs_free_sbi_rust(struct super_block *sb); extern int erofs_iget5_eq_rust(struct inode *inode, void *opaque); extern struct inode *erofs_iget_rust(struct super_block *sb, erofs_nid_t nid); +extern struct dentry *erofs_lookup_rust(struct inode *inode, struct dentry *dentry, + unsigned int flags); +extern struct dentry *erofs_get_parent_rust(struct dentry *dentry); #endif diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 659502bdf5fe..d49c804acf3d 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -554,6 +554,7 @@ static struct dentry *erofs_fh_to_parent(struct super_block *sb, erofs_nfs_get_inode); } +#ifndef CONFIG_EROFS_FS_RUST static struct dentry *erofs_get_parent(struct dentry *child) { erofs_nid_t nid; @@ -565,6 +566,7 @@ static struct dentry *erofs_get_parent(struct dentry *child) return ERR_PTR(err); return d_obtain_alias(erofs_iget(child->d_sb, nid)); } +#endif static const struct export_operations erofs_export_ops = { .encode_fh = generic_encode_ino32_fh, From patchwork Mon Sep 16 13:56:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805476 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B5CC1898F0; Mon, 16 Sep 2024 13:57:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495039; cv=none; b=kGVuHmuZ4VgyXPN5J0W7kz5laCV6rEeJDITgHIYFojFdS7I5cYjDF2MMEb7H90Bka9GONyKz3W8nhKjJOurICDmT4Yrn60KDi+tePPAR9F86lnwH3uyVPG39DLicoCdM0JAursCDVg6uCQxjk7KIdTEpguClqRw9ZU1Mw2G/z1g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495039; c=relaxed/simple; bh=lw8ntQ+iL9OQzESbczYfpyczLE2s4HQsBSHMKYWadaE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hziIjYPhJJJUExfd0tqTgVYGFwSazBvB0Qa6jnH4oPS3LrPRTae6AKj7XMk0B/nsEXGjhP7Ct0oC0EPYL+cJK9T0NJ256BGDAl5g7jEJGohdxCVTV1aDH2l89tDCnTxdH1fhn5kE3NIZOtdrXMbdCtyAcqTsm4I/fC2GVCJU7zc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=jWV+aFZQ; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="jWV+aFZQ" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 6959869981; Mon, 16 Sep 2024 09:57:16 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495037; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=PJC+8jRBBBR/onvAu4WHTXjuB2eZs+/U1I9QC+qBq5s=; b=jWV+aFZQUroYA6ESh1hKZd3vfmMWYPu9Uq2vVLl32hAOGy/VZ4pGNk96YKOUnWNudiIsg6 DBPyRMbCZByWdUx9yyknSavniNyCSrExlnFblJaSXcN2HCBjj5PUaH8t5ENhZjeWH8t5Ao TXIVyB5Ai/Sw1UNP5SsxvgNd74GJog45DBCvPiuQKHsfR+lPDNj+11amvNszH/doWkk5PT HDpYpHIrFI/WObyup+4Tpk1wImstQ4X3n6RAT0a7E4f2XdZD+YtAz3g2v37TykytMMbm0w gEE4VS7I3E1eCL2M5WoPaRXv+s+He11gjIwtPoxaYmqlcrfBRmfbrTHS3Ghdxw== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 20/24] erofs: introduce readdir alternative to C Date: Mon, 16 Sep 2024 21:56:30 +0800 Message-ID: <20240916135634.98554-21-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduce erofs_readdir_rust as an alternative for erofs_readdir written in Rust. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 2 +- fs/erofs/dir.c | 2 ++ fs/erofs/dir_rs.rs | 57 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/internal.h | 1 + fs/erofs/rust_bindings.h | 1 + 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 fs/erofs/dir_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 0f748f3e0ff6..e086487971b6 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +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 inode_rs.o namei_rs.o rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o dir_rs.o rust_helpers.o diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index c3b90abdee37..0f5df8a4169b 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -6,6 +6,7 @@ */ #include "internal.h" +#ifndef CONFIG_EROFS_FS_RUST static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, void *dentry_blk, struct erofs_dirent *de, unsigned int nameoff0, unsigned int maxsize) @@ -92,6 +93,7 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx) erofs_put_metabuf(&buf); return err < 0 ? err : 0; } +#endif const struct file_operations erofs_dir_fops = { .llseek = generic_file_llseek, diff --git a/fs/erofs/dir_rs.rs b/fs/erofs/dir_rs.rs new file mode 100644 index 000000000000..d965e6076242 --- /dev/null +++ b/fs/erofs/dir_rs.rs @@ -0,0 +1,57 @@ +// 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; +use core::ffi::*; +use core::ptr::NonNull; + +use kernel::bindings::{dir_context, file}; +use kernel::container_of; + +use rust::{ + erofs_sys::{inode::*, *}, + kinode::*, + ksuperblock::*, +}; + +/// Exported as a replacement of erofs_readdir. +#[no_mangle] +pub unsafe extern "C" fn erofs_readdir_rust( + f: NonNull, + mut ctx: NonNull, +) -> c_int { + // SAFETY: inode is always initialized in file. + let k_inode = unsafe { f.as_ref().f_inode }; + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode, KernelInode, k_inode) }; + // SAFETY: The super_block is always initialized when calling iget5_locked. + let sb = unsafe { (*k_inode).i_sb }; + let sbi = erofs_sbi(NonNull::new(sb).unwrap()); + // SAFETY: ctx is nonnull. + let offset = unsafe { ctx.as_ref().pos }; + match sbi + .filesystem + .fill_dentries(erofs_inode, offset as Off, &mut |dir, pos| unsafe { + // inline expansion from dir_emit + ctx.as_ref().actor.unwrap()( + ctx.as_ptr(), + dir.name.as_ptr().cast(), + dir.name.len() as i32, + pos as i64, + dir.desc.nid as u64, + dir.desc.file_type as u32, + ); + ctx.as_mut().pos = pos as i64; + }) { + Ok(_) => { + unsafe { ctx.as_mut().pos = erofs_inode.info().file_size() as i64 } + 0 + } + Err(e) => (i32::from(e)) as c_int, + } +} diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 1d9dfae285d5..6f57bb866637 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -444,6 +444,7 @@ int erofs_iget5_set(struct inode *inode, void *opaque); #define erofs_iget erofs_iget_rust #define erofs_get_parent erofs_get_parent_rust #define erofs_lookup erofs_lookup_rust +#define erofs_readdir erofs_readdir_rust #else struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid); #endif diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index b35014aa5cae..8b71d65e2c0b 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -23,4 +23,5 @@ extern struct inode *erofs_iget_rust(struct super_block *sb, erofs_nid_t nid); extern struct dentry *erofs_lookup_rust(struct inode *inode, struct dentry *dentry, unsigned int flags); extern struct dentry *erofs_get_parent_rust(struct dentry *dentry); +extern int erofs_readdir_rust(struct file *file, struct dir_context *ctx); #endif From patchwork Mon Sep 16 13:56:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805477 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 36EBB18CC0A; Mon, 16 Sep 2024 13:57:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495041; cv=none; b=NT+PD00yQwByg46apn6N03hSLm3yAqO62GhYe4ju1xjy9+FZM/s2xljgwRU6M+l0KfMsUve+9SxiEt5hfg+m1jPEKrOeukxZ4lglw64QulmRPpQWJm57HTLPWer2s7nFFcVZjsmWf9I0H3BmHjMBP+nkAkk4eae5uP+QTUQlsSE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495041; c=relaxed/simple; bh=P8reVC9LHn9Ss/NzZdNp07rUoCvE/rgeeNwx4HOeqnw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IjtF8aVBVfWzgYna1maCIRmk4VLogWMnrAb4G2EVePOxKfODM69jBiSodk4/hChV8a9mZyJ48U9WGbDB8AP/h3k9ERnMqZAq6SvL91TzX/Hp/vKDEMxNgjQ6z/ktrTyS0qOek8DW9ApTW5Z/cB1Wz9wYMgc2IAmaJehZ5+BISDw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=X5cUuPKc; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="X5cUuPKc" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 584C969839; Mon, 16 Sep 2024 09:57:18 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495039; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=SF+isR41/QqrBfGfC6meT3Kg4eWEa6AIAKKhQ1hnyqE=; b=X5cUuPKcDAJD4qrkdbm0LQChHyRJrM+CjfZdi2pNiAo3Gu2Pbkbzoy2+ZgrhlD7ofI06mj blYOAEf2pYeemD0LXW0dKogk+HQaxnzrCt+pFL7ZMYsBWgy1bDVVrw+R4UTlgXG18IAIT0 QRbBTNXXdkHc5dTL2oVYI/1RgPEYRt4oAbzo9+DfSQ4aNMPccOlygyOnfQPM5e3QAaSs8L 5mrbOfVBY3lQiL15qkSsUCPmoNJ71ipLnZgDo/hFse/fb9t/BXtSixqvPCw+i0cMbk+pIg 4imgAQxaMDCa/6rHNCewn5Uw3UcvIAe9dEz0QgMAI/PFjHEDSZtT4GX+V+OWTw== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 21/24] erofs: introduce erofs_map_blocks alternative to C Date: Mon, 16 Sep 2024 21:56:31 +0800 Message-ID: <20240916135634.98554-22-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces erofs_map_blocks alternative written in Rust, which will be hooked inside the erofs_iomap_begin. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 2 +- fs/erofs/data.c | 5 ++++ fs/erofs/data_rs.rs | 63 ++++++++++++++++++++++++++++++++++++++++ fs/erofs/rust_bindings.h | 4 +++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 fs/erofs/data_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index e086487971b6..219ddca0642e 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -9,4 +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 inode_rs.o namei_rs.o dir_rs.o rust_helpers.o +erofs-$(CONFIG_EROFS_FS_RUST) += super_rs.o inode_rs.o namei_rs.o dir_rs.o data_rs.o rust_helpers.o diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 61debd799cf9..c9694661136b 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -293,7 +293,12 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, map.m_la = offset; map.m_llen = length; +#ifdef CONFIG_EROFS_FS_RUST + ret = erofs_map_blocks_rust(inode, &map); +#else ret = erofs_map_blocks(inode, &map); +#endif + if (ret < 0) return ret; diff --git a/fs/erofs/data_rs.rs b/fs/erofs/data_rs.rs new file mode 100644 index 000000000000..ac34a9dd2079 --- /dev/null +++ b/fs/erofs/data_rs.rs @@ -0,0 +1,63 @@ +// 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; +use core::ffi::*; +use core::ptr::NonNull; + +use kernel::bindings::inode; +use kernel::container_of; + +use rust::{erofs_sys::*, kinode::*, ksuperblock::*}; + +#[repr(C)] +struct ErofsBuf { + mapping: NonNull, + page: NonNull, + base: NonNull, + kmap_type: c_int, +} + +/// A helper sturct to map blocks for iomap_begin because iomap is not generated by bindgen +#[repr(C)] +pub struct ErofsMapBlocks { + buf: ErofsBuf, + pub(crate) m_pa: u64, + pub(crate) m_la: u64, + pub(crate) m_plen: u64, + pub(crate) m_llen: u64, + pub(crate) m_deviceid: u16, + pub(crate) m_flags: u32, +} +/// Exported as a replacement for erofs_map_blocks. +#[no_mangle] +pub unsafe extern "C" fn erofs_map_blocks_rust( + k_inode: NonNull, + mut map: NonNull, +) -> c_int { + // SAFETY: super_block and superblockinfo is always initialized in k_inode. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) }; + // SAFETY: The map is always initialized in the caller. + match sbi + .filesystem + .map(erofs_inode, unsafe { map.as_ref().m_la } as Off) + { + Ok(m) => unsafe { + map.as_mut().m_pa = m.physical.start; + map.as_mut().m_la = map.as_ref().m_la; + map.as_mut().m_plen = m.physical.len; + map.as_mut().m_llen = m.physical.len; + map.as_mut().m_deviceid = m.device_id; + map.as_mut().m_flags = m.map_type.into(); + 0 + }, + Err(e) => i32::from(e) as c_int, + } +} diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index 8b71d65e2c0b..ad9aa75a7a2c 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -24,4 +24,8 @@ extern struct dentry *erofs_lookup_rust(struct inode *inode, struct dentry *dent unsigned int flags); extern struct dentry *erofs_get_parent_rust(struct dentry *dentry); extern int erofs_readdir_rust(struct file *file, struct dir_context *ctx); + +struct erofs_map_blocks; +extern int erofs_map_blocks_rust(struct inode *inode, + struct erofs_map_blocks *map); #endif From patchwork Mon Sep 16 13:56:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805478 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3BA7E1917EB; Mon, 16 Sep 2024 13:57:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495043; cv=none; b=O+bgP8dIjVlQbc0teHHtsZ+J+wq9UQwqlMk7HG5zfYcbY45jsKkjfkPZLtmU7W6awW6S1IEDD0KeYKP6/mVxHX0JJZEAlQ+C9pRDf7N71v6BmZD1kJNZlczhe44J+zY1tQStFIPCaw4x4iT7mnSTJvYyTdPIBqbiouzFG190W6M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495043; c=relaxed/simple; bh=rNUlETDV+01prA4JBPSRw8P+VTclzz+be5rG2+iUEmc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=czlPTiBF0v8/WAe0VuCi531uPPbMlAF/p2aS8/qe5KnTQmxEap4QMLyfDxt06qbBvKUiI2LFzqO2qIrsPP8P0C95rVwaRy24ZsGqB5WwiLgXKrPK7xEKJpDReWhzSecCfQVQhGbywMD8YvhnASvy956ttssuvXo9/TJ7q72f5k4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=X4baUaJu; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="X4baUaJu" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 5407B69846; Mon, 16 Sep 2024 09:57:20 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495041; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=iVEpuQCRq5HfW1zEs0Xldj9thdzekA2PSp+UaBg4euk=; b=X4baUaJuu1m/SZcizjCUwjQXlm2cqf/Wsik3+r0ZAj0Dsx1wUrzzvdWixSm+HzNQVhpbBH 7pEknBiEY52wUf/Ntn1D1CENrM44nH9qkHp//5Ehmwavc2rz41hCKJmzvvJu/EaCatnECd JLUHPJsylOQ+KaMJoiFUzPEuG0L7FP2pJpr7jWA3K5p+MXgtQZdtZSUPqswck7TEIiUNbw nkvJzl55CjR5pTO0hjZcoNxb5/ZWgGvAKIUvXmXdvkN5EmtaGUvIbS6FYAFK4fwgVTJDnA Vlr6mklfEGHUgfNmXRNtMVyexGCFFXHp20eM31T/GXzyy3MIxL/N+cG21fb/YA== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 22/24] erofs: add skippable iters in Rust Date: Mon, 16 Sep 2024 21:56:32 +0800 Message-ID: <20240916135634.98554-23-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduce self-owned skippable data iterators in Rust. This iterators will be used to access extended attributes later. Signed-off-by: Yiyang Wu --- fs/erofs/rust/erofs_sys/data/raw_iters.rs | 121 ++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters.rs b/fs/erofs/rust/erofs_sys/data/raw_iters.rs index 8f3bd250d252..f1ff0a251596 100644 --- a/fs/erofs/rust/erofs_sys/data/raw_iters.rs +++ b/fs/erofs/rust/erofs_sys/data/raw_iters.rs @@ -4,3 +4,124 @@ pub(crate) mod ref_iter; mod traits; pub(crate) use traits::*; + +use super::*; +use alloc::boxed::Box; + +/// Represents a skippable continuous buffer iterator. This is used primarily for reading the +/// extended attributes. Since the key-value is flattened out in its original format. +pub(crate) struct SkippableContinuousIter<'a> { + iter: Box + 'a>, + data: RefBuffer<'a>, + cur: usize, +} + +fn cmp_with_cursor_move( + lhs: &[u8], + rhs: &[u8], + lhs_cur: &mut usize, + rhs_cur: &mut usize, + len: usize, +) -> bool { + let result = lhs[*lhs_cur..(*lhs_cur + len)] == rhs[*rhs_cur..(*rhs_cur + len)]; + *lhs_cur += len; + *rhs_cur += len; + result +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum SkipCmpError { + PosixError(Errno), + NotEqual(Off), +} + +impl From for SkipCmpError { + fn from(e: Errno) -> Self { + SkipCmpError::PosixError(e) + } +} + +impl<'a> SkippableContinuousIter<'a> { + pub(crate) fn try_new( + mut iter: Box + 'a>, + ) -> PosixResult> { + if iter.eof() { + return Ok(None); + } + let data = iter.next().unwrap()?; + Ok(Some(Self { iter, data, cur: 0 })) + } + pub(crate) fn skip(&mut self, offset: Off) -> PosixResult<()> { + let dlen = self.data.content().len() - self.cur; + if offset as usize <= dlen { + self.cur += offset as usize; + } else { + self.cur = 0; + self.iter.advance_off(dlen as Off); + self.data = self.iter.next().unwrap()?; + } + Ok(()) + } + + pub(crate) fn read(&mut self, buf: &mut [u8]) -> PosixResult<()> { + let mut dlen = self.data.content().len() - self.cur; + let mut bcur = 0_usize; + let blen = buf.len(); + if dlen != 0 && dlen >= blen { + buf.clone_from_slice(&self.data.content()[self.cur..(self.cur + blen)]); + self.cur += blen; + } else { + buf[bcur..(bcur + dlen)].copy_from_slice(&self.data.content()[self.cur..]); + bcur += dlen; + while bcur < blen { + self.cur = 0; + self.data = self.iter.next().unwrap()?; + dlen = self.data.content().len(); + if dlen >= blen - bcur { + buf[bcur..].copy_from_slice(&self.data.content()[..(blen - bcur)]); + self.cur = blen - bcur; + return Ok(()); + } else { + buf[bcur..(bcur + dlen)].copy_from_slice(self.data.content()); + bcur += dlen; + } + } + } + Ok(()) + } + + pub(crate) fn try_cmp(&mut self, buf: &[u8]) -> Result<(), SkipCmpError> { + let dlen = self.data.content().len() - self.cur; + let blen = buf.len(); + let mut bcur = 0_usize; + + if dlen != 0 && dlen >= blen { + if cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, blen) { + Ok(()) + } else { + Err(SkipCmpError::NotEqual(bcur as Off)) + } + } else { + if dlen != 0 { + let clen = dlen.min(blen); + if !cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, clen) { + return Err(SkipCmpError::NotEqual(bcur as Off)); + } + } + while bcur < blen { + self.cur = 0; + self.data = self.iter.next().unwrap()?; + let dlen = self.data.content().len(); + let clen = dlen.min(blen - bcur); + if !cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, clen) { + return Err(SkipCmpError::NotEqual(bcur as Off)); + } + } + + Ok(()) + } + } + pub(crate) fn eof(&self) -> bool { + self.data.content().len() - self.cur == 0 && self.iter.eof() + } +} From patchwork Mon Sep 16 13:56:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805479 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 303BD192589; Mon, 16 Sep 2024 13:57:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495046; cv=none; b=CTN78x3NbQhBm1AsjIgvVM38fzM5lSWvHGHZJ1h+IadmrVIqyiQQCfFm0FV025qGh2PBc2GjoP7Il2gBxfvyegQJAZA+sc158EyB9PpFKkpXUFg6+lGCe7tphHAOylS/959+HjikbOl+M2XiRo2EUP3Antx3pHpRlLKXXmtBjlY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495046; c=relaxed/simple; bh=7DhpC3v/3K+OOvs0Ee6iKzIQkx7FoXxDfepESWYQ9uc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t0T2FvyT9xXtnVL7IYIMLrQJdMe+zH/jV13eZhz4Tp86WMKA3Bpolw8dEmWmlF7VbMruo+j93EcE35eB6KIXzOo+GYHnmBi3CJlXRPCekfcwJ5IIrD1g6IqBaltXhIFbw0qQ47fsVPQzgQld7Qfl4oT4H/68R90oy32x1nV2baQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=fKGjqmd+; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="fKGjqmd+" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 561F569848; Mon, 16 Sep 2024 09:57:22 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495043; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=zlfk2yVyXop5WdEA16RsoMhaE54MNmJqzOSetL+7z4A=; b=fKGjqmd+H0YGLTKH12je9r6EFTAdm+p96HRgadUd7QQmZjwntWblUGYIdIVSycNZ0Dntvw 04B30JssSY01wVuEXuSZe3c5YHseypnyeV4f61UiRhsvghp8y/3GYPlALSfLETAnAL4Cs7 3VopXQjsQbZCkndT8ZbgZA5OZATgIrBIp37RtnuRksV+NNLSYI5kV0lyq2mUs1r2cg0dM2 3eJpUiWmkeNgcCTfx0LAq2qEOqLVoV3hTh3S3eZSO11zzkhhTRuws9yStiZ882x4srUXjF ke2oPQPZDLX6eeBA+43a9lYCtH2VnF3ntPe/a6R/qXjEFM+FJ+YxS0PX0hkmkg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 23/24] erofs: implement xattrs operations in Rust Date: Mon, 16 Sep 2024 21:56:33 +0800 Message-ID: <20240916135634.98554-24-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch adds xattrs for erofs_sys crate and will later be used to implement xattr handler in Rust. Signed-off-by: Yiyang Wu --- 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, 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, @@ -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> { + let mut result: Vec = 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 = 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; + // Currently we eagerly initialized all xattrs; + fn read_inode_xattrs_shared_entries( + &self, + nid: Nid, + info: &InodeInfo, + ) -> PosixResult { + let sb = self.superblock(); + let mut offset = sb.iloc(nid) + info.inode_size(); + let mut buf = XATTR_ENTRY_SUMMARY_BUF; + let mut indexes: Vec = Vec::new(); + self.backend().fill(&mut buf, offset)?; + + let header: XAttrSharedEntrySummary = XAttrSharedEntrySummary::from(buf); + offset += size_of::() 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 { + 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::() as Off + + 4 * shared_count as Off; + + let inline_len = inode.info().xattr_size() + - size_of::() 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 { + 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::() as Off + + shared_count as Off * 4; + let mut offset = 0; + let inline_len = inode.info().xattr_size() + - size_of::() 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 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 backend: B, sb: SuperBlock, device_info: DeviceInfo, + infixes: Vec, } impl FileSystem for KernelFileSystem @@ -58,6 +59,9 @@ fn continuous_iter<'a>( fn device_info(&self) -> &DeviceInfo { &self.device_info } + fn xattr_infixes(&self) -> &Vec { + &self.infixes + } } impl KernelFileSystem @@ -68,6 +72,12 @@ pub(crate) fn try_new(backend: B) -> PosixResult { 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 { 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), } + +/// 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; + fn get_xattr_key( + &mut self, + pfs: &[XAttrInfix], + header: &XAttrEntryHeader, + buffer: &mut [u8], + ) -> PosixResult; + fn query_xattr_value( + &mut self, + pfs: &[XAttrInfix], + header: &XAttrEntryHeader, + name: &[u8], + index: u32, + buffer: &mut Option<&mut [u8]>, + ) -> PosixResult; + fn skip_xattr_value(&mut self, header: &XAttrEntryHeader) -> PosixResult<()>; +} +impl<'a> XAttrEntriesProvider for SkippableContinuousIter<'a> { + fn get_entry_header(&mut self) -> PosixResult { + 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 { + 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 { + let xattr_size = round!( + UP, + header.suffix_len as Off + header.value_len as Off, + size_of::() 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 = 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::() 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, pub(crate) nid: MaybeUninit, + pub(crate) shared_entries: MaybeUninit, pub(crate) k_inode: MaybeUninit, 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 { From patchwork Mon Sep 16 13:56:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yiyang Wu X-Patchwork-Id: 13805480 Received: from mail.tlmp.cc (unknown [148.135.17.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 175571925B6; Mon, 16 Sep 2024 13:57:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.135.17.20 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495047; cv=none; b=usfwa/6ZbdVHRj4zs44cIR1bRLIa+OY8+cYL4OTNRX53rS1uIOmKPl7fuLkjXB62y9bTjtlXKN5l3hTZ3kGfQWILoBcelomv2Me6cxSRmSU6SH+7/kVEX2yxoGGJdmlfCi5Q0ta+mzXG08Laoxb6NEv3AuYjU6NpCrR7qsWej8U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726495047; c=relaxed/simple; bh=IbqHVfFbye38HXIk4ja/9ILQ7+ASn23iwfedn4kSYa4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jUtIRtGyeAcL+1jxGaculGf42yhK8ZTT+7K3lI4N+AQdEpnj24HKBBiXQdstyLBFcgPjfyhNvX5+bDdT8vNIN5lzd+XsaVXhkeyvsd9O2bDlL/57GCL5gQe2BNrvUEftgybQ272lSyAx5IqyGbkk6DhpZbvhhuouiScDafK536I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc; spf=pass smtp.mailfrom=tlmp.cc; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b=OBq4tMd5; arc=none smtp.client-ip=148.135.17.20 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tlmp.cc Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tlmp.cc header.i=@tlmp.cc header.b="OBq4tMd5" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 4B6EF6984F; Mon, 16 Sep 2024 09:57:24 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tlmp.cc; s=dkim; t=1726495045; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=1pC3X6eZfUmCLid8GeSOP4AYR2slkMfkaqDKXR4//jw=; b=OBq4tMd5dYEC3VbRFlTrDgJ/lGksSk/7sMmAwQyZTzjoDd5wCgs9eVvUoWrXGTmzjl1gDa TeDBQH3Afx9YA958Hdk4c3RXefxejPxbat5ZHuSEHNhhSfQSgFu9EC6oB3j8f91y78BDo+ AudCJOL23givZmhLYVNf/+WRgtxOGJ8hYdG+6PcUlex5iiIgm1aBqEUFuIK0MQtFM2AtB3 axd12VcnG+Jx9Q7SA02HMmKWEpnx1oZ0au7byoIDk5fCKwr40CF6x1RpwhEtT6NTZlYm5D nEjXbsW8XwpE3XcSOicA6n0Cxj0XTGwa/1FU4hHB+3pVCxvNC0y3afs5M3yScg== From: Yiyang Wu To: linux-erofs@lists.ozlabs.org Cc: rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, LKML Subject: [RFC PATCH 24/24] erofs: introduce xattrs replacement to C Date: Mon, 16 Sep 2024 21:56:34 +0800 Message-ID: <20240916135634.98554-25-toolmanp@tlmp.cc> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240916135634.98554-1-toolmanp@tlmp.cc> References: <20240916135634.98554-1-toolmanp@tlmp.cc> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Last-TLS-Session-Version: TLSv1.3 This patch introduces erofs_getxattr_rust and erofs_listxattr_rust to C and can replace the original xattr logic entirely. Note that the original acl implementation is tweaked with a lifted function called erofs_getxattr_nobuf, so that difference of the calling convention of Rust side code can be bridged. Signed-off-by: Yiyang Wu --- fs/erofs/Makefile | 3 ++ fs/erofs/rust_bindings.h | 8 +++ fs/erofs/xattr.c | 31 +++++++++--- fs/erofs/xattr.h | 7 +++ fs/erofs/xattr_rs.rs | 106 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 fs/erofs/xattr_rs.rs diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 219ddca0642e..ad0650698f4b 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -10,3 +10,6 @@ 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 inode_rs.o namei_rs.o dir_rs.o data_rs.o rust_helpers.o +ifeq ($(CONFIG_EROFS_FS_XATTR),y) +erofs-$(CONFIG_EROFS_FS_RUST) += xattr_rs.o +endif diff --git a/fs/erofs/rust_bindings.h b/fs/erofs/rust_bindings.h index ad9aa75a7a2c..e5a879efd9e2 100644 --- a/fs/erofs/rust_bindings.h +++ b/fs/erofs/rust_bindings.h @@ -28,4 +28,12 @@ extern int erofs_readdir_rust(struct file *file, struct dir_context *ctx); struct erofs_map_blocks; extern int erofs_map_blocks_rust(struct inode *inode, struct erofs_map_blocks *map); +extern int erofs_getxattr_rust(struct inode *inode, unsigned int flags, + const char *name, void *buffer, size_t size); +extern ssize_t erofs_listxattr_rust(struct dentry *dentry, char *buffer, + size_t buffer_size); +#ifdef CONFIG_EROFS_FS_POSIX_ACL +extern int erofs_getxattr_nobuf_rust(struct inode *inode, int prefix, + const char *name, char **value); +#endif #endif diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c index a90d7d649739..0296c5809695 100644 --- a/fs/erofs/xattr.c +++ b/fs/erofs/xattr.c @@ -8,6 +8,7 @@ #include #include "xattr.h" +#ifndef CONFIG_EROFS_FS_RUST struct erofs_xattr_iter { struct super_block *sb; struct erofs_buf buf; @@ -122,6 +123,7 @@ static int erofs_init_inode_xattrs(struct inode *inode) clear_and_wake_up_bit(EROFS_I_BL_XATTR_BIT, &vi->flags); return ret; } +#endif static bool erofs_xattr_user_list(struct dentry *dentry) { @@ -175,6 +177,7 @@ const struct xattr_handler * const erofs_xattr_handlers[] = { NULL, }; +#ifndef CONFIG_EROFS_FS_RUST static int erofs_xattr_copy_to_buffer(struct erofs_xattr_iter *it, unsigned int len) { @@ -509,8 +512,28 @@ int erofs_xattr_prefixes_init(struct super_block *sb) erofs_xattr_prefixes_cleanup(sb); return ret; } +#endif #ifdef CONFIG_EROFS_FS_POSIX_ACL +#ifndef CONFIG_EROFS_FS_RUST +static int erofs_getxattr_nobuf(struct inode *inode, int prefix, + const char *name, char **value) +{ + int rc; + char *buf = NULL; + rc = erofs_getxattr(inode, prefix, name, NULL, 0); + if (rc > 0) { + buf = kmalloc(rc, GFP_KERNEL); + if (!value) + return ENOMEM; + rc = erofs_getxattr(inode, prefix, name, buf, rc); + } + *value = buf; + return rc; +} +#else +#define erofs_getxattr_nobuf erofs_getxattr_nobuf_rust +#endif struct posix_acl *erofs_get_acl(struct inode *inode, int type, bool rcu) { struct posix_acl *acl; @@ -531,13 +554,7 @@ struct posix_acl *erofs_get_acl(struct inode *inode, int type, bool rcu) return ERR_PTR(-EINVAL); } - rc = erofs_getxattr(inode, prefix, "", NULL, 0); - if (rc > 0) { - value = kmalloc(rc, GFP_KERNEL); - if (!value) - return ERR_PTR(-ENOMEM); - rc = erofs_getxattr(inode, prefix, "", value, rc); - } + rc = erofs_getxattr_nobuf(inode, prefix, "", &value); if (rc == -ENOATTR) acl = NULL; diff --git a/fs/erofs/xattr.h b/fs/erofs/xattr.h index b246cd0e135e..2b934c25e991 100644 --- a/fs/erofs/xattr.h +++ b/fs/erofs/xattr.h @@ -46,10 +46,17 @@ static inline const char *erofs_xattr_prefix(unsigned int idx, extern const struct xattr_handler * const erofs_xattr_handlers[]; +#ifdef CONFIG_EROFS_FS_RUST +#define erofs_getxattr erofs_getxattr_rust +#define erofs_listxattr erofs_listxattr_rust +static inline int erofs_xattr_prefixes_init(struct super_block *sb) { return 0; } +static inline void erofs_xattr_prefixes_cleanup(struct super_block *sb) {} +#else int erofs_xattr_prefixes_init(struct super_block *sb); void erofs_xattr_prefixes_cleanup(struct super_block *sb); int erofs_getxattr(struct inode *, int, const char *, void *, size_t); ssize_t erofs_listxattr(struct dentry *, char *, size_t); +#endif #else static inline int erofs_xattr_prefixes_init(struct super_block *sb) { return 0; } static inline void erofs_xattr_prefixes_cleanup(struct super_block *sb) {} diff --git a/fs/erofs/xattr_rs.rs b/fs/erofs/xattr_rs.rs new file mode 100644 index 000000000000..9429507089f6 --- /dev/null +++ b/fs/erofs/xattr_rs.rs @@ -0,0 +1,106 @@ +// 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; +use core::ffi::*; +use core::ptr::NonNull; + +use kernel::bindings::{dentry, inode}; +use kernel::container_of; + +use rust::{erofs_sys::xattrs::*, kinode::*, ksuperblock::*}; + +/// Used as a replacement for erofs_getattr. +#[no_mangle] +pub unsafe extern "C" fn erofs_getxattr_rust( + k_inode: NonNull, + index: c_uint, + name: NonNull, + buffer: NonNull, + size: usize, +) -> c_int { + // SAFETY: super_block and superblockinfo is always initialized in k_inode. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) }; + // SAFETY: buffer is always initialized in the caller and name is null terminated C string. + unsafe { + match sbi.filesystem.get_xattr( + erofs_inode, + index, + core::ffi::CStr::from_ptr(name.as_ptr().cast()).to_bytes(), + &mut Some(core::slice::from_raw_parts_mut( + buffer.as_ptr().cast(), + size, + )), + ) { + Ok(value) => match value { + XAttrValue::Buffer(x) => x as c_int, + _ => unreachable!(), + }, + Err(e) => i32::from(e) as c_int, + } + } +} + +/// Used as a replacement for erofs_getattr_nobuf. +#[no_mangle] +pub unsafe extern "C" fn erofs_getxattr_nobuf_rust( + k_inode: NonNull, + index: u32, + name: NonNull, + mut value: NonNull<*mut u8>, +) -> c_int { + // SAFETY: super_block and superblockinfo is always initialized in k_inode. + let sbi = erofs_sbi(unsafe { NonNull::new(k_inode.as_ref().i_sb).unwrap() }); + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called + let erofs_inode = unsafe { &*container_of!(k_inode.as_ptr(), KernelInode, k_inode) }; + // SAFETY: buffer is always initialized in the caller and name is null terminated C string. + unsafe { + match sbi.filesystem.get_xattr( + erofs_inode, + index, + core::ffi::CStr::from_ptr(name.as_ptr().cast()).to_bytes(), + &mut None, + ) { + Ok(xattr_value) => match xattr_value { + XAttrValue::Vec(v) => { + let rc = v.len() as c_int; + *value.as_mut() = v.leak().as_mut_ptr().cast(); + rc + } + + _ => unreachable!(), + }, + Err(e) => i32::from(e) as c_int, + } + } +} + +/// Used as a replacement for erofs_getattr. +#[no_mangle] +pub unsafe extern "C" fn erofs_listxattr_rust( + dentry: NonNull, + buffer: NonNull, + size: usize, +) -> c_long { + // SAFETY: dentry is always initialized in the caller. + let k_inode = unsafe { dentry.as_ref().d_inode }; + // SAFETY: We are sure that the inode is a Kernel Inode since alloc_inode is called. + let erofs_inode = unsafe { &*container_of!(k_inode, KernelInode, k_inode) }; + // SAFETY: The super_block is initialized when the erofs_alloc_sbi_rust is called. + let sbi = erofs_sbi(unsafe { NonNull::new((*k_inode).i_sb).unwrap() }); + match sbi.filesystem.list_xattrs( + erofs_inode, + // SAFETY: buffer is always initialized in the caller. + unsafe { core::slice::from_raw_parts_mut(buffer.as_ptr().cast(), size) }, + ) { + Ok(value) => value as c_long, + Err(e) => i32::from(e) as c_long, + } +}