Removed .. and . entries

No longer need to be stored on disk, can be simulated on
the chip side. As mentioned in other commits, the parent
entries had dozens of problems with atomic updates, as
well as making everything just a bit more complex than
is needed.
This commit is contained in:
Christopher Haster
2017-04-15 11:26:37 -05:00
parent 1f13006e36
commit 3b1bcbe851
2 changed files with 56 additions and 60 deletions

114
lfs.c
View File

@@ -522,8 +522,7 @@ static int lfs_pair_shift(lfs_t *lfs, lfs_block_t pair[2],
/// Directory operations /// /// Directory operations ///
static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir, static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t tail[2]) {
lfs_block_t parent[2], lfs_block_t tail[2]) {
// Allocate pair of dir blocks // Allocate pair of dir blocks
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
int err = lfs_alloc(lfs, &dir->pair[i]); int err = lfs_alloc(lfs, &dir->pair[i]);
@@ -549,35 +548,10 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
dir->d.tail[1] = tail[1]; dir->d.tail[1] = tail[1];
// Write out to memory // Write out to memory
if (!parent) { return lfs_pair_commit(lfs, dir->pair,
return lfs_pair_commit(lfs, dir->pair, 1, (struct lfs_commit_region[]){
1, (struct lfs_commit_region[]){ {0, sizeof(dir->d), &dir->d}
{0, sizeof(dir->d), &dir->d} });
});
} else {
dir->d.size += 2*sizeof(struct lfs_disk_entry) + 3;
return lfs_pair_commit(lfs, dir->pair,
5, (struct lfs_commit_region[]){
{0, sizeof(dir->d), &dir->d},
{sizeof(dir->d), sizeof(struct lfs_disk_entry),
&(struct lfs_disk_entry){
.type = LFS_TYPE_DIR,
.len = sizeof(struct lfs_disk_entry)+1,
.u.dir[0] = dir->pair[0],
.u.dir[1] = dir->pair[1],
}},
{sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
{sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
sizeof(struct lfs_disk_entry),
&(struct lfs_disk_entry){
.type = LFS_TYPE_DIR,
.len = sizeof(struct lfs_disk_entry)+2,
.u.dir[0] = parent[0] ? parent[0] : dir->pair[0],
.u.dir[1] = parent[1] ? parent[1] : dir->pair[1],
}},
{sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
});
}
} }
static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) { static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
@@ -725,7 +699,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
lfs_dir_t olddir; lfs_dir_t olddir;
memcpy(&olddir, dir, sizeof(olddir)); memcpy(&olddir, dir, sizeof(olddir));
int err = lfs_dir_alloc(lfs, dir, 0, olddir.d.tail); int err = lfs_dir_alloc(lfs, dir, olddir.d.tail);
if (err) { if (err) {
return err; return err;
} }
@@ -763,7 +737,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
// Build up new directory // Build up new directory
lfs_dir_t dir; lfs_dir_t dir;
err = lfs_dir_alloc(lfs, &dir, cwd.pair, cwd.d.tail); err = lfs_dir_alloc(lfs, &dir, cwd.d.tail);
if (err) { if (err) {
return err; return err;
} }
@@ -799,6 +773,8 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
if (err) { if (err) {
return err; return err;
} else if (strcmp(path, "/") == 0) { } else if (strcmp(path, "/") == 0) {
// special offset for '.' and '..'
dir->off = sizeof(dir->d) - 2;
return 0; return 0;
} }
@@ -810,7 +786,14 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
return LFS_ERROR_NOT_DIR; return LFS_ERROR_NOT_DIR;
} }
return lfs_dir_fetch(lfs, dir, entry.d.u.dir); err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
if (err) {
return err;
}
// special offset for '.' and '..'
dir->off = sizeof(dir->d) - 2;
return 0;
} }
int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
@@ -821,6 +804,18 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
memset(info, 0, sizeof(*info)); memset(info, 0, sizeof(*info));
if (dir->off == sizeof(dir->d) - 2) {
info->type = LFS_TYPE_DIR;
strcpy(info->name, ".");
dir->off += 1;
return 1;
} else if (dir->off == sizeof(dir->d) - 1) {
info->type = LFS_TYPE_DIR;
strcpy(info->name, "..");
dir->off += 1;
return 1;
}
lfs_entry_t entry; lfs_entry_t entry;
int err = lfs_dir_next(lfs, dir, &entry); int err = lfs_dir_next(lfs, dir, &entry);
if (err) { if (err) {
@@ -1100,8 +1095,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
// Write root directory // Write root directory
lfs_dir_t root; lfs_dir_t root;
err = lfs_dir_alloc(lfs, &root, err = lfs_dir_alloc(lfs, &root, (lfs_block_t[2]){0, 0});
(lfs_block_t[2]){0, 0}, (lfs_block_t[2]){0, 0});
if (err) { if (err) {
return err; return err;
} }
@@ -1195,9 +1189,6 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
return err; return err;
} }
// skip '.' and '..'
dir.off += 2*sizeof(struct lfs_disk_entry) + 3;
// iterate over contents // iterate over contents
while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(file.entry.d)) { while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(file.entry.d)) {
int err = lfs_bd_read(lfs, dir.pair[0], dir.off, int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
@@ -1248,14 +1239,6 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) {
return err; return err;
} }
// skip .. and . entries
for (int i = 0; i < 2; i++) {
int err = lfs_dir_next(lfs, &parent, &entry);
if (err) {
return err;
}
}
while (true) { while (true) {
int err = lfs_dir_next(lfs, &parent, &entry); int err = lfs_dir_next(lfs, &parent, &entry);
if (err && err != LFS_ERROR_NO_ENTRY) { if (err && err != LFS_ERROR_NO_ENTRY) {
@@ -1339,12 +1322,13 @@ int lfs_remove(lfs_t *lfs, const char *path) {
lfs_dir_t dir; lfs_dir_t dir;
if (entry.d.type == LFS_TYPE_DIR) { if (entry.d.type == LFS_TYPE_DIR) {
// must be empty before removal // must be empty before removal, checking size
// without masking top bit checks for any case where
// dir is not empty
int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir); int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
if (err) { if (err) {
return err; return err;
} else if (dir.d.size != sizeof(dir.d) + } else if (dir.d.size != sizeof(dir.d)) {
2*sizeof(struct lfs_disk_entry) + 3) {
return LFS_ERROR_INVALID; return LFS_ERROR_INVALID;
} }
} }
@@ -1367,16 +1351,28 @@ int lfs_remove(lfs_t *lfs, const char *path) {
} }
} }
pdir.d.tail[0] = cwd.d.tail[0]; // TODO easier check for head block? (common case)
pdir.d.tail[1] = cwd.d.tail[1]; if (!(pdir.d.size & 0x80000000)) {
pdir.d.rev += 1; int err = lfs_pair_shift(lfs, entry.dir,
1, (struct lfs_commit_region[]) {
{0, sizeof(cwd.d), &cwd.d},
},
entry.off, entry.d.len);
if (err) {
return err;
}
} else {
pdir.d.tail[0] = cwd.d.tail[0];
pdir.d.tail[1] = cwd.d.tail[1];
pdir.d.rev += 1;
err = lfs_pair_commit(lfs, pdir.pair, err = lfs_pair_commit(lfs, pdir.pair,
1, (struct lfs_commit_region[]) { 1, (struct lfs_commit_region[]) {
{0, sizeof(pdir.d), &pdir.d}, {0, sizeof(pdir.d), &pdir.d},
}); });
if (err) { if (err) {
return err; return err;
}
} }
} else { } else {
int err = lfs_pair_shift(lfs, entry.dir, int err = lfs_pair_shift(lfs, entry.dir,

View File

@@ -17,7 +17,7 @@ tests/test.py << TEST
TEST TEST
# remove most recent file, this should be the update to the previous # remove most recent file, this should be the update to the previous
# linked-list entry and should orphan the child # linked-list entry and should orphan the child
rm -v "blocks/$(ls -t blocks | sed -n '/^[0-9a-f]*$/p' | sed -n '1p')" rm -v blocks/8
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &config) => 0; lfs_mount(&lfs, &config) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY;