From 16af6af40f44ace07ab7e3e1ea272089322a03f7 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Wed, 24 Apr 2024 19:33:30 +0200 Subject: [PATCH] Add Filesystem::try_mount When mounting a filesystem, often code like this is used: if !Filesystem::is_mountable(alloc, storage) { Filesystem::format(storage).ok(); } Filesystem::mount(alloc, storage) This mounts the filesystem twice because Filesystem::is_mountable is equivalent to Filesystem::mount(...).is_ok(). Depending on the storage implementation, mounting the filesystem can have significant cost. But directly calling Filesystem::mount and re-mounting in the error case is prohibited by the borrow checker. This patch adds a try_mount method that accepts a callable that is called on mount error. Afterwards, mounting is re-tried. --- CHANGELOG.md | 2 ++ src/fs.rs | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcf955e83..8850e4f8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Added - Added object-safe traits `DynFile`, `DynFilesystem` and `DynStorage` for accessing `Storage`, `Filesystem` and `File` implementations for any storage. +- Added `Filesystem::try_mount` function ([#57][]) ## Fixed @@ -18,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added path iteration utilities ([#47][]) [#47]: https://github.com/trussed-dev/littlefs2/pull/47 +[#57]: https://github.com/trussed-dev/littlefs2/pull/57 ## [v0.4.0] - 2023-02-07 diff --git a/src/fs.rs b/src/fs.rs index 873d54302..50c475649 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -16,7 +16,7 @@ pub type Bytes = generic_array::GenericArray; use crate::{ driver, - io::{self, OpenSeekFrom, Result}, + io::{self, Error, OpenSeekFrom, Result}, path, path::{Path, PathBuf}, }; @@ -1179,10 +1179,28 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> { pub fn mount(alloc: &'a mut Allocation, storage: &'a mut Storage) -> Result { let fs = Self::new(alloc, storage); - let mut alloc = fs.alloc.borrow_mut(); + fs.raw_mount()?; + Ok(fs) + } + + /// Mount the filesystem or, if that fails, call `f` with the mount error and the storage and then try again. + pub fn try_mount(alloc: &'a mut Allocation, storage: &'a mut Storage, f: F) -> Result + where + F: FnOnce(Error, &mut Storage) -> Result<()>, + { + let fs = Self::new(alloc, storage); + if let Err(err) = fs.raw_mount() { + f(err, fs.storage)?; + fs.raw_mount()?; + } + Ok(fs) + } + + fn raw_mount(&self) -> Result<()> { + let mut alloc = self.alloc.borrow_mut(); let return_code = unsafe { ll::lfs_mount(&mut alloc.state, &alloc.config) }; drop(alloc); - io::result_from(fs, return_code) + io::result_from((), return_code) } // Not public, user should use `mount`, possibly after `format`