Skip to content

Commit 97a7191

Browse files
committed
Fixed issue with creating files named "littlefs"
A rather humorous issue, we accidentally ended up mixing our file namespace with our superblocks. This meant if we created a file named "littlefs" it would reference the superblock and all sorts of things would break. Fixing this also highlighted another issue, the fact that the superblock always needs to come before any file entries in the directory. I didn't account for this in the initial B-tree design, but we need a higher ordering for superblocks + children + files than just name. To fix this I added ordering information in the 2 bits currently unused in the tag type. Though note that the size of these fields are flexible. 9-bit type field: [--- 9 ---] [1|- 3 -|- 2 -|- 3 -] ^ ^ ^ ^- type-specific info | | \------- ordering info | \------------- subtype \----------------- user bit
1 parent aeca766 commit 97a7191

File tree

4 files changed

+50
-40
lines changed

4 files changed

+50
-40
lines changed

lfs.c

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ static inline uint16_t lfs_tag_type(lfs_tag_t tag) {
287287
}
288288

289289
static inline uint16_t lfs_tag_subtype(lfs_tag_t tag) {
290-
return ((tag & 0x7c000000) >> 26) << 4;
290+
return ((tag & 0x78000000) >> 26) << 4;
291291
}
292292

293293
static inline uint16_t lfs_tag_id(lfs_tag_t tag) {
@@ -531,7 +531,7 @@ static int lfs_dir_traverse(lfs_t *lfs,
531531
}
532532
}
533533

534-
if (lfs_tag_subtype(tag) == LFS_TYPE_NAME) {
534+
if (lfs_tag_subtype(tag) == LFS_TYPE_CREATE) {
535535
// found where something was created
536536
if (lfs_tag_id(tag) == lfs_tag_id(matchtag - matchdiff)) {
537537
break;
@@ -673,7 +673,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
673673
}
674674

675675
// check for special tags
676-
if (lfs_tag_subtype(tag) == LFS_TYPE_NAME) {
676+
if (lfs_tag_subtype(tag) == LFS_TYPE_CREATE) {
677677
temp.count += 1;
678678

679679
if (tempfoundtag &&
@@ -822,7 +822,7 @@ static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir,
822822
static int lfs_dir_getglobals(lfs_t *lfs, const lfs_mdir_t *dir,
823823
struct lfs_globals *globals) {
824824
struct lfs_globals locals;
825-
lfs_stag_t res = lfs_dir_get(lfs, dir, 0x7c000000,
825+
lfs_stag_t res = lfs_dir_get(lfs, dir, 0x78000000,
826826
LFS_MKTAG(LFS_TYPE_GLOBALS, 0, 10), &locals);
827827
if (res < 0 && res != LFS_ERR_NOENT) {
828828
return res;
@@ -848,15 +848,15 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
848848
}
849849

850850
lfs_stag_t tag = lfs_dir_get(lfs, dir, 0x7c3fe000,
851-
LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name);
851+
LFS_MKTAG(LFS_TYPE_DIR, id, lfs->name_max+1), info->name);
852852
if (tag < 0) {
853853
return tag;
854854
}
855855

856856
info->type = lfs_tag_type(tag);
857857

858858
struct lfs_ctz ctz;
859-
tag = lfs_dir_get(lfs, dir, 0x7c3fe000,
859+
tag = lfs_dir_get(lfs, dir, 0x783fe000,
860860
LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
861861
if (tag < 0) {
862862
return tag;
@@ -893,13 +893,12 @@ static int lfs_dir_find_match(void *data,
893893
}
894894

895895
// found match?
896-
if (res == 0 && (name->size == lfs_tag_size(tag) ||
897-
lfs_tag_type(tag) == LFS_TYPE_SUPERBLOCK)) {
896+
if (res == 0 && name->size == lfs_tag_size(tag)) {
898897
return tag;
899898
}
900899

901900
// a greater name found, exit early
902-
if (res == 2 && lfs_tag_type(tag) != LFS_TYPE_SUPERBLOCK) {
901+
if (res > 1 && lfs_tag_type(tag) != LFS_TYPE_SUPERBLOCK) {
903902
return tag | 0x1fff;
904903
}
905904

@@ -969,7 +968,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
969968

970969
// grab the entry data
971970
if (lfs_tag_id(tag) != 0x1ff) {
972-
lfs_stag_t res = lfs_dir_get(lfs, dir, 0x7c3fe000,
971+
lfs_stag_t res = lfs_dir_get(lfs, dir, 0x783fe000,
973972
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail);
974973
if (res < 0) {
975974
return res;
@@ -980,7 +979,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
980979
// find entry matching name
981980
while (true) {
982981
tag = lfs_dir_fetchmatch(lfs, dir, dir->tail,
983-
0x7c000000, LFS_MKTAG(LFS_TYPE_NAME, 0, namelen),
982+
0x7c000000, LFS_MKTAG(LFS_TYPE_DIR, 0, namelen),
984983
lfs_dir_find_match, &(struct lfs_dir_find_match){
985984
lfs, name, namelen});
986985
if (tag < 0) {
@@ -1059,7 +1058,7 @@ static int lfs_commit_move_match(void *data,
10591058
struct lfs_commit *commit = move->commit;
10601059

10611060
if (move->pass == 0) {
1062-
if (lfs_tag_subtype(tag) != LFS_TYPE_NAME) {
1061+
if (lfs_tag_subtype(tag) != LFS_TYPE_CREATE) {
10631062
return 0;
10641063
}
10651064
} else {
@@ -1068,7 +1067,7 @@ static int lfs_commit_move_match(void *data,
10681067
.pair[0] = commit->block,
10691068
.off = commit->off,
10701069
.etag = commit->ptag}, NULL,
1071-
lfs_tag_isuser(tag) ? 0x7fffe000 : 0x7c3fe000, tag, 0,
1070+
lfs_tag_isuser(tag) ? 0x7fffe000 : 0x783fe000, tag, 0,
10721071
lfs_dir_get_match, &(struct lfs_dir_get_match){
10731072
lfs, NULL, 0, true});
10741073
if (res < 0 && res != LFS_ERR_NOENT) {
@@ -1578,7 +1577,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
15781577
lfs_tag_t createtag = 0xffffffff;
15791578
int attrcount = 0;
15801579
for (const struct lfs_mattr *a = attrs; a; a = a->next) {
1581-
if (lfs_tag_subtype(a->tag) == LFS_TYPE_NAME) {
1580+
if (lfs_tag_subtype(a->tag) == LFS_TYPE_CREATE) {
15821581
dir->count += 1;
15831582
createtag = a->tag;
15841583
} else if (lfs_tag_subtype(a->tag) == LFS_TYPE_DELETE) {
@@ -1795,7 +1794,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
17951794
pair[1] = lfs->root[1];
17961795
} else {
17971796
// get dir pair from parent
1798-
lfs_stag_t res = lfs_dir_get(lfs, &dir->m, 0x7c3fe000,
1797+
lfs_stag_t res = lfs_dir_get(lfs, &dir->m, 0x783fe000,
17991798
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
18001799
if (res < 0) {
18011800
return res;
@@ -2190,7 +2189,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
21902189
file->flags |= LFS_F_DIRTY;
21912190
} else {
21922191
// try to load what's on disk, if it's inlined we'll fix it later
2193-
tag = lfs_dir_get(lfs, &file->m, 0x7c3fe000,
2192+
tag = lfs_dir_get(lfs, &file->m, 0x783fe000,
21942193
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
21952194
if (tag < 0) {
21962195
err = tag;
@@ -2245,7 +2244,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
22452244

22462245
// don't always read (may be new/trunc file)
22472246
if (file->ctz.size > 0) {
2248-
lfs_stag_t res = lfs_dir_get(lfs, &file->m, 0x7c3fe000,
2247+
lfs_stag_t res = lfs_dir_get(lfs, &file->m, 0x783fe000,
22492248
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, file->ctz.size),
22502249
file->cache.buffer);
22512250
if (res < 0) {
@@ -2800,7 +2799,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
28002799
if (lfs_tag_type(tag) == LFS_TYPE_DIR) {
28012800
// must be empty before removal
28022801
lfs_block_t pair[2];
2803-
lfs_stag_t res = lfs_dir_get(lfs, &cwd, 0x7c3fe000,
2802+
lfs_stag_t res = lfs_dir_get(lfs, &cwd, 0x783fe000,
28042803
LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair);
28052804
if (res < 0) {
28062805
return res;
@@ -2880,7 +2879,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
28802879
} else if (lfs_tag_type(prevtag) == LFS_TYPE_DIR) {
28812880
// must be empty before removal
28822881
lfs_block_t prevpair[2];
2883-
lfs_stag_t res = lfs_dir_get(lfs, &newcwd, 0x7c3fe000,
2882+
lfs_stag_t res = lfs_dir_get(lfs, &newcwd, 0x783fe000,
28842883
LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair);
28852884
if (res < 0) {
28862885
return res;
@@ -3139,9 +3138,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
31393138

31403139
// write one superblock
31413140
lfs_superblock_t superblock = {
3142-
.magic = {"littlefs"},
3143-
.version = LFS_DISK_VERSION,
3144-
3141+
.version = LFS_DISK_VERSION,
31453142
.block_size = lfs->cfg->block_size,
31463143
.block_count = lfs->cfg->block_count,
31473144
.name_max = lfs->name_max,
@@ -3151,8 +3148,10 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
31513148

31523149
lfs_superblock_tole32(&superblock);
31533150
err = lfs_dir_commit(lfs, &root,
3154-
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, &superblock, sizeof(superblock),
3155-
NULL));
3151+
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
3152+
&superblock, sizeof(superblock),
3153+
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
3154+
NULL)));
31563155
if (err) {
31573156
goto cleanup;
31583157
}
@@ -3178,7 +3177,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
31783177
lfs_mdir_t dir = {.tail = {0, 1}};
31793178
while (!lfs_pair_isnull(dir.tail)) {
31803179
// fetch next block in tail list
3181-
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7fc00000,
3180+
lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, 0x7fffe000,
31823181
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8),
31833182
lfs_dir_find_match, &(struct lfs_dir_find_match){
31843183
lfs, "littlefs", 8});
@@ -3195,8 +3194,8 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
31953194

31963195
// grab superblock
31973196
lfs_superblock_t superblock;
3198-
tag = lfs_dir_get(lfs, &dir, 0x7f800000,
3199-
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
3197+
tag = lfs_dir_get(lfs, &dir, 0x7fffe000,
3198+
LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
32003199
&superblock);
32013200
if (tag < 0) {
32023201
err = tag;
@@ -3248,7 +3247,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
32483247

32493248
lfs->attr_max = superblock.attr_max;
32503249
}
3251-
32523250
}
32533251

32543252
// has globals?
@@ -3258,6 +3256,12 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
32583256
}
32593257
}
32603258

3259+
// found superblock?
3260+
if (lfs_pair_isnull(lfs->root)) {
3261+
err = LFS_ERR_INVAL;
3262+
goto cleanup;
3263+
}
3264+
32613265
// update littlefs with globals
32623266
lfs_global_fromle32(&lfs->locals);
32633267
lfs_global_xor(&lfs->globals, &lfs->locals);
@@ -3306,7 +3310,7 @@ int lfs_fs_traverse(lfs_t *lfs,
33063310

33073311
for (uint16_t id = 0; id < dir.count; id++) {
33083312
struct lfs_ctz ctz;
3309-
lfs_stag_t tag = lfs_dir_get(lfs, &dir, 0x7c3fe000,
3313+
lfs_stag_t tag = lfs_dir_get(lfs, &dir, 0x783fe000,
33103314
LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz);
33113315
if (tag < 0) {
33123316
if (tag == LFS_ERR_NOENT) {

lfs.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ enum lfs_error {
8888
// File types
8989
enum lfs_type {
9090
// file types
91-
LFS_TYPE_REG = 0x002,
92-
LFS_TYPE_DIR = 0x003,
91+
LFS_TYPE_REG = 0x011,
92+
LFS_TYPE_DIR = 0x010,
9393

9494
// internally used types
9595
LFS_TYPE_USERATTR = 0x100,
96-
LFS_TYPE_NAME = 0x000,
96+
LFS_TYPE_CREATE = 0x000,
9797
LFS_TYPE_DELETE = 0x020,
9898
LFS_TYPE_STRUCT = 0x040,
9999
LFS_TYPE_TAIL = 0x080,
@@ -110,8 +110,8 @@ enum lfs_type {
110110
// internal chip sources
111111
LFS_FROM_MEM = 0x000,
112112
LFS_FROM_DISK = 0x200,
113-
LFS_FROM_MOVE = 0x0c1,
114-
LFS_FROM_USERATTRS = 0x0c2,
113+
LFS_FROM_MOVE = 0x061,
114+
LFS_FROM_USERATTRS = 0x062,
115115
};
116116

117117
// File open flags
@@ -339,9 +339,7 @@ typedef struct lfs_file {
339339
} lfs_file_t;
340340

341341
typedef struct lfs_superblock {
342-
char magic[8];
343342
uint32_t version;
344-
345343
lfs_size_t block_size;
346344
lfs_size_t block_count;
347345

tests/debug.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import binascii
55

66
TYPES = {
7-
(0x1ff, 0x002): 'reg',
8-
(0x1ff, 0x003): 'dir',
7+
(0x1ff, 0x011): 'create reg',
8+
(0x1ff, 0x010): 'create dir',
99
(0x1ff, 0x001): 'superblock',
1010
(0x1ff, 0x020): 'delete',
1111
(0x1f0, 0x0e0): 'globals',
@@ -23,10 +23,10 @@ def typeof(type):
2323
mask = 0x1ff & ~((1 << prefix)-1)
2424
if (mask, type & mask) in TYPES:
2525
return TYPES[mask, type & mask] + (
26-
' [%0*x]' % (prefix/4, type & ((1 << prefix)-1))
26+
' %0*x' % (prefix/4, type & ((1 << prefix)-1))
2727
if prefix else '')
2828
else:
29-
return '[%02x]' % type
29+
return '%02x' % type
3030

3131
def main(*blocks):
3232
# find most recent block

tests/test_paths.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ tests/test.py << TEST
139139
lfs_unmount(&lfs) => 0;
140140
TEST
141141

142+
echo "--- Superblock conflict test ---"
143+
tests/test.py << TEST
144+
lfs_mount(&lfs, &cfg) => 0;
145+
lfs_mkdir(&lfs, "littlefs") => 0;
146+
lfs_remove(&lfs, "littlefs") => 0;
147+
lfs_unmount(&lfs) => 0;
148+
TEST
149+
142150
echo "--- Max path test ---"
143151
tests/test.py << TEST
144152
lfs_mount(&lfs, &cfg) => 0;

0 commit comments

Comments
 (0)