Fixed missing mroot attrs lost during uninlining

Not sure how this was missed for so long, but we completely forget about
in-flight mroot attrs if we happen to uninline the mtree.

I guess this was missed because only some late-stage fs ops need to
commit mroot attrs (lfsr_fs_grow, lfsr_setattr, upgrades, etc), but
being able to commit to the mroot is definitely an operation we need to
support.

Fixing this in a non-awkward way was a bit tricky. We need some way to
commit both the provided attr-list and our new mtree, but all of the
lower layers only accept a single attr-list. The solution here
is to add a special tail-recursive LFSR_TAG_ATTRS that can be used to
chain together multiple attr-lists. This solves the problem quite
elegantly and may actually be useful in the future?

It takes a bit of code:

           code          stack
  before: 33850           2584
  after:  33926 (+0.2%)   2592 (+0.3%)

But this solves our final lfsr_fs_grow-related bug. No more mroot-split
hacks in test_grow, and we can now grow any stuck filesystem.
This commit is contained in:
Christopher Haster
2024-06-12 01:00:33 -05:00
parent 9ad59dcfe6
commit f024b35170
3 changed files with 454 additions and 189 deletions
+39 -12
View File
@@ -837,9 +837,10 @@ enum lfsr_tag {
// in-device only tags, these should never get written to disk
LFSR_TAG_INTERNAL = 0x0800,
LFSR_TAG_MOVE = 0x0800,
LFSR_TAG_SHRUBCOMMIT = 0x0801,
LFSR_TAG_SHRUBTRUNK = 0x0802,
LFSR_TAG_ATTRS = 0x0800,
LFSR_TAG_MOVE = 0x0801,
LFSR_TAG_SHRUBCOMMIT = 0x0802,
LFSR_TAG_SHRUBTRUNK = 0x0803,
// some in-device only tag modifiers
LFSR_TAG_RM = 0x8000,
@@ -1671,6 +1672,10 @@ typedef struct lfsr_data_name {
// hacky attrs - these end up handled as special cases in high-level
// commit layers
// chain another attr-list, only allowed as last attr
#define LFSR_ATTR_ATTRS(_tag, _weight, _attrs, _attr_count) \
LFSR_ATTR_(_tag, _weight, (const lfsr_attr_t*){_attrs}, _attr_count)
// a move of all attrs from an mdir entry
#define LFSR_ATTR_MOVE(_tag, _weight, _mdir) \
LFSR_ATTR_(_tag, _weight, (const lfsr_mdir_t*){_mdir}, 0)
@@ -6106,10 +6111,25 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
// we just happen to never split in an mdir commit
LFS_ASSERT(!(i > 0 && lfsr_attr_isinsert(attrs[i])));
// attr lists can be chained, but only tail-recursively
if (attrs[i].tag == LFSR_TAG_ATTRS) {
// must be the last tag
LFS_ASSERT(i == attr_count-1);
// how would weight make sense here?
LFS_ASSERT(attrs[i].weight == 0);
const lfsr_attr_t *attrs_ = attrs[i].cat;
lfs_size_t attr_count_ = attrs[i].count;
// switch to chained attr-list
attrs = attrs_;
attr_count = attr_count_;
i = -1;
continue;
// 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
if (attrs[i].tag == LFSR_TAG_MOVE) {
} else if (attrs[i].tag == LFSR_TAG_MOVE) {
// weighted moves are not supported
LFS_ASSERT(attrs[i].weight == 0);
const lfsr_mdir_t *mdir__ = attrs[i].cat;
@@ -7135,14 +7155,21 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// note end_rid=0 here will delete any files leftover from a split
// in our mroot
uint8_t mtree_buf[LFS_MAX(LFSR_MPTR_DSIZE, LFSR_BTREE_DSIZE)];
err = lfsr_mdir_commit_(lfs, &mroot_, -1, 0, NULL, -1, LFSR_ATTRS(
(lfsr_mtree_ismptr(&mtree_))
? LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_MDIR, 0,
LFSR_DATA_MPTR_(&mtree_.u.mptr.mptr, mtree_buf))
: LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_MTREE, 0,
LFSR_DATA_BTREE_(&mtree_.u.btree, mtree_buf))));
err = lfsr_mdir_commit_(lfs, &mroot_, -1, 0, NULL,
-1, LFSR_ATTRS(
(lfsr_mtree_ismptr(&mtree_))
? LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_MDIR, 0,
LFSR_DATA_MPTR_(&mtree_.u.mptr.mptr, mtree_buf))
: LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_MTREE, 0,
LFSR_DATA_BTREE_(&mtree_.u.btree, mtree_buf)),
// were we committing to the mroot? include any -1 attrs
(mdir->mid == -1)
? LFSR_ATTR_ATTRS(
LFSR_TAG_ATTRS, 0,
attrs, attr_count)
: LFSR_ATTR_NOOP()));
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
goto failed;
+8 -118
View File
@@ -442,7 +442,7 @@ code = '''
#
[cases.test_grow_incr_dir_many]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.REMOUNT = [false, true]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
code = '''
@@ -584,7 +584,7 @@ code = '''
'''
[cases.test_grow_incr_dir_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.REMOUNT = [false, true]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256]
defines.OPS = 1024
@@ -608,18 +608,6 @@ code = '''
assert(fsinfo.name_limit == LFS_NAME_MAX);
assert(fsinfo.file_limit == LFS_FILE_MAX);
// make mroot split, TODO fix this
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_mkdir(&lfs, name) => 0;
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_remove(&lfs, name) => 0;
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
lfs_size_t sim_size = 0;
@@ -822,7 +810,7 @@ code = '''
'''
[cases.test_grow_incr_file_many]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.REMOUNT = [false, true]
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.SIZE = [
@@ -853,18 +841,6 @@ code = '''
assert(fsinfo.name_limit == LFS_NAME_MAX);
assert(fsinfo.file_limit == LFS_FILE_MAX);
// make mroot split, TODO fix this
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_mkdir(&lfs, name) => 0;
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_remove(&lfs, name) => 0;
}
uint32_t prng = 42;
for (lfs_size_t i = 0; i < N; i++) {
again:;
@@ -982,7 +958,7 @@ code = '''
'''
[cases.test_grow_incr_file_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.REMOUNT = [false, true]
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.OPS = 1024
@@ -1016,18 +992,6 @@ code = '''
assert(fsinfo.name_limit == LFS_NAME_MAX);
assert(fsinfo.file_limit == LFS_FILE_MAX);
// make mroot split, TODO fix this
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_mkdir(&lfs, name) => 0;
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_remove(&lfs, name) => 0;
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
@@ -1291,7 +1255,7 @@ code = '''
'''
[cases.test_grow_incr_orphanzombie_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.OPS = 1024
defines.SIZE = [
@@ -1324,18 +1288,6 @@ code = '''
assert(fsinfo.name_limit == LFS_NAME_MAX);
assert(fsinfo.file_limit == LFS_FILE_MAX);
// make mroot split, TODO fix this
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_mkdir(&lfs, name) => 0;
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_remove(&lfs, name) => 0;
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
@@ -1729,7 +1681,7 @@ code = '''
'''
[cases.test_grow_incr_orphanzombiedir_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.OPS = 1024
defines.SIZE = [
@@ -1762,18 +1714,6 @@ code = '''
assert(fsinfo.name_limit == LFS_NAME_MAX);
assert(fsinfo.file_limit == LFS_FILE_MAX);
// make mroot split, TODO fix this
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_mkdir(&lfs, name) => 0;
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
lfsr_remove(&lfs, name) => 0;
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
@@ -2271,7 +2211,7 @@ code = '''
# wrong.
#
[cases.test_grow_incr_file_pl_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.OPS = 256
defines.SIZE = [
@@ -2309,31 +2249,6 @@ code = '''
assert(fsinfo.file_limit == LFS_FILE_MAX);
}
// make mroot split, TODO fix this
struct lfs_info info;
err = lfsr_stat(&lfs, "split", &info);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
if (lfs.mtree.u.weight == 0x80000000) {
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || err == LFS_ERR_EXIST);
}
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOENT);
}
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "split",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfsr_file_close(&lfs, &file) => 0;
}
// keep some test state on disk to survive powerloss
typedef struct fuzz_state {
lfs_size_t i;
@@ -2609,7 +2524,7 @@ code = '''
# wrong.
#
[cases.test_grow_incr_filedir_pl_fuzz]
defines.INIT_BLOCK_COUNT = 7 # TODO need to fix mroot split issue
defines.INIT_BLOCK_COUNT = 2
# note dirs x files grows O(n^2)
defines.N = [1, 2, 4, 8]
defines.M = 'N'
@@ -2649,31 +2564,6 @@ code = '''
assert(fsinfo.file_limit == LFS_FILE_MAX);
}
// make mroot split, TODO fix this
struct lfs_info info;
err = lfsr_stat(&lfs, "split", &info);
assert(!err || err == LFS_ERR_NOENT);
if (err == LFS_ERR_NOENT) {
if (lfs.mtree.u.weight == 0x80000000) {
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || err == LFS_ERR_EXIST);
}
}
for (lfs_size_t i = 0; i < 24; i++) {
char name[256];
sprintf(name, "splitme%03x", i);
err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOENT);
}
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "split",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfsr_file_close(&lfs, &file) => 0;
}
// keep some test state on disk to survive powerloss
typedef struct fuzz_state {
lfs_size_t i;
+407 -59
View File
@@ -168,11 +168,12 @@ code = '''
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined
assert(lfsr_mtree_weight(&lfs.mtree) == (1 << lfs.mdir_bits));
@@ -186,10 +187,14 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -206,10 +211,14 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -244,7 +253,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -264,6 +274,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -286,6 +300,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -320,7 +338,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -328,7 +347,7 @@ code = '''
assert(lfs.mroot.rbyd.weight == 0);
// now add another large entry to an mdir, forcing a split
memset(buffer+1, 'c', SIZE-1);
memset(buffer+1, 'd', SIZE-1);
lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1,
&mdir, NULL, NULL) => LFS_ERR_NOENT;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
@@ -337,7 +356,8 @@ code = '''
// force mdir to compact
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert mdir was split correctly
assert(lfsr_mtree_weight(&lfs.mtree) == (3 << lfs.mdir_bits));
@@ -357,11 +377,19 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (2 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
@@ -385,11 +413,19 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (2 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -606,7 +642,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -633,6 +670,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -649,6 +690,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -683,7 +728,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -712,6 +758,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -728,6 +778,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -833,7 +887,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -841,7 +896,7 @@ code = '''
assert(lfs.mroot.rbyd.weight == 0);
// now add another large entry to an mdir, forcing a split
memset(buffer+1, 'c', SIZE-1);
memset(buffer+1, 'd', SIZE-1);
lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1,
&mdir, NULL, NULL) => LFS_ERR_NOENT;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
@@ -870,11 +925,15 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
@@ -892,11 +951,15 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
lfsr_unmount(&lfs) => 0;
'''
@@ -932,7 +995,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -940,7 +1004,7 @@ code = '''
assert(lfs.mroot.rbyd.weight == 0);
// now add another large entry to an mdir, forcing a split
memset(buffer+1, 'c', SIZE-1);
memset(buffer+1, 'd', SIZE-1);
lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1,
&mdir, NULL, NULL) => LFS_ERR_NOENT;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
@@ -948,7 +1012,7 @@ code = '''
assert(mdir.rbyd.weight == 2);
// remove an entry, forcing the mdir to be dropped
memset(buffer+1, 'c', SIZE-1);
memset(buffer+1, 'd', SIZE-1);
lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1,
&mdir, NULL, NULL) => 0;
// force mdir to compact while we're removing
@@ -975,6 +1039,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -997,6 +1065,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -1157,11 +1229,12 @@ code = '''
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined
assert(lfsr_mtree_weight(&lfs.mtree) == (1 << lfs.mdir_bits));
@@ -1173,10 +1246,10 @@ code = '''
lfsr_mdir_t old_mdir = mdir;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(4), 0, LFSR_DATA_BUF("d", 1)))) => 0;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(5), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0);
@@ -1192,10 +1265,24 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1212,10 +1299,24 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -1252,7 +1353,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -1266,10 +1368,10 @@ code = '''
lfsr_mdir_t old_mdir = mdir;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("d", 1)))) => 0;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0);
@@ -1291,6 +1393,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (0 << lfs.mdir_bits)+1, &mdir) => 0;
assert(mdir.rbyd.weight == 2);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1313,6 +1429,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (0 << lfs.mdir_bits)+1, &mdir) => 0;
assert(mdir.rbyd.weight == 2);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -1349,7 +1479,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -1363,10 +1494,10 @@ code = '''
lfsr_mdir_t old_mdir = mdir;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("d", 1)))) => 0;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0);
@@ -1388,6 +1519,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1410,6 +1555,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -1440,9 +1599,11 @@ code = '''
// force mroot to compact twice, this should extend the mroot
lfsr_mdir_t old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("b", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -1453,6 +1614,14 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1464,6 +1633,14 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -1497,9 +1674,11 @@ code = '''
// force mroot to compact twice, this should extend the mroot
lfsr_mdir_t old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("b", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -1507,13 +1686,17 @@ code = '''
// twice, forcing a second mroot extension
old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("d", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(4), 0, LFSR_DATA_BUF("e", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(5), 0, LFSR_DATA_BUF("f", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(6), 0, LFSR_DATA_BUF("g", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -1524,6 +1707,30 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'f');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'g');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1535,6 +1742,30 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(5), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'f');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(6), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'g');
lfsr_unmount(&lfs) => 0;
'''
@@ -1565,18 +1796,22 @@ code = '''
// force mroot to compact twice, this should extend the mroot
lfsr_mdir_t old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("b", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
// force mroot to compact twice again, this should relocate the mroot
old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("d", 1)))) => 0;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(4), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -1587,6 +1822,22 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1598,6 +1849,22 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(4), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -1634,7 +1901,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -1651,10 +1919,10 @@ code = '''
lfsr_mdir_t old_mdir = mdir;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("d", 1)))) => 0;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("e", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0);
// assert mroot relocated
@@ -1678,6 +1946,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1700,6 +1982,20 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (1 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_unmount(&lfs) => 0;
'''
@@ -1736,7 +2032,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -1744,7 +2041,7 @@ code = '''
assert(lfs.mroot.rbyd.weight == 0);
// now add another large entry to an mdir, forcing a split
memset(buffer+1, 'c', SIZE-1);
memset(buffer+1, 'd', SIZE-1);
lfsr_mtree_namelookup(&lfs, &lfs.mtree, 0, (const char*)buffer+1, SIZE-1,
&mdir, NULL, NULL) => LFS_ERR_NOENT;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
@@ -1758,10 +2055,10 @@ code = '''
lfsr_mdir_t old_mdir = mdir;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("e", 1)))) => 0;
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("f", 1)))) => 0;
// assert we relocated
assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0);
// assert mroot relocated
@@ -1785,11 +2082,23 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (2 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'f');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
@@ -1813,11 +2122,23 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_mtree_lookup(&lfs, &lfs.mtree, (2 << lfs.mdir_bits)+0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_REG, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'c');
assert(buffer[1] == 'd');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'e');
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'f');
lfsr_unmount(&lfs) => 0;
'''
@@ -1855,7 +2176,8 @@ code = '''
// force mroot to compact
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mdirs were unininlined and split
assert(lfsr_mtree_weight(&lfs.mtree) == (2 << lfs.mdir_bits));
@@ -1872,7 +2194,7 @@ code = '''
// force mdir to compact twice, this should relocate
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_REG, 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF("d", 1)))) => 0;
// force mdir to compact while we're removing
mdir.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
@@ -1893,6 +2215,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1909,6 +2235,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'a');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -1940,12 +2270,13 @@ code = '''
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
LFSR_ATTR(LFSR_TAG_UATTR(2), 0, LFSR_DATA_BUF(buffer, SIZE)))) => 0;
// force mroot to compact, this should both uninline and relocate
lfsr_mdir_t old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(3), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mroot relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -1961,10 +2292,14 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -1981,10 +2316,14 @@ code = '''
lfsr_mtree_lookup(&lfs, &lfs.mtree, 0, &mdir) => 0;
assert(mdir.rbyd.weight == 1);
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_mdir_lookup(&lfs, &mdir, LFSR_TAG_UATTR(2), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[0] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(3), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''
@@ -2027,7 +2366,8 @@ code = '''
// force mroot to compact, this should both split and relocate
lfsr_mdir_t old_mroot = lfs.mroot;
lfs.mroot.rbyd.eoff = -1;
lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0;
lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS(
LFSR_ATTR(LFSR_TAG_UATTR(1), 0, LFSR_DATA_BUF("c", 1)))) => 0;
// assert mroot relocated
assert(lfsr_mdir_cmp(&old_mroot, &lfs.mroot) != 0);
@@ -2049,6 +2389,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
// check things stay sane after remount
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
@@ -2071,6 +2415,10 @@ code = '''
lfsr_data_read(&lfs, &data, buffer, SIZE) => SIZE;
assert(buffer[1] == 'b');
lfsr_mdir_lookup(&lfs, &lfs.mroot, LFSR_TAG_UATTR(1), &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 1) => 1;
assert(buffer[0] == 'c');
lfsr_unmount(&lfs) => 0;
'''