From cb2e35143efcdb1d2e4e8ea7a05774f700f3093f Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 9 Jul 2019 18:58:38 -0500 Subject: [PATCH] Fixed issue where inlined files were not cleaned up A relatively late change in v2 was to switch from implicit replacement of inline files to explicit replacement, which requires explicitly deleting the inline struct tag before creating a CTZ skip-list tag. Unfortunately I never added the actual logic to delete the tag. This went unnoticed as the later CTZ skip-list tag always overrides the search for the struct tag during a directory fetch. To fix we need to add an explicit delete. Also there was some clean up necessary for actually removing delete tags during compaction as well as some refactoring around outlining. Found by Johnxjj --- lfs.c | 38 ++++++++++++++++++++++++-------------- lfs.h | 15 ++++++++------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/lfs.c b/lfs.c index c554135..b174661 100644 --- a/lfs.c +++ b/lfs.c @@ -415,6 +415,7 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t begin, uint16_t end); static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file); +static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); static void lfs_fs_prepmove(lfs_t *lfs, @@ -633,8 +634,9 @@ static int lfs_dir_traverse_filter(void *p, // check for redundancy uint32_t mask = LFS_MKTAG(0x7ff, 0x3ff, 0); if ((mask & tag) == (mask & *filtertag) || - (mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | - (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { + lfs_tag_isdelete(*filtertag) || + (mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | + (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { return true; } @@ -1643,11 +1645,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && f->ctz.size > lfs->cfg->cache_size) { - f->flags &= ~LFS_F_READING; - f->off = 0; - - lfs_alloc_ack(lfs); - int err = lfs_file_relocate(lfs, f); + int err = lfs_file_outline(lfs, f); if (err) { return err; } @@ -2473,7 +2471,6 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { lfs_cache_zero(lfs, &lfs->pcache); file->block = nblock; - file->flags &= ~LFS_F_INLINE; file->flags |= LFS_F_WRITING; return 0; @@ -2485,6 +2482,19 @@ relocate: } } +static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { + file->off = file->pos; + lfs_alloc_ack(lfs); + int err = lfs_file_relocate(lfs, file); + if (err) { + return err; + } + + file->flags &= ~LFS_F_INLINE; + file->flags |= LFS_F_OUTLINE; + return 0; +} + static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_READING) { if (!(file->flags & LFS_F_INLINE)) { @@ -2596,6 +2606,9 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { // commit file data and attributes err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( + {file->flags & LFS_F_OUTLINE + ? LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0x3ff) + : LFS_MKTAG(LFS_FROM_NOOP, 0, 0), NULL}, {LFS_MKTAG(type, file->id, size), buffer}, {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, file->cfg->attr_count), file->cfg->attrs})); @@ -2607,15 +2620,14 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - file->flags &= ~LFS_F_DIRTY; + file->flags &= ~LFS_F_DIRTY & ~LFS_F_OUTLINE; } return 0; relocate: // inline file doesn't fit anymore - file->off = file->pos; - err = lfs_file_relocate(lfs, file); + err = lfs_file_outline(lfs, file); if (err) { file->flags |= LFS_F_ERRED; return err; @@ -2740,9 +2752,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, lfs_min(0x3fe, lfs_min( lfs->cfg->cache_size, lfs->cfg->block_size/8))) { // inline file doesn't fit anymore - file->off = file->pos; - lfs_alloc_ack(lfs); - int err = lfs_file_relocate(lfs, file); + int err = lfs_file_outline(lfs, file); if (err) { file->flags |= LFS_F_ERRED; return err; diff --git a/lfs.h b/lfs.h index c78b3d6..18a5110 100644 --- a/lfs.h +++ b/lfs.h @@ -122,13 +122,13 @@ enum lfs_type { // File open flags enum lfs_open_flags { // open flags - LFS_O_RDONLY = 1, // Open a file as read only - LFS_O_WRONLY = 2, // Open a file as write only - LFS_O_RDWR = 3, // Open a file as read and write - LFS_O_CREAT = 0x0100, // Create a file if it does not exist - 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_RDONLY = 1, // Open a file as read only + LFS_O_WRONLY = 2, // Open a file as write only + LFS_O_RDWR = 3, // Open a file as read and write + LFS_O_CREAT = 0x0100, // Create a file if it does not exist + 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 // internally used flags LFS_F_DIRTY = 0x010000, // File does not match storage @@ -136,6 +136,7 @@ enum lfs_open_flags { LFS_F_READING = 0x040000, // File has been read since last flush LFS_F_ERRED = 0x080000, // An error occured during write LFS_F_INLINE = 0x100000, // Currently inlined in directory entry + LFS_F_OUTLINE = 0x200000, // Need to delete inlined directory entry }; // File seek flags