Implemented desynchronized files

Desynchronized files are a new concept intended to capture some useful
quirks of the previous multiple-open-file behavior.

This adds:

- LFS_O_DESYNC     - Mark a file as desync during open
- lfsr_file_desync - Mark a file as desync whenever
- lfsr_file_sync   - Mark a file as NOT desync, and sync the file

Desynced files:

1. Don't recieve updates from writes to other file handles. This makes
   desynced files act as a sort of snapshot of the file at the time it
   was marked desync.

2. Don't call lfsr_file_sync on close. Unless lfsr_file_sync is
   explicitly called, changes to desynced files are not reflected on
   disk and not broadcasted to other file handles.

A side-effect of 2., is that this gives you a quick way to abort a file
write. Marking a file as desync and then closing the file will never
error.

Additionally, if an error occurs during a write operation, the file is
implicitly marked as desync. This provides graceful write aborting in
unlikely error cases. This has actually always been a feature in
littlefs, it was just named differently and didn't have an optional
recovery mode.

Since littlefs actually has to do more work to keep files in sync, the
desync feature is quite cheap:

            code          stack
  before:  33324           3072
  after:   33360 (+0.1%)   3072 (+0.0%)
This commit is contained in:
Christopher Haster
2024-01-02 13:44:19 -06:00
parent 3e32569454
commit b15940461d
3 changed files with 699 additions and 99 deletions
+28 -4
View File
@@ -162,12 +162,12 @@ enum lfs_open_flags {
LFS_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0800, // Move to end of file on every write
LFS_O_DESYNC = 0x1000, // Do not sync or recieve file updates
#endif
// internally used flags
LFS_F_UNFLUSHED = 0x010000, // File's data does not match storage
LFS_F_UNSYNCED = 0x020000, // File's metadata does not match storage
LFS_F_ERRORED = 0x040000, // An error occurred during write
};
// File seek flags
@@ -778,8 +778,13 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
// Close a file
//
// Any pending writes are written out to storage as though
// sync had been called and releases any allocated resources.
// If the file is not desynchronized, any pending writes are written out
// to storage as though sync had been called.
//
// Releases any allocated resources, even if there is an error.
//
// Readonly and desynchronized files do not touch disk and will always
// return 0.
//
// Returns a negative error code on failure.
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
@@ -787,11 +792,30 @@ int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file);
// Synchronize a file on storage
//
// Any pending writes are written out to storage.
// Any pending writes are written out to storage and other open files.
//
// If the file was desynchronized, it is now marked as synchronized. It will
// now recieve file updates and syncs on close.
//
// Returns a negative error code on failure.
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file);
// Mark a file as desynchronized
//
// Desynchronized files do not recieve file updates and do not sync on close.
// They effectively act as snapshots of the underlying file at that point
// in time.
//
// If an error occurs during a write operation, the file is implicitly marked
// as desynchronized.
//
// An explicit and successful call to lfsr_file_sync reverses this, marking
// the file as synchronized again.
//
// Returns a negative error code on failure.
int lfsr_file_desync(lfs_t *lfs, lfsr_file_t *file);
// Read data from file
//
// Takes a buffer and size indicating where to store the read data.