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 *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;

15
lfs.h
View File

@@ -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