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
This commit is contained in:
Christopher Haster
2019-07-09 18:58:38 -05:00
parent abd90cb84c
commit cb2e35143e
2 changed files with 32 additions and 21 deletions

38
lfs.c
View File

@@ -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 *dir, const struct lfs_mattr *attrs, int attrcount,
lfs_mdir_t *source, uint16_t begin, uint16_t end); 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_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 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_preporphans(lfs_t *lfs, int8_t orphans);
static void lfs_fs_prepmove(lfs_t *lfs, static void lfs_fs_prepmove(lfs_t *lfs,
@@ -633,8 +634,9 @@ static int lfs_dir_traverse_filter(void *p,
// check for redundancy // check for redundancy
uint32_t mask = LFS_MKTAG(0x7ff, 0x3ff, 0); uint32_t mask = LFS_MKTAG(0x7ff, 0x3ff, 0);
if ((mask & tag) == (mask & *filtertag) || if ((mask & tag) == (mask & *filtertag) ||
(mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | lfs_tag_isdelete(*filtertag) ||
(LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { (mask & tag) == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) |
(LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) {
return true; 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 && if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 &&
f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) &&
f->ctz.size > lfs->cfg->cache_size) { f->ctz.size > lfs->cfg->cache_size) {
f->flags &= ~LFS_F_READING; int err = lfs_file_outline(lfs, f);
f->off = 0;
lfs_alloc_ack(lfs);
int err = lfs_file_relocate(lfs, f);
if (err) { if (err) {
return 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); lfs_cache_zero(lfs, &lfs->pcache);
file->block = nblock; file->block = nblock;
file->flags &= ~LFS_F_INLINE;
file->flags |= LFS_F_WRITING; file->flags |= LFS_F_WRITING;
return 0; 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) { static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
if (file->flags & LFS_F_READING) { if (file->flags & LFS_F_READING) {
if (!(file->flags & LFS_F_INLINE)) { 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 // commit file data and attributes
err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( 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(type, file->id, size), buffer},
{LFS_MKTAG(LFS_FROM_USERATTRS, file->id, {LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
file->cfg->attr_count), file->cfg->attrs})); file->cfg->attr_count), file->cfg->attrs}));
@@ -2607,15 +2620,14 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
return err; return err;
} }
file->flags &= ~LFS_F_DIRTY; file->flags &= ~LFS_F_DIRTY & ~LFS_F_OUTLINE;
} }
return 0; return 0;
relocate: relocate:
// inline file doesn't fit anymore // inline file doesn't fit anymore
file->off = file->pos; err = lfs_file_outline(lfs, file);
err = lfs_file_relocate(lfs, file);
if (err) { if (err) {
file->flags |= LFS_F_ERRED; file->flags |= LFS_F_ERRED;
return err; 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_min(0x3fe, lfs_min(
lfs->cfg->cache_size, lfs->cfg->block_size/8))) { lfs->cfg->cache_size, lfs->cfg->block_size/8))) {
// inline file doesn't fit anymore // inline file doesn't fit anymore
file->off = file->pos; int err = lfs_file_outline(lfs, file);
lfs_alloc_ack(lfs);
int err = lfs_file_relocate(lfs, file);
if (err) { if (err) {
file->flags |= LFS_F_ERRED; file->flags |= LFS_F_ERRED;
return err; return err;

15
lfs.h
View File

@@ -122,13 +122,13 @@ enum lfs_type {
// File open flags // File open flags
enum lfs_open_flags { enum lfs_open_flags {
// open flags // open flags
LFS_O_RDONLY = 1, // Open a file as read only LFS_O_RDONLY = 1, // Open a file as read only
LFS_O_WRONLY = 2, // Open a file as write only LFS_O_WRONLY = 2, // Open a file as write only
LFS_O_RDWR = 3, // Open a file as read and write 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_CREAT = 0x0100, // Create a file if it does not exist
LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS_O_EXCL = 0x0200, // Fail if a file already exists
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size 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_APPEND = 0x0800, // Move to end of file on every write
// internally used flags // internally used flags
LFS_F_DIRTY = 0x010000, // File does not match storage 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_READING = 0x040000, // File has been read since last flush
LFS_F_ERRED = 0x080000, // An error occured during write LFS_F_ERRED = 0x080000, // An error occured during write
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
LFS_F_OUTLINE = 0x200000, // Need to delete inlined directory entry
}; };
// File seek flags // File seek flags