Skip to content

Commit 51b2c7e

Browse files
committed
Changed custom attribute descriptors to used arrays
While linked-lists do have some minor benefits, arrays are more idiomatic in C and may provide a more intuitive API. Initially the linked-list approach was more beneficial than it is now, since it allowed custom attributes to be chained to internal linked lists of attributes. However, this was dropped because exposing the internal attribute list in this way created a rather messy user interface that required strictly encoding the attributes with the on-disk tag format. Minor downside, users can no longer introduce custom attributes in different layers (think OS vs app). Minor upside, the code size and stack usage was reduced a bit. Fortunately, this API can always be changed in the future without breaking anything (except maybe API compatibility).
1 parent 66d7515 commit 51b2c7e

File tree

3 files changed

+115
-119
lines changed

3 files changed

+115
-119
lines changed

lfs.c

Lines changed: 75 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -320,17 +320,17 @@ static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) {
320320
struct lfs_mattr {
321321
lfs_tag_t tag;
322322
const void *buffer;
323-
const struct lfs_mattr *next;
324323
};
325324

326-
#define LFS_MKATTR(type, id, buffer, size, next) \
327-
&(const struct lfs_mattr){LFS_MKTAG(type, id, size), (buffer), (next)}
328-
329325
struct lfs_diskoff {
330326
lfs_block_t block;
331327
lfs_off_t off;
332328
};
333329

330+
#define LFS_MKATTRS(...) \
331+
(struct lfs_mattr[]){__VA_ARGS__}, \
332+
sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr)
333+
334334
// operations on global state
335335
static inline void lfs_gstate_xor(struct lfs_gstate *a,
336336
const struct lfs_gstate *b) {
@@ -409,7 +409,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
409409

410410
/// Internal operations predeclared here ///
411411
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
412-
const struct lfs_mattr *attrs);
412+
const struct lfs_mattr *attrs, int attrcount);
413413
static int lfs_dir_compact(lfs_t *lfs,
414414
lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount,
415415
lfs_mdir_t *source, uint16_t begin, uint16_t end);
@@ -600,13 +600,9 @@ static int lfs_dir_traverse(lfs_t *lfs,
600600
buffer = &disk;
601601
ptag = tag;
602602
} else if (attrcount > 0) {
603-
const struct lfs_mattr *a = attrs;
604-
for (int j = 0; j < attrcount-1; j++) {
605-
a = a->next;
606-
}
607-
608-
tag = a->tag;
609-
buffer = a->buffer;
603+
tag = attrs[0].tag;
604+
buffer = attrs[0].buffer;
605+
attrs += 1;
610606
attrcount -= 1;
611607
} else if (!hasseenmove &&
612608
lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) {
@@ -647,7 +643,9 @@ static int lfs_dir_traverse(lfs_t *lfs,
647643
}
648644

649645
// handle special cases for mcu-side operations
650-
if (lfs_tag_type3(tag) == LFS_FROM_MOVE) {
646+
if (lfs_tag_type3(tag) == LFS_FROM_NOOP) {
647+
// do nothing
648+
} else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) {
651649
uint16_t fromid = lfs_tag_size(tag);
652650
uint16_t toid = lfs_tag_id(tag);
653651
int err = lfs_dir_traverse(lfs,
@@ -660,9 +658,10 @@ static int lfs_dir_traverse(lfs_t *lfs,
660658
return err;
661659
}
662660
} else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) {
663-
for (const struct lfs_attr *a = buffer; a; a = a->next) {
664-
int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a->type,
665-
lfs_tag_id(tag) + diff, a->size), a->buffer);
661+
for (unsigned i = 0; i < lfs_tag_size(tag); i++) {
662+
const struct lfs_attr *a = buffer;
663+
int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type,
664+
lfs_tag_id(tag) + diff, a[i].size), a[i].buffer);
666665
if (err) {
667666
return err;
668667
}
@@ -1266,9 +1265,8 @@ static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) {
12661265

12671266
// steal tail
12681267
lfs_pair_tole32(tail->tail);
1269-
err = lfs_dir_commit(lfs, dir,
1270-
LFS_MKATTR(LFS_TYPE_TAIL + tail->split, 0x3ff, tail->tail, 8,
1271-
NULL));
1268+
err = lfs_dir_commit(lfs, dir, LFS_MKATTRS(
1269+
{LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail}));
12721270
lfs_pair_fromle32(tail->tail);
12731271
if (err) {
12741272
return err;
@@ -1557,27 +1555,24 @@ static int lfs_dir_compact(lfs_t *lfs,
15571555
}
15581556

15591557
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
1560-
const struct lfs_mattr *attrs) {
1558+
const struct lfs_mattr *attrs, int attrcount) {
15611559
// calculate changes to the directory
15621560
lfs_tag_t deletetag = 0xffffffff;
15631561
lfs_tag_t createtag = 0xffffffff;
1564-
int attrcount = 0;
1565-
for (const struct lfs_mattr *a = attrs; a; a = a->next) {
1566-
if (lfs_tag_type3(a->tag) == LFS_TYPE_CREATE) {
1567-
createtag = a->tag;
1562+
for (int i = 0; i < attrcount; i++) {
1563+
if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) {
1564+
createtag = attrs[i].tag;
15681565
dir->count += 1;
1569-
} else if (lfs_tag_type3(a->tag) == LFS_TYPE_DELETE) {
1570-
deletetag = a->tag;
1566+
} else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) {
1567+
deletetag = attrs[i].tag;
15711568
LFS_ASSERT(dir->count > 0);
15721569
dir->count -= 1;
1573-
} else if (lfs_tag_type1(a->tag) == LFS_TYPE_TAIL) {
1574-
dir->tail[0] = ((lfs_block_t*)a->buffer)[0];
1575-
dir->tail[1] = ((lfs_block_t*)a->buffer)[1];
1576-
dir->split = (lfs_tag_chunk(a->tag) & 1);
1570+
} else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) {
1571+
dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0];
1572+
dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1];
1573+
dir->split = (lfs_tag_chunk(attrs[i].tag) & 1);
15771574
lfs_pair_fromle32(dir->tail);
15781575
}
1579-
1580-
attrcount += 1;
15811576
}
15821577

15831578
// do we have a pending move?
@@ -1755,9 +1750,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
17551750

17561751
// setup dir
17571752
lfs_pair_tole32(pred.tail);
1758-
err = lfs_dir_commit(lfs, &dir,
1759-
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, pred.tail, 8,
1760-
NULL));
1753+
err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS(
1754+
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail}));
17611755
lfs_pair_fromle32(pred.tail);
17621756
if (err) {
17631757
return err;
@@ -1768,9 +1762,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
17681762
// update tails, this creates a desync
17691763
lfs_fs_preporphans(lfs, +1);
17701764
lfs_pair_tole32(dir.pair);
1771-
err = lfs_dir_commit(lfs, &pred,
1772-
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, dir.pair, 8,
1773-
NULL));
1765+
err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS(
1766+
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair}));
17741767
lfs_pair_fromle32(dir.pair);
17751768
if (err) {
17761769
return err;
@@ -1780,14 +1773,13 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
17801773

17811774
// now insert into our parent block
17821775
lfs_pair_tole32(dir.pair);
1783-
err = lfs_dir_commit(lfs, &cwd,
1784-
LFS_MKATTR(LFS_TYPE_DIRSTRUCT, id, dir.pair, sizeof(dir.pair),
1785-
LFS_MKATTR(LFS_TYPE_DIR, id, path, nlen,
1786-
LFS_MKATTR(LFS_TYPE_CREATE, id, NULL, 0,
1787-
(!cwd.split)
1788-
? LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, dir.pair, 8,
1789-
NULL)
1790-
: NULL))));
1776+
err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
1777+
{LFS_MKTAG(LFS_TYPE_CREATE, id, 0)},
1778+
{LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path},
1779+
{LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair},
1780+
{!cwd.split
1781+
? LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8)
1782+
: LFS_MKTAG(LFS_FROM_NOOP, 0, 0), dir.pair}));
17911783
lfs_pair_fromle32(dir.pair);
17921784
if (err) {
17931785
return err;
@@ -2188,11 +2180,10 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
21882180
}
21892181

21902182
// get next slot and create entry to remember name
2191-
err = lfs_dir_commit(lfs, &file->m,
2192-
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0,
2193-
LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen,
2194-
LFS_MKATTR(LFS_TYPE_CREATE, file->id, NULL, 0,
2195-
NULL))));
2183+
err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
2184+
{LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0)},
2185+
{LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path},
2186+
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0)}));
21962187
if (err) {
21972188
err = LFS_ERR_NAMETOOLONG;
21982189
goto cleanup;
@@ -2221,20 +2212,21 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
22212212
}
22222213

22232214
// fetch attrs
2224-
for (const struct lfs_attr *a = file->cfg->attrs; a; a = a->next) {
2215+
for (unsigned i = 0; i < file->cfg->attr_count; i++) {
22252216
if ((file->flags & 3) != LFS_O_WRONLY) {
22262217
lfs_stag_t res = lfs_dir_get(lfs, &file->m,
22272218
LFS_MKTAG(0x7ff, 0x3ff, 0),
2228-
LFS_MKTAG(LFS_TYPE_USERATTR + a->type, file->id, a->size),
2229-
a->buffer);
2219+
LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type,
2220+
file->id, file->cfg->attrs[i].size),
2221+
file->cfg->attrs[i].buffer);
22302222
if (res < 0 && res != LFS_ERR_NOENT) {
22312223
err = res;
22322224
goto cleanup;
22332225
}
22342226
}
22352227

22362228
if ((file->flags & 3) != LFS_O_RDONLY) {
2237-
if (a->size > lfs->attr_max) {
2229+
if (file->cfg->attrs[i].size > lfs->attr_max) {
22382230
err = LFS_ERR_NOSPC;
22392231
goto cleanup;
22402232
}
@@ -2476,11 +2468,10 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
24762468
}
24772469

24782470
// commit file data and attributes
2479-
err = lfs_dir_commit(lfs, &file->m,
2480-
LFS_MKATTR(LFS_FROM_USERATTRS,
2481-
file->id, file->cfg->attrs, 0,
2482-
LFS_MKATTR(type, file->id, buffer, size,
2483-
NULL)));
2471+
err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
2472+
{LFS_MKTAG(type, file->id, size), buffer},
2473+
{LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
2474+
file->cfg->attr_count), file->cfg->attrs}));
24842475
if (err) {
24852476
if (err == LFS_ERR_NOSPC && (file->flags & LFS_F_INLINE)) {
24862477
goto relocate;
@@ -2850,9 +2841,8 @@ int lfs_remove(lfs_t *lfs, const char *path) {
28502841
}
28512842

28522843
// delete the entry
2853-
err = lfs_dir_commit(lfs, &cwd,
2854-
LFS_MKATTR(LFS_TYPE_DELETE, lfs_tag_id(tag), NULL, 0,
2855-
NULL));
2844+
err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
2845+
{LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0)}));
28562846
if (err) {
28572847
return err;
28582848
}
@@ -2943,21 +2933,22 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
29432933
lfs_fs_prepmove(lfs, newoldtagid, oldcwd.pair);
29442934

29452935
// move over all attributes
2946-
err = lfs_dir_commit(lfs, &newcwd,
2947-
LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tag_id(oldtag),
2948-
LFS_MKATTR(lfs_tag_type3(oldtag), newid, newpath, strlen(newpath),
2949-
LFS_MKATTR(LFS_TYPE_CREATE, newid, NULL, 0,
2950-
(prevtag != LFS_ERR_NOENT)
2951-
? LFS_MKATTR(LFS_TYPE_DELETE, newid, NULL, 0, NULL)
2952-
: NULL))));
2936+
err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS(
2937+
{prevtag != LFS_ERR_NOENT
2938+
? LFS_MKTAG(LFS_TYPE_DELETE, newid, 0)
2939+
: LFS_MKTAG(LFS_FROM_NOOP, 0, 0)},
2940+
{LFS_MKTAG(LFS_TYPE_CREATE, newid, 0)},
2941+
{LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)),
2942+
newpath},
2943+
{LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd}));
29532944
if (err) {
29542945
return err;
29552946
}
29562947

29572948
// let commit clean up after move (if we're different! otherwise move
29582949
// logic already fixed it for us)
29592950
if (lfs_pair_cmp(oldcwd.pair, newcwd.pair) != 0) {
2960-
err = lfs_dir_commit(lfs, &oldcwd, NULL);
2951+
err = lfs_dir_commit(lfs, &oldcwd, NULL, 0);
29612952
if (err) {
29622953
return err;
29632954
}
@@ -3031,9 +3022,8 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
30313022
}
30323023
}
30333024

3034-
return lfs_dir_commit(lfs, &cwd,
3035-
LFS_MKATTR(LFS_TYPE_USERATTR + type, id, buffer, size,
3036-
NULL));
3025+
return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
3026+
{LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer}));
30373027
}
30383028

30393029
int lfs_setattr(lfs_t *lfs, const char *path,
@@ -3198,12 +3188,11 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
31983188
};
31993189

32003190
lfs_superblock_tole32(&superblock);
3201-
err = lfs_dir_commit(lfs, &root,
3202-
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0,
3203-
&superblock, sizeof(superblock),
3204-
LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8,
3205-
LFS_MKATTR(LFS_TYPE_CREATE, 0, NULL, 0,
3206-
NULL))));
3191+
err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(
3192+
{LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)},
3193+
{LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
3194+
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
3195+
&superblock}));
32073196
if (err) {
32083197
goto cleanup;
32093198
}
@@ -3516,8 +3505,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
35163505
lfs_fs_preporphans(lfs, +1);
35173506

35183507
lfs_pair_tole32(newpair);
3519-
int err = lfs_dir_commit(lfs, &parent,
3520-
&(struct lfs_mattr){.tag=tag, .buffer=newpair});
3508+
int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS({tag, newpair}));
35213509
lfs_pair_fromle32(newpair);
35223510
if (err) {
35233511
return err;
@@ -3537,9 +3525,8 @@ static int lfs_fs_relocate(lfs_t *lfs,
35373525
if (err != LFS_ERR_NOENT) {
35383526
// replace bad pair, either we clean up desync, or no desync occured
35393527
lfs_pair_tole32(newpair);
3540-
err = lfs_dir_commit(lfs, &parent,
3541-
LFS_MKATTR(LFS_TYPE_TAIL + parent.split, 0x3ff, newpair, 8,
3542-
NULL));
3528+
err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS(
3529+
{LFS_MKTAG(LFS_TYPE_TAIL + parent.split, 0x3ff, 8), newpair}));
35433530
lfs_pair_fromle32(newpair);
35443531
if (err) {
35453532
return err;
@@ -3600,7 +3587,7 @@ static int lfs_fs_demove(lfs_t *lfs) {
36003587
}
36013588

36023589
// rely on cancel logic inside commit
3603-
err = lfs_dir_commit(lfs, &movedir, NULL);
3590+
err = lfs_dir_commit(lfs, &movedir, NULL, 0);
36043591
if (err) {
36053592
return err;
36063593
}
@@ -3660,9 +3647,8 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
36603647
pair[0], pair[1]);
36613648

36623649
lfs_pair_tole32(pair);
3663-
err = lfs_dir_commit(lfs, &pdir,
3664-
LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, pair, 8,
3665-
NULL));
3650+
err = lfs_dir_commit(lfs, &pdir, LFS_MKATTRS(
3651+
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pair}));
36663652
lfs_pair_fromle32(pair);
36673653
if (err) {
36683654
return err;

lfs.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ enum lfs_type {
123123
LFS_TYPE_MOVESTATE = 0x7ff,
124124

125125
// internal chip sources
126+
LFS_FROM_NOOP = 0x000,
126127
LFS_FROM_MOVE = 0x101,
127128
LFS_FROM_USERATTRS = 0x102,
128129
};
@@ -268,7 +269,8 @@ struct lfs_info {
268269
char name[LFS_NAME_MAX+1];
269270
};
270271

271-
// Custom attribute structure
272+
// Custom attribute structure, used to describe custom attributes
273+
// committed atomically during file writes.
272274
struct lfs_attr {
273275
// 8-bit type of attribute, provided by user and used to
274276
// identify the attribute
@@ -279,9 +281,6 @@ struct lfs_attr {
279281

280282
// Size of attribute in bytes, limited to LFS_ATTR_MAX
281283
lfs_size_t size;
282-
283-
// Pointer to next attribute in linked list
284-
struct lfs_attr *next;
285284
};
286285

287286
// Optional configuration provided during lfs_file_opencfg
@@ -290,8 +289,8 @@ struct lfs_file_config {
290289
// By default lfs_malloc is used to allocate this buffer.
291290
void *buffer;
292291

293-
// Optional linked list of custom attributes related to the file. If the
294-
// file is opened with read access, the attributes will be read from
292+
// Optional list of custom attributes related to the file. If the file
293+
// is opened with read access, these attributes will be read from disk
295294
// during the open call. If the file is opened with write access, the
296295
// attributes will be written to disk every file sync or close. This
297296
// write occurs atomically with update to the file's contents.
@@ -302,6 +301,9 @@ struct lfs_file_config {
302301
// is larger, then it will be silently truncated. If the attribute is not
303302
// found, it will be created implicitly.
304303
struct lfs_attr *attrs;
304+
305+
// Number of custom attributes in the list
306+
lfs_size_t attr_count;
305307
};
306308

307309

0 commit comments

Comments
 (0)