-
-
Notifications
You must be signed in to change notification settings - Fork 178
Introducing a high-level FS abstraction #472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I haven't had a chance to look at the details of this yet, but I'm definitely on board with the idea of a high-level FS API! The motivation you described sounds very reasonable to me. I'll give some more detailed feedback once I get some time to peruse :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for contributing this code! I've left some comments, based on an initial review of the PR.
src/fs/file_system.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for keeping this comment around?
src/fs/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of just saying that this is not like UNIX, we could also affirmatively indicate that it's a look like Windows, where you also have distinct "drive letters" for each volume :)
src/fs/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though it's unlikely that an UEFI app will start the other processors, during the boot stage, sync is still a problem because of interrupts. You could have code which modifies an internal data structure, gets interrupted by an event, and then that event handler tries to access the same data structure (which is currently in an invalid, in progress state!).
Fortunately, event handlers aren't exactly the usual place to do FS operations...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I don't know how interrupts in UEFI are handled and where they are used. If an interrupt handler wants to access the FileSystem
abstraction, while the lock is contended, then.. what to do? Force an unlock the File System? @GabrielMajeri
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, it is the users'/developers's responsibility to find a locking policy. A user might wrap the FileSystem
implementation in a SpinLock or not.
The documentation says that there is no out-of-the-box synchronization.
src/fs/file_system.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've noticed these todo!
calls. Are you planning to implement them before finalizing the PR, or leave them for future implementation post-merge? (if it's the first case, then I'd advise marking the PR as a draft so we don't accidentally merge it before it's ready 😅)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They will be implemented, for sure! I just wanted to clarify if we want this thing at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having recently done something with the "raw" filesystem API I can confirm that a simpler fs interface would be nice :)
3050d50
to
c5ef515
Compare
386aade
to
16e3360
Compare
@nicholasbishop @GabrielMajeri I finally had time working on this. It is still not ready to merge but much closer now. I add it as a new workspace member uefi-fs
. Let me know what you think.
API examples from the new integration test:
let mut fs = FileSystem::new(sfs); fs.create_dir("test_file_system_abs").unwrap(); // slash is transparently transformed to backslash fs.write("test_file_system_abs/foo", "hello").unwrap(); // absolute or relative paths are supported; ./ is ignored fs.copy("\\test_file_system_abs/foo", "\\test_file_system_abs/./bar").unwrap(); let read = fs.read("\\test_file_system_abs\\bar").unwrap(); let read = String::from_utf8(read).unwrap(); fs.rename("test_file_system_abs\\bar", "test_file_system_abs\\barfoo").unwrap(); let entries = fs.read_dir("test_file_system_abs").unwrap() .map(|e| e.unwrap().file_name().to_string()) .collect::<Vec<_>>(); assert_eq!(&[".", "..", "foo", "barfoo"], entries.as_slice());
Looks nice!
A few thoughts and questions:
- Will a
PathBuf
API be provided as well? Wouldn't necessarily need to be in the initial PR. - I think maybe instead of a new crate, we could put this as a module in the main
uefi
crate, e.g.uefi::fs
. My reasoning is basically that unless the new code runs against one of a few specific cases I'll list below, it's easier on the end user to keep it in the main crate. This is relevant to those other tickets about features vs crates as well, and I intend to write up some more thoughts eventually. But briefly, the reasons I can think of to put it in a separate crate are:- If the new code increases the compile-time of the crate significantly then putting it in a separate crate makes sense. I don't think that's an issue here; compilation-time increases are often related to pulling in more dependencies, but the only new dep here is
derive_more
, which pulls inquote
/syn
/proc_macro2
, all of which we already depend on because ofuefi-macros
. And the new code is not so large that it should meaningfully affect compilation times. - If the new code needs to be separated by a feature flag. Putting it in a separate crate can be a reasonable alternative to crate features, but in this case I think we can either gate the whole thing behind
alloc
, or maybe do it more fine-grained and just gate particular functions and types behindalloc
. But it's not like, depending on new unstable features or anything. - If the new code would negatively affect the API of the
uefi
crate. I don't think there's any issue with that here, it could all be neatly contained inuefi::fs
.
- If the new code increases the compile-time of the crate significantly then putting it in a separate crate makes sense. I don't think that's an issue here; compilation-time increases are often related to pulling in more dependencies, but the only new dep here is
- Just a suggestion for examples and tests with paths containing backslashes, you can use
r"a\b\c"
as a slightly cleaner alternative to"a\\b\\c"
.
uefi-fs/src/lib.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed from looking at the cargo doc
output, probably want a pub use
for Path
here.
16e3360
to
62ee08a
Compare
- Will a
PathBuf
API be provided as well? Wouldn't necessarily need to be in the initial PR.
So far, the API a user sees is just a &str
. Internally, it is transformed to a normalized CString16. I do not have a Path/PathBuf implementation yet (that is meant to be public). I think in the long term, each method should consume fn foo<P: Into<&cstr16>(&self, path: P)
or so, but I'm not sure about the interface. I think, it is most important that &str
is accepted as path.
Internally, the separator is \\
. However, users can just use a regular slash. The slash is transparently replaced by the internal path normalization process.
I think maybe instead of a new crate, we could put this as a module in the main
uefi
crate, e.g.uefi::fs
. My reasoning is basically that unless the new code runs against one of a few specific cases I'll list below, it's easier on the end user to keep it in the main crate. This is relevant to those other tickets about features vs crates as well, and I intend to write up some more thoughts eventually. But briefly, the reasons I can think of to put it in a separate crate are:
- If the new code increases the compile-time of the crate significantly then putting it in a separate crate makes sense. I don't think that's an issue here; compilation-time increases are often related to pulling in more dependencies, but the only new dep here is
derive_more
, which pulls inquote
/syn
/proc_macro2
, all of which we already depend on because ofuefi-macros
. And the new code is not so large that it should meaningfully affect compilation times.- If the new code needs to be separated by a feature flag. Putting it in a separate crate can be a reasonable alternative to crate features, but in this case I think we can either gate the whole thing behind
alloc
, or maybe do it more fine-grained and just gate particular functions and types behindalloc
. But it's not like, depending on new unstable features or anything.- If the new code would negatively affect the API of the
uefi
crate. I don't think there's any issue with that here, it could all be neatly contained inuefi::fs
.
I thought about it, and it doesn't massively increase compilation times nor requires it a feature flag. It will be just part of the normal API.
- Just a suggestion for examples and tests with paths containing backslashes, you can use
r"a\b\c"
as a slightly cleaner alternative to"a\\b\\c"
.
Ah, I didn't know that, thanks.
PS: This feature heavily uses (small and medium) allocations. In the long term, we might get some feedback in case our allocator does something wrong or so.
Ping @nicholasbishop ? :)
uefi/src/fs/file_system.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since FileSystem
now just contains the open SimpleFileSystemProtocol
, would it makes sense to drop the new type and instead add the FileSystem
methods directly to SimpleFileSystemProtocol
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to keep thinks separate. Low-level API and high-level API should not exist on the same type, especially, as mixing them together might break stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you say more about what might break when using both? If there are things the end user must avoid doing then we should add that info to the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought again about it and there are probably no safety issues, just convenience issues and a weird mixture of low-level and high-level APIs. However, I mixed up the SimpleFileSystem protocol with the FileProtocol. As the SimpleFileSystem protocol is so simple, it only has open_volume
, integrating the new FileSystem abstraction into the SimpleFileSystem protocol abstraction is a possible design choice. However, the following properties do not feel right:
- mix of low-level API with high-level API
- I need additional helpers for the Filesystem (
Path
,FileSystemError
, ...) and it feels wrong to integrate them intouefi::proto::media
. They are types of a different level.
Instead, I'd allow constructing a FileSystem
from a SimpleFileSystem
(via .into() or .to_file_ystem()
) for a high developer convenience.
What do you say?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, I especially agree that it would feel a little weird to have things like Path
mixed into uefi::proto::media
. It's a little unfortunate that the names are kinda reversed; SimpleFileSystem
is really more complex to use than FileSystem
. But that's probably fine, I don't have any better suggestion :) Anyway, +1 to the separate module.
b34efe5
to
6b1bc4c
Compare
uefi/src/fs/file_system.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this lifetime is technically wrong. It only lifes as long "as it lives". Should be the same the underlying protocol, hence, 'a
.
xtask/src/qemu.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo, I used this for testing. remove
6b1bc4c
to
4bc5821
Compare
@nicholasbishop I think this is ready for review and merging, when we keep the following things in mind:
- So far, the public API change and exports are very small and unlikely to ever change. I'd like to keep it that way.
- Users only use
&str
to pass in paths at the moment. This will eventually by replaced by something likeInto<Path>
, wherePath
is part of a public API of thefs
module. This will be subject of (follow-up) discussions (of a follow-up PR hopefully) - I'm very unhappy with my internal implementation of
NormalizedPath
and path handling in general. However, as this is a purely internal API, I think I can fix this in a follow-up MR and finally merge this feature. - I'm very happy with the state of the (public) documentation right now and how this simplifies things
Open Questions/Blockers:
- In my
NormalizedPath
abstraction I kept the way open for merging a path with a present working directory. The idea is that users specifyFileSystem::set_pwd("/foo/kernel")
. But I think, this is over-engineered and too feature-creep, aye? - I need do double check that the integration test is sufficient.
4bc5821
to
1f47d4d
Compare
uefi/src/table/boot.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[cfg(feature = "alloc")]
uefi/src/fs/file_system.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the interest of getting it merged, maybe just drop this method for now?
I'm in favor of merging this once the tests are passing and the one todo!()
is fixed. We can handle cleanups/additional tests in follow up PRs.
I'm in favor of merging this once the tests are passing and the one
todo!()
is fixed. We can handle cleanups/additional tests in follow up PRs.
I've created a tracking issue: #747
I'm in favor of merging this once the tests are passing and the one todo!() is fixed. We can handle cleanups/additional tests in follow up PRs.
I want to refactor the all my existing abstractions, namely Path
, Components
, and NormalizedPath
in a follow-up PR. Currently, the code is not very nice.
ce533e7
to
81299de
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is ugly but will be replaced once there is a new and better Path/PAthBuf abstraction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole module will be refactored in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole module will be refactored in a follow-up PR.
8a54c28
to
78a32a0
Compare
78a32a0
to
509dc71
Compare
This reverts a small change from: rust-osdev#472 If using the library without the `alloc` feature enabled, `FileSystem` isn't available, but you might still want access to the image's file system via the underlying protocol. The high-level API is still easily accessible via `FileSystem::new`.
This reverts a small change from: rust-osdev#472 If using the library without the `alloc` feature enabled, `FileSystem` isn't available, but you might still want access to the image's file system via the underlying protocol. The high-level API is still easily accessible via `FileSystem::new`.
This reverts a small change from: #472 If using the library without the `alloc` feature enabled, `FileSystem` isn't available, but you might still want access to the image's file system via the underlying protocol. The high-level API is still easily accessible via `FileSystem::new`.
This reverts a small change from: rust-osdev#472 If using the library without the `alloc` feature enabled, `FileSystem` isn't available, but you might still want access to the image's file system via the underlying protocol. The high-level API is still easily accessible via `FileSystem::new`.
Uh oh!
There was an error while loading. Please reload this page.
Hi! This originated in a personal learning project and I'd like to know what others think about it. Would be cool if we can bring this upstream. It's about creating a high level FS abstraction over the existing FS protocol. It aims to be as close to top-level functions provided by
std::fs
as possible.Motivation
Usually, UEFI-application hackers want to do something like this:
Code example / API demonstration
From the module description (initial version; a few changes in the meantime):
Open Questions
Steps to Undraft