Fixed/implemented renaming open files
This requires two things: 1. Any opened file handles need to have their mid/mdir updated after the rename succeeds. 2. Any shrubs/sprouts need to be copied over to the new mdir, even if they aren't in-tree. The LFSR_TAG_MOVE operation is starting to look an awfully lot like lfsr_mdir_compact... Unfortunately lfsr_mdir_compact, uh, compacts, whereas LFSR_TAG_MOVE appends to the rbyd like normal, so it's not clear exactly _how_ to deduplicate.
This commit is contained in:
@@ -4723,15 +4723,17 @@ static lfs_ssize_t lfsr_sprout_estimate(lfs_t *lfs,
|
|||||||
return LFSR_TAG_DSIZE + lfsr_data_size(sprout);
|
return LFSR_TAG_DSIZE + lfsr_data_size(sprout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfsr_sprout_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
|
static int lfsr_sprout_compact(lfs_t *lfs, const lfsr_rbyd_t *rbyd_,
|
||||||
lfsr_data_t *sprout_, const lfsr_data_t *sprout, bool orphan) {
|
lfsr_data_t *sprout_, const lfsr_data_t *sprout) {
|
||||||
// write out bsprout
|
// this gets a bit weird, since upper layers need to do the actual
|
||||||
int err = lfsr_rbyd_appendcompactattr(lfs, rbyd_,
|
// compaction, we just update internal state here
|
||||||
(orphan) ? LFSR_TAG_SHRUB(DATA) : LFSR_TAG_DATA, 0,
|
|
||||||
*sprout);
|
// this is a bit tricky since we don't know the tag size,
|
||||||
if (err) {
|
// but we have just enough info
|
||||||
return err;
|
lfsr_data_t sprout__ = LFSR_DATA_DISK(
|
||||||
}
|
rbyd_->blocks[0],
|
||||||
|
rbyd_->eoff - lfsr_data_size(sprout),
|
||||||
|
lfsr_data_size(sprout));
|
||||||
|
|
||||||
// stage any opened inlined files with their new location so we
|
// stage any opened inlined files with their new location so we
|
||||||
// can update these later if our commit is a success
|
// can update these later if our commit is a success
|
||||||
@@ -4744,21 +4746,11 @@ static int lfsr_sprout_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
|
|||||||
&& lfsr_sprout_cmp(
|
&& lfsr_sprout_cmp(
|
||||||
&file_->ftree.u.bsprout,
|
&file_->ftree.u.bsprout,
|
||||||
sprout) == 0) {
|
sprout) == 0) {
|
||||||
// this is a bit tricky since we don't know the tag size,
|
file_->ftree_.u.bsprout = sprout__;
|
||||||
// but we have just enough info
|
|
||||||
file_->ftree_.u.bsprout = LFSR_DATA_DISK(
|
|
||||||
rbyd_->blocks[0],
|
|
||||||
rbyd_->eoff - lfsr_data_size(sprout),
|
|
||||||
lfsr_data_size(sprout));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a bit tricky since we don't know the tag size,
|
*sprout_ = sprout__;
|
||||||
// but we have just enough info
|
|
||||||
*sprout_ = LFSR_DATA_DISK(
|
|
||||||
rbyd_->blocks[0],
|
|
||||||
rbyd_->eoff - lfsr_data_size(sprout),
|
|
||||||
lfsr_data_size(sprout));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5427,6 +5419,8 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
// do nothing
|
// do nothing
|
||||||
|
|
||||||
// move tags copy over any tags associated with the source's rid
|
// move tags copy over any tags associated with the source's rid
|
||||||
|
// TODO can this be deduplicated with lfsr_mdir_compact__ more?
|
||||||
|
// it _really_ wants to be deduplicated
|
||||||
} else if (attrs[i].tag == LFSR_TAG_MOVE) {
|
} else if (attrs[i].tag == LFSR_TAG_MOVE) {
|
||||||
// weighted moves are not supported
|
// weighted moves are not supported
|
||||||
LFS_ASSERT(attrs[i].delta == 0);
|
LFS_ASSERT(attrs[i].delta == 0);
|
||||||
@@ -5447,8 +5441,25 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// special case for bshrubs, we need to copy these over
|
// found an inlined sprout? we can just copy this like
|
||||||
if (tag == LFSR_TAG_BSHRUB) {
|
// normal but we need to update any opened inlined files
|
||||||
|
if (tag == LFSR_TAG_DATA) {
|
||||||
|
err = lfsr_rbyd_appendattr(lfs, &rbyd_,
|
||||||
|
rid - lfs_smax32(start_rid, 0),
|
||||||
|
tag, 0, data);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lfsr_sprout_compact(lfs, &rbyd_, &data,
|
||||||
|
&data);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found an inlined shrub? we need to compact the shrub
|
||||||
|
// as well to bring it along with us
|
||||||
|
} else if (tag == LFSR_TAG_BSHRUB) {
|
||||||
lfsr_shrub_t shrub;
|
lfsr_shrub_t shrub;
|
||||||
err = lfsr_data_readshrub(lfs, &data, mdir__,
|
err = lfsr_data_readshrub(lfs, &data, mdir__,
|
||||||
&shrub);
|
&shrub);
|
||||||
@@ -5484,6 +5495,55 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we're not quite done! we also need to bring over any
|
||||||
|
// unsynced files
|
||||||
|
for (lfsr_opened_t *opened = lfs->opened;
|
||||||
|
opened;
|
||||||
|
opened = opened->next) {
|
||||||
|
lfsr_file_t *file = (lfsr_file_t*)opened;
|
||||||
|
// belongs to our mid?
|
||||||
|
if (file->type != LFS_TYPE_REG
|
||||||
|
|| file->mdir.mid != mdir__->mid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inlined sprout?
|
||||||
|
if (lfsr_ftree_isbsprout(&file->mdir, &file->ftree)
|
||||||
|
// only compact once, first compact should stage
|
||||||
|
// the new block
|
||||||
|
&& file->ftree_.u.bsprout.u.disk.block
|
||||||
|
!= rbyd_.blocks[0]) {
|
||||||
|
int err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_,
|
||||||
|
LFSR_TAG_SHRUB(DATA), 0,
|
||||||
|
file->ftree.u.bsprout);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lfsr_sprout_compact(lfs, &rbyd_,
|
||||||
|
&file->ftree_.u.bsprout,
|
||||||
|
&file->ftree.u.bsprout);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inlined shrub?
|
||||||
|
} else if (lfsr_ftree_isbshrub(&file->mdir, &file->ftree)
|
||||||
|
// only compact once, first compact should stage
|
||||||
|
// the new block
|
||||||
|
&& file->ftree.u.bshrub.blocks[0]
|
||||||
|
!= rbyd_.blocks[0]) {
|
||||||
|
int err = lfsr_shrub_compact(lfs, &rbyd_,
|
||||||
|
&file->ftree_.u.bshrub, &file->ftree.u.bshrub);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// shrub tags append a set of attributes to an unrelated trunk
|
// shrub tags append a set of attributes to an unrelated trunk
|
||||||
// in our rbyd
|
// in our rbyd
|
||||||
} else if (attrs[i].tag == LFSR_TAG_SHRUBALLOC
|
} else if (attrs[i].tag == LFSR_TAG_SHRUBALLOC
|
||||||
@@ -5753,9 +5813,15 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
|||||||
// found an inlined sprout? we can just copy this like normal but
|
// found an inlined sprout? we can just copy this like normal but
|
||||||
// we need to update any opened inlined files
|
// we need to update any opened inlined files
|
||||||
if (tag == LFSR_TAG_DATA) {
|
if (tag == LFSR_TAG_DATA) {
|
||||||
LFS_ASSERT(weight == 0);
|
err = lfsr_rbyd_appendcompactattr(lfs, &mdir_->rbyd,
|
||||||
|
tag, weight, data);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = lfsr_sprout_compact(lfs, &mdir_->rbyd, &data,
|
err = lfsr_sprout_compact(lfs, &mdir_->rbyd, &data,
|
||||||
&data, false);
|
&data);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
return err;
|
return err;
|
||||||
@@ -5825,9 +5891,15 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
|||||||
// only compact once, first compact should stage the new block
|
// only compact once, first compact should stage the new block
|
||||||
&& file->ftree_.u.bsprout.u.disk.block
|
&& file->ftree_.u.bsprout.u.disk.block
|
||||||
!= mdir_->rbyd.blocks[0]) {
|
!= mdir_->rbyd.blocks[0]) {
|
||||||
|
err = lfsr_rbyd_appendcompactattr(lfs, &mdir_->rbyd,
|
||||||
|
LFSR_TAG_SHRUB(DATA), 0, file->ftree.u.bsprout);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = lfsr_sprout_compact(lfs, &mdir_->rbyd,
|
err = lfsr_sprout_compact(lfs, &mdir_->rbyd,
|
||||||
&file->ftree_.u.bsprout,
|
&file->ftree_.u.bsprout, &file->ftree.u.bsprout);
|
||||||
&file->ftree.u.bsprout, true);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
return err;
|
return err;
|
||||||
@@ -6591,7 +6663,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
|||||||
if (opened->mdir.mid < attrs[i].rid - attrs[i].delta) {
|
if (opened->mdir.mid < attrs[i].rid - attrs[i].delta) {
|
||||||
// mark as zombied and move onto the next rid, upper
|
// mark as zombied and move onto the next rid, upper
|
||||||
// layers should handle the repercussions
|
// layers should handle the repercussions
|
||||||
opened->flags |= LFS_F_ZOMBIE;
|
opened->flags |= LFS_F_ZOMBIE | LFS_F_UNSYNC | LFS_O_DESYNC;
|
||||||
|
opened->flags &= ~LFS_F_UNCREAT;
|
||||||
opened->mdir.mid = attrs[i].rid;
|
opened->mdir.mid = attrs[i].rid;
|
||||||
} else {
|
} else {
|
||||||
opened->mdir.mid += attrs[i].delta;
|
opened->mdir.mid += attrs[i].delta;
|
||||||
@@ -8396,7 +8469,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
|
|||||||
? LFSR_ATTR(mdir.mid, RM, -1, NULL())
|
? LFSR_ATTR(mdir.mid, RM, -1, NULL())
|
||||||
: LFSR_ATTR_NOOP(),
|
: LFSR_ATTR_NOOP(),
|
||||||
LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{
|
LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{
|
||||||
mdir.mid + ((exists) ? 1 : 0),
|
mdir.mid,
|
||||||
-1}})))));
|
-1}})))));
|
||||||
if (err) {
|
if (err) {
|
||||||
goto failed_with_bookmark;
|
goto failed_with_bookmark;
|
||||||
@@ -8413,18 +8486,6 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark any zombied files as created to avoid a remove from beyond
|
|
||||||
// the grave
|
|
||||||
for (lfsr_opened_t *opened = lfs->opened;
|
|
||||||
opened;
|
|
||||||
opened = opened->next) {
|
|
||||||
if (opened->type == LFS_TYPE_REG
|
|
||||||
&& opened->mdir.mid == mdir.mid) {
|
|
||||||
LFS_ASSERT(lfsr_f_iszombie(opened->flags));
|
|
||||||
opened->flags &= ~LFS_F_UNCREAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed_with_bookmark:
|
failed_with_bookmark:
|
||||||
@@ -8712,15 +8773,15 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark any zombied files as created to avoid a remove from beyond
|
// update moved files with the new mdir
|
||||||
// the grave
|
|
||||||
for (lfsr_opened_t *opened = lfs->opened;
|
for (lfsr_opened_t *opened = lfs->opened;
|
||||||
opened;
|
opened;
|
||||||
opened = opened->next) {
|
opened = opened->next) {
|
||||||
if (opened->type == LFS_TYPE_REG
|
if (opened->type == LFS_TYPE_REG
|
||||||
&& opened->mdir.mid == new_mdir.mid) {
|
// TODO should we have lfsr_grm_isrm or something?
|
||||||
LFS_ASSERT(lfsr_f_iszombie(opened->flags));
|
&& (opened->mdir.mid == lfs->grm.rms[0]
|
||||||
opened->flags &= ~LFS_F_UNCREAT;
|
|| opened->mdir.mid == lfs->grm.rms[1])) {
|
||||||
|
opened->mdir = new_mdir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9308,11 +9369,10 @@ int lfsr_file_open(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file);
|
int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file);
|
||||||
|
|
||||||
int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) {
|
int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) {
|
||||||
// don't call lfsr_file_sync if we're readonly, desynced, or zombied
|
// don't call lfsr_file_sync if we're readonly or desynced
|
||||||
int err = 0;
|
int err = 0;
|
||||||
if (!lfsr_o_isrdonly(file->flags)
|
if (!lfsr_o_isrdonly(file->flags)
|
||||||
&& !lfsr_o_isdesync(file->flags)
|
&& !lfsr_o_isdesync(file->flags)) {
|
||||||
&& !lfsr_f_iszombie(file->flags)) {
|
|
||||||
err = lfsr_file_sync(lfs, file);
|
err = lfsr_file_sync(lfs, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11034,9 +11094,8 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
// notify all files of creation
|
// notify all files of creation
|
||||||
file_->flags &= ~LFS_F_UNCREAT;
|
file_->flags &= ~LFS_F_UNCREAT;
|
||||||
|
|
||||||
// mark desynced/zombied files an unsynced
|
// mark desynced files an unsynced
|
||||||
if (lfsr_o_isdesync(file_->flags)
|
if (lfsr_o_isdesync(file_->flags)) {
|
||||||
|| lfsr_f_iszombie(file_->flags)) {
|
|
||||||
file_->flags |= LFS_F_UNSYNC;
|
file_->flags |= LFS_F_UNSYNC;
|
||||||
|
|
||||||
// update synced files
|
// update synced files
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ code = '''
|
|||||||
|
|
||||||
# one purpose of this test is to check that data is not hidden
|
# one purpose of this test is to check that data is not hidden
|
||||||
# and then revealed by truncate, that would be bad
|
# and then revealed by truncate, that would be bad
|
||||||
[cases.test_fwrite_truncate_2]
|
[cases.test_fwrite_truncate_truncate]
|
||||||
defines.FROM = [
|
defines.FROM = [
|
||||||
'0',
|
'0',
|
||||||
'CACHE_SIZE/2',
|
'CACHE_SIZE/2',
|
||||||
@@ -832,7 +832,7 @@ code = '''
|
|||||||
|
|
||||||
# one purpose of this test is to check that data is not hidden
|
# one purpose of this test is to check that data is not hidden
|
||||||
# and then revealed by fruncate, that would be bad
|
# and then revealed by fruncate, that would be bad
|
||||||
[cases.test_fwrite_fruncate_2]
|
[cases.test_fwrite_fruncate_fruncate]
|
||||||
defines.FROM = [
|
defines.FROM = [
|
||||||
'0',
|
'0',
|
||||||
'CACHE_SIZE/2',
|
'CACHE_SIZE/2',
|
||||||
|
|||||||
Reference in New Issue
Block a user