From nobody Tue Sep 9 23:02:28 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0734C41513 for ; Wed, 26 Jul 2023 17:11:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231922AbjGZRLt (ORCPT ); Wed, 26 Jul 2023 13:11:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51288 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230113AbjGZRLn (ORCPT ); Wed, 26 Jul 2023 13:11:43 -0400 Received: from aer-iport-5.cisco.com (aer-iport-5.cisco.com [173.38.203.67]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 006961BD6; Wed, 26 Jul 2023 10:11:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=10089; q=dns/txt; s=iport; t=1690391502; x=1691601102; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TRWzNxjh1uYFqrfsbY1Jt0vK+xcFRJ/MMfLVEQAsNfg=; b=cXYm+r53ojMKGnnqgq7PA6UnE4TumeBgvEUdvRj4TXRscuxeqlMdRCNM rfVNFZwPATw3caI9ce53YYoDH3CBxaYqHAbFkASee63ybcgTN2mLyKtRd 3u9eCn9hL4YzEHQvQxx97rdupk8C8zGiekiN3U2e5VA//ge9CAPQLMm63 s=; X-IronPort-AV: E=Sophos;i="6.01,232,1684800000"; d="scan'208";a="5874462" Received: from aer-iport-nat.cisco.com (HELO aer-core-7.cisco.com) ([173.38.203.22]) by aer-iport-5.cisco.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jul 2023 16:46:23 +0000 Received: from archlinux-cisco.cisco.com (dhcp-10-61-98-211.cisco.com [10.61.98.211]) (authenticated bits=0) by aer-core-7.cisco.com (8.15.2/8.15.2) with ESMTPSA id 36QGjqTx022602 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Wed, 26 Jul 2023 16:46:22 GMT From: Ariel Miculas To: rust-for-linux@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, tycho@tycho.pizza, brauner@kernel.org, viro@zeniv.linux.org.uk, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, Ariel Miculas Subject: [RFC PATCH v2 07/10] samples: puzzlefs: populate the directory entries with the inodes from the puzzlefs metadata file Date: Wed, 26 Jul 2023 19:45:31 +0300 Message-ID: <20230726164535.230515-8-amiculas@cisco.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230726164535.230515-1-amiculas@cisco.com> References: <20230726164535.230515-1-amiculas@cisco.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-User: amiculas X-Outbound-SMTP-Client: 10.61.98.211, dhcp-10-61-98-211.cisco.com X-Outbound-Node: aer-core-7.cisco.com Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" I've used the same strategy as in try_new_populated_root_dentry from rust/kernel/fs.rs, that is, recursively traverse the filesystem starting from the root and create the necessary dentries. This is not ideal because it creates all the dentries up front, but there are no rust filesystem abstractions for implementing lookups yet. Signed-off-by: Ariel Miculas --- rust/alloc/vec/mod.rs | 17 +++++ rust/kernel/fs.rs | 4 +- samples/rust/puzzlefs.rs | 141 +++++++++++++++++++++++++++++---------- 3 files changed, 127 insertions(+), 35 deletions(-) diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs index e8344c77939e..b755cf0b936c 100644 --- a/rust/alloc/vec/mod.rs +++ b/rust/alloc/vec/mod.rs @@ -2499,6 +2499,15 @@ unsafe fn split_at_spare_mut_with_len( } } =20 +impl Vec { + /// Try to clone the vector using the global allocator + #[inline] + #[stable(feature =3D "kernel", since =3D "1.0.0")] + pub fn try_clone(&self) -> Result { + self.try_clone_in(Global) + } +} + impl Vec { /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// @@ -2623,6 +2632,14 @@ pub fn try_extend_from_slice(&mut self, other: &[T])= -> Result<(), TryReserveErr self.try_spec_extend(other.iter()) } =20 + /// Tries to clone the vector using the given allocator + #[stable(feature =3D "kernel", since =3D "1.0.0")] + pub fn try_clone_in(&self, allocator: A) -> Result { + let mut new_vec =3D Vec::try_with_capacity_in(self.len(), allocato= r)?; + new_vec.try_extend_from_slice(&self)?; + Ok(new_vec) + } + /// Copies elements from `src` range to the end of the vector. /// /// # Panics diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs index 10f90f78fc54..709b79fa0030 100644 --- a/rust/kernel/fs.rs +++ b/rust/kernel/fs.rs @@ -781,7 +781,9 @@ impl SuperParams { /// /// The superblock is a newly-created one and this is the only active poin= ter to it. pub struct NewSuperBlock<'a, T: Type + ?Sized, S =3D NeedsInit> { - sb: &'a mut SuperBlock, + /// Pointer to the superblock; this fields is public so puzzlefs can c= all + /// try_new_dcache_dir_inode when populating the directory hierarchy + pub sb: &'a mut SuperBlock, =20 // This also forces `'a` to be invariant. _p: PhantomData<&'a mut &'a S>, diff --git a/samples/rust/puzzlefs.rs b/samples/rust/puzzlefs.rs index 8a64e0bd437d..1f0073716d91 100644 --- a/samples/rust/puzzlefs.rs +++ b/samples/rust/puzzlefs.rs @@ -6,16 +6,19 @@ use kernel::mount::Vfsmount; use kernel::prelude::*; use kernel::{ - c_str, file, fmt, fs, + c_str, file, fs, io_buffer::IoBufferWriter, - str::CString, sync::{Arc, ArcBorrow}, }; =20 mod puzzle; // Required by the autogenerated '_capnp.rs' files +use puzzle::inode::PuzzleFS; +use puzzle::types::{Inode, InodeMode, MetadataBlob}; use puzzle::{manifest_capnp, metadata_capnp}; =20 +use kernel::fs::{DEntry, INodeParams, NeedsRoot, NewSuperBlock, RootDEntry= }; + module_fs! { type: PuzzleFsModule, name: "puzzlefs", @@ -27,7 +30,6 @@ =20 #[derive(Debug)] struct PuzzlefsInfo { - base_path: CString, vfs_mount: Arc, } =20 @@ -55,9 +57,81 @@ fn try_new() -> Result { } } =20 +fn puzzlefs_populate_dir( + sb: &NewSuperBlock<'_, PuzzleFsModule, NeedsRoot>, + pfs: &PuzzleFS, + parent: &DEntry, + ino: u64, + name: &CStr, + recursion: usize, +) -> Result { + if recursion =3D=3D 0 { + return Err(E2BIG); + } + + let inode =3D Arc::try_new(pfs.find_inode(ino).map_err(|_| EINVAL)?)?; + match &inode.mode { + InodeMode::File { chunks: _ } =3D> { + let params =3D INodeParams { + mode: inode.permissions, + ino: inode.ino, + value: inode.clone(), + }; + let creator =3D fs::file_creator::<_, FsFile>(); + let inode =3D creator(sb, params)?; + sb.try_new_dentry(inode, parent, name)?; + } + InodeMode::Dir { dir_list } =3D> { + let params =3D INodeParams { + mode: inode.permissions, + ino: inode.ino, + value: inode.clone(), + }; + + let new_dentry; + let new_parent =3D if name.as_bytes() !=3D c_str!("").as_bytes= () { + let dcache_inode =3D sb.sb.try_new_dcache_dir_inode(params= )?; + new_dentry =3D sb.try_new_dentry(dcache_inode, parent, nam= e)?; + &new_dentry + } else { + parent + }; + + for entry in &dir_list.entries { + let mut name =3D entry.name.try_clone()?; + // append NUL terminator + name.try_push(0)?; + let name =3D CStr::from_bytes_with_nul(&name)?; + puzzlefs_populate_dir(sb, pfs, new_parent, entry.ino, name= , recursion - 1)?; + } + } + _ =3D> todo!(), + } + + Ok(()) +} + +/// Creates a new root dentry populated with the given entries. +fn try_new_populated_root_puzzlefs_dentry( + sb: &NewSuperBlock<'_, PuzzleFsModule, NeedsRoot>, + pfs: &PuzzleFS, + root_value: ::INodeData, +) -> Result> { + let root_inode =3D sb.sb.try_new_dcache_dir_inode(INodeParams { + mode: 0o755, + ino: root_value.ino, + value: root_value, + })?; + let root =3D sb.try_new_root_dentry(root_inode)?; + let ino =3D 1u64; + puzzlefs_populate_dir(sb, pfs, &root, ino, c_str!(""), 10)?; + Ok(root) +} + impl fs::Type for PuzzleFsModule { type Context =3D Self; - type INodeData =3D &'static [u8]; + // this is Arc so it can be cloned in puzzlefs_populate_dir + type INodeData =3D Arc; type Data =3D Box; const SUPER_TYPE: fs::Super =3D fs::Super::Independent; const NAME: &'static CStr =3D c_str!("puzzlefs"); @@ -65,41 +139,35 @@ impl fs::Type for PuzzleFsModule { const DCACHE_BASED: bool =3D true; =20 fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self>) -> Result<&f= s::SuperBlock> { - let base_path =3D CString::try_from_fmt(fmt!("hello world"))?; - pr_info!("base_path {:?}\n", base_path); let vfs_mount =3D Vfsmount::new_private_mount(c_str!("/home/puzzle= fs_oci"))?; pr_info!("vfs_mount {:?}\n", vfs_mount); =20 + let arc_vfs_mount =3D Arc::try_new(vfs_mount)?; + let sb =3D sb.init( Box::try_new(PuzzlefsInfo { - base_path, - vfs_mount: Arc::try_new(vfs_mount)?, + vfs_mount: arc_vfs_mount.clone(), })?, &fs::SuperParams { magic: 0x72757374, ..fs::SuperParams::DEFAULT }, )?; - let root =3D sb.try_new_populated_root_dentry( - &[], - kernel::fs_entries![ - file("test1", 0o600, "abc\n".as_bytes(), FsFile), - file("test2", 0o600, "def\n".as_bytes(), FsFile), - char("test3", 0o600, [].as_slice(), (10, 125)), - sock("test4", 0o755, [].as_slice()), - fifo("test5", 0o755, [].as_slice()), - block("test6", 0o755, [].as_slice(), (1, 1)), - dir( - "dir1", - 0o755, - [].as_slice(), - [ - file("test1", 0o600, "abc\n".as_bytes(), FsFile), - file("test2", 0o600, "def\n".as_bytes(), FsFile), - ] - ), - ], + + let file =3D file::RegularFile::from_path_in_root_mnt( + &arc_vfs_mount, + c_str!("997eed138af30d187e87d682dd2ae9f240fae78f668907a0519460= b397c82467"), + file::flags::O_RDONLY.try_into().unwrap(), + 0, )?; + + // TODO: figure out how to go from WireFormatError to kernel::erro= r::Error + let metadata =3D MetadataBlob::new(file).map_err(|_| EINVAL)?; + + let mut puzzlefs =3D PuzzleFS::new(metadata).map_err(|_| EINVAL)?; + let root_inode =3D Arc::try_new(puzzlefs.find_inode(1).map_err(|_|= EINVAL)?)?; + + let root =3D try_new_populated_root_puzzlefs_dentry(&sb, &mut puzz= lefs, root_inode)?; let sb =3D sb.init_root(root)?; Ok(sb) } @@ -110,7 +178,7 @@ fn fill_super(_data: (), sb: fs::NewSuperBlock<'_, Self= >) -> Result<&fs::SuperBl #[vtable] impl file::Operations for FsFile { // must be the same as INodeData - type OpenData =3D &'static [u8]; + type OpenData =3D Arc; type Filesystem =3D PuzzleFsModule; // this is an Arc because Data must be ForeignOwnable and the only imp= lementors of it are Box, // Arc and (); we cannot pass a reference to read, so we share Vfsmoun= t using and Arc @@ -126,14 +194,19 @@ fn open( =20 fn read( data: ArcBorrow<'_, Vfsmount>, - file: &file::File, + _file: &file::File, writer: &mut impl IoBufferWriter, offset: u64, ) -> Result { - file::read_from_slice( - file.inode::().ok_or(EINVAL)?.fs_data(), - writer, - offset, - ) + let mut buf =3D Vec::try_with_capacity(writer.len())?; + buf.try_resize(writer.len(), 0)?; + let file =3D file::RegularFile::from_path_in_root_mnt( + &data, + c_str!("data"), + file::flags::O_RDONLY.try_into().unwrap(), + 0, + )?; + let nr_bytes_read =3D file.read_with_offset(&mut buf[..], offset)?; + file::read_from_slice(&buf[..nr_bytes_read], writer, 0) } } --=20 2.41.0