Skip to content
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

Allow clearing FAT dirty flag. #66

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

reitermarkus
Copy link
Contributor

When the FAT dirty flag is set (which happens after ejecting an SD card without unmounting first on macOS), creating directories does not work as expected afterwards: When remounting the SD card after creating directories, these directories will be files instead.

If the dirty flag is cleared before creating the directories, mounting the SD card again under macOS works as expected, i.e. the directories are accessible as normal.

I have added a set_fat_dirty_flag method to clear the flag, but I am not sure when clearing this flag should be done.

When the dirty flag is set, this should result in an error when creating the FileSystem (or when trying to write to it).
Alternatively, the flag should ideally be cleared automatically when mounting after the filesystem has been checked somehow.

Closes #64.

@reitermarkus reitermarkus marked this pull request as draft May 26, 2022 04:02
src/table.rs Outdated Show resolved Hide resolved
src/fs.rs Outdated Show resolved Hide resolved
src/fs.rs Outdated
@@ -604,6 +608,15 @@ impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> {
Ok(())
}

pub fn set_fat_dirty_flag(&self, dirty: bool) -> Result<(), Error<IO::Error>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think handling it when filesystem is mounted would be better. Fail by default if dirty flag is set + add option in FsOptions to allow mounting a dirty FS (and clear the flag during mounting - this probably deserves another option). Also handle dirty flag from BSP. I don't like showing in user-facing API those weird and legacy things from FAT like doubled dirty flags by making two setters and getters.
Of course it is still a bad to work with a dirty FS. Proper solution would be to add some filesystem checking functionality but that's probably a ton of work...

@reitermarkus reitermarkus force-pushed the fat-dirty branch 2 times, most recently from c57fad8 to 9bbab4f Compare May 31, 2022 21:08
@reitermarkus
Copy link
Contributor Author

@rafalh, I have moved the check and added an option to ignore/clear the flag when mounting the file system.

@reitermarkus reitermarkus force-pushed the fat-dirty branch 3 times, most recently from 4971e1c to d05dca7 Compare June 13, 2022 11:03
@reitermarkus reitermarkus marked this pull request as ready for review June 13, 2022 11:15
@reitermarkus
Copy link
Contributor Author

@rafalh, can you review this again? Thanks.

@reitermarkus
Copy link
Contributor Author

@rafalh, ping.

@reitermarkus
Copy link
Contributor Author

@rafalh, could you have another look here? Thanks.

Copy link
Owner

@rafalh rafalh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mixed in too many things here. Dirty bit handling is a very important thing and can result in undetected filesystem corruption if not handled with care. I don't like changes to it being mixed with some refactors like const functions or some weird changes to errors in DiskSlice.
Please split this into smaller PRs that are easy to review.

let status_flags = fs.read_status_flags().unwrap();
assert_eq!(status_flags.dirty(), true);
assert_eq!(status_flags.dirty(), false);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also add one more remount step to make sure dirty flag is cleared on the disk (it is cached so such test makes sense)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added another remount step.

val |= FAT32_IO_ERROR_BIT;
}

Fat32::set(fat, 1, FatValue::Data(!val))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to keep it more explicit than using bit-wise negation here like that.
Also it's not really a "data" so it makes more sense to use set_raw function

src/fs.rs Outdated
}

fn unmount_internal(&self) -> Result<(), Error<IO::Error>> {
pub fn flush(&mut self) -> Result<(), Error<IO::Error>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, at first I through it's a bad idea to allow clearing the dirty flag like that, but it makes sense because dirty flag is set after first write, not at mount. If I understand correctly &mut will require all files to be closed, so it should be okay.
But if this was to be public it must be documented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the &mut is the important part here. This is basically the same as unmount without actually dropping the IO object.

if bpb.status_flags().dirty {
if bpb_status_flags.dirty() {
if options.ignore_dirty_flag {
warn!("BPB is dirty, clearing dirty flag.");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not BPB being dirty, it's entire filesystem. Please change it, e.g. "Filesystem is dirty (BPB), clearing..."

let mut fat_status_flags = read_fat_flags(&mut fat_slice::<&mut IO, IO::Error, IO>(&mut disk, &bpb), fat_type)?;
if fat_status_flags.dirty() {
if options.ignore_dirty_flag {
warn!("FAT is dirty, clearing dirty flag.");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not BPB being dirty, it's entire filesystem. Please change it, e.g. "Filesystem is dirty (FAT), clearing..."

@@ -512,7 +552,7 @@ impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> {
///
/// `Error::Io` will be returned if the underlying storage object returned an I/O error.
pub fn read_status_flags(&self) -> Result<FsStatusFlags, Error<IO::Error>> {
let bpb_status = self.bpb.status_flags();
let bpb_status = self.current_status_flags.get();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function allowed to check if dirty flag was set before filesystem was opened. current_status_flags will never have this flag set, even if ignore_dirty_flag is set. I would rather keep the old behavior for now because new one makes it impossible to mount a dirty volume and still get information about it being dirty.

src/fs.rs Outdated
disk.write_u8(encoded)?;
self.current_status_flags.set(flags);
Ok(())
set_dirty_flag(&mut *disk, self.fat_type(), &self.current_status_flags, dirty)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why adding this new free set_dirty_flag function? AFAIK it is used only in this place.

@@ -695,12 +716,12 @@ pub(crate) struct FsIoAdapter<'a, IO: ReadWriteSeek, TP, OCC> {
}

impl<IO: ReadWriteSeek, TP, OCC> IoBase for FsIoAdapter<'_, IO, TP, OCC> {
type Error = IO::Error;
type Error = Error<IO::Error>;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change? I see some more changes to error handling but I don't understand how it is related to clearing dirty flags

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite remember exactly. Somewhere the errors types were not compatible during propagation.

src/fs.rs Outdated Show resolved Hide resolved
@reitermarkus
Copy link
Contributor Author

@rafalh, can you take a look here? You should review my other PRs first so I can rebase this one for easier review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot create directories with lfn feature.
2 participants