diff options
author | Christopher Haster <chaster@utexas.edu> | 2018-08-12 07:05:52 +0300 |
---|---|---|
committer | Christopher Haster <chaster@utexas.edu> | 2018-10-18 18:00:48 +0300 |
commit | 21217d75ada4d9c2e91b39c93c89cdd2568d8bbf (patch) | |
tree | a61f004168b6950614b44ef517edded825601853 | |
parent | 38011f4cd0e31295f1b25abf72d61e7c7f3827ec (diff) |
Dropped lfs_fs_getattr for the more implicit lfs_getattr("/")
This was a pretty simple oversight on my part. Conceptually, there's no
difference between lfs_fs_getattr and lfs_getattr("/"). Any operations
on directories can be applied "globally" by referring to the root
directory.
Implementation wise, this actually fixes the "corner case" of storing
attributes on the root directory, which is broken since the root
directory doesn't have a related entry. Instead we need to use the root
superblock for this purpose.
Fewer functions means less code to document and maintain, so this is a
nice benefit. Now we just have a single lfs_getattr/setattr/removeattr set
of functions along with the ability to access attributes atomically in
lfs_file_opencfg.
-rw-r--r-- | lfs.c | 141 | ||||
-rw-r--r-- | lfs.h | 31 | ||||
-rwxr-xr-x | tests/debug.py | 12 | ||||
-rwxr-xr-x | tests/test_attrs.sh | 54 |
4 files changed, 107 insertions, 131 deletions
@@ -540,7 +540,7 @@ static int lfs_commit_attrs(lfs_t *lfs, struct lfs_commit *commit, uint16_t id, const struct lfs_attr *attrs); static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit, - uint16_t fromid, uint16_t toid, + uint32_t frommask, uint32_t fromtag, uint32_t tomask, uint32_t totag, const lfs_mdir_t *dir, const lfs_mattr_t *attrs); static int lfs_commit_attr(lfs_t *lfs, struct lfs_commit *commit, @@ -548,7 +548,8 @@ static int lfs_commit_attr(lfs_t *lfs, struct lfs_commit *commit, if (lfs_tag_subtype(tag) == LFS_FROM_MOVE) { // special case for moves return lfs_commit_move(lfs, commit, - lfs_tag_size(tag), lfs_tag_id(tag), + 0x003ff000, LFS_MKTAG(0, lfs_tag_size(tag), 0), + 0x003ff000, LFS_MKTAG(0, lfs_tag_id(tag), 0), buffer, NULL); } else if (lfs_tag_subtype(tag) == LFS_FROM_ATTRS) { // special case for custom attributes @@ -617,7 +618,7 @@ static int lfs_commit_attrs(lfs_t *lfs, struct lfs_commit *commit, } static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit, - uint16_t fromid, uint16_t toid, + uint32_t frommask, uint32_t fromtag, uint32_t tomask, uint32_t totag, const lfs_mdir_t *dir, const lfs_mattr_t *attrs) { // iterate through list and commits, only committing unique entries lfs_off_t off = dir->off; @@ -650,17 +651,15 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit, } if (lfs_tag_type(tag) == LFS_TYPE_DELETE && - lfs_tag_id(tag) <= fromid) { + lfs_tag_id(tag) <= lfs_tag_id(fromtag)) { // something was deleted, we need to move around it - fromid += 1; - } else if (lfs_tag_id(tag) != fromid) { - // ignore non-matching ids - } else { + fromtag += LFS_MKTAG(0, 1, 0); + } else if ((tag & frommask) == (fromtag & frommask)) { // check if type has already been committed int32_t res = lfs_commit_get(lfs, commit->block, commit->off, commit->ptag, lfs_tag_isuser(tag) ? 0x7ffff000 : 0x7c3ff000, - (tag & 0x7fc00000) | LFS_MKTAG(0, toid, 0), + (tag & ~tomask) | totag, 0, NULL, true); if (res < 0 && res != LFS_ERR_NOENT) { return res; @@ -669,7 +668,7 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit, if (res == LFS_ERR_NOENT) { // update id and commit, as we are currently unique int err = lfs_commit_attr(lfs, commit, - (tag & 0xffc00fff) | LFS_MKTAG(0, toid, 0), + (tag & ~tomask) | totag, buffer); if (err) { return err; @@ -1068,8 +1067,7 @@ static int lfs_dir_compact(lfs_t *lfs, // do we have enough space to expand? if (res < lfs->cfg->block_count/2) { LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); - ack = 0; - exhausted = (lfs_pair_cmp(dir->pair, lfs->root) != 0); + exhausted = true; goto split; } } else { @@ -1118,7 +1116,9 @@ static int lfs_dir_compact(lfs_t *lfs, // commit with a move for (uint16_t id = begin; id < end; id++) { err = lfs_commit_move(lfs, &commit, - id, id - begin, source, attrs); + 0x003ff000, LFS_MKTAG(0, id, 0), + 0x003ff000, LFS_MKTAG(0, id - begin, 0), + source, attrs); if (err) { if (err == LFS_ERR_NOSPC) { goto split; @@ -1134,7 +1134,23 @@ static int lfs_dir_compact(lfs_t *lfs, // reopen reserved space at the end commit.end = lfs->cfg->block_size - 8; + if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { + // move over (duplicate) superblock if we are root + err = lfs_commit_move(lfs, &commit, + 0x7c000000, LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 0), + 0x7ffff000, LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 0), + source, attrs); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + if (!relocated) { + // commit any globals, unless we're relocating, in which case our + // parent will steal our globals err = lfs_commit_globals(lfs, &commit, &dir->locals); if (err) { if (err == LFS_ERR_CORRUPT) { @@ -1178,8 +1194,7 @@ split: // commit no longer fits, need to split dir, // drop caches and create tail lfs_cache_drop(lfs, &lfs->pcache); - - if (ack == -1) { + if (!exhausted && ack < 0) { // If we can't fit in this block, we won't fit in next block return LFS_ERR_NOSPC; } @@ -1190,11 +1205,16 @@ split: return err; } + if (exhausted) { + lfs->root[0] = tail.pair[0]; + lfs->root[1] = tail.pair[1]; + } + tail.split = dir->split; tail.tail[0] = dir->tail[0]; tail.tail[1] = dir->tail[1]; - err = lfs_dir_compact(lfs, &tail, attrs, source, ack+1-exhausted, end); + err = lfs_dir_compact(lfs, &tail, attrs, source, ack+1, end); if (err) { return err; } @@ -2770,9 +2790,19 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, return res; } + uint16_t id = lfs_tag_id(res); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + return err; + } + } + res = lfs_dir_get(lfs, &cwd, 0x7ffff000, - LFS_MKTAG(0x100 | type, lfs_tag_id(res), - lfs_min(size, lfs->attr_max)), buffer); + LFS_MKTAG(0x100 | type, id, lfs_min(size, lfs->attr_max)), + buffer); if (res < 0 && res != LFS_ERR_NOENT) { return res; } @@ -2792,8 +2822,18 @@ int lfs_setattr(lfs_t *lfs, const char *path, return res; } + uint16_t id = lfs_tag_id(res); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + return err; + } + } + return lfs_dir_commit(lfs, &cwd, - LFS_MKATTR(0x100 | type, lfs_tag_id(res), buffer, size, + LFS_MKATTR(0x100 | type, id, buffer, size, NULL)); } @@ -2941,9 +2981,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { lfs_superblock_tole32(&superblock); err = lfs_dir_commit(lfs, &root, - LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, &superblock, sizeof(superblock), - LFS_MKATTR(LFS_TYPE_ROOT, 1, NULL, 0, - NULL))); + LFS_MKATTR(LFS_TYPE_ROOT, 0, &superblock, sizeof(superblock), + NULL)); if (err) { goto cleanup; } @@ -2965,15 +3004,18 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { return err; } - // load superblock + // find root/superblock lfs_mdir_t root; - err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; + lfs_superblock_t superblock; + int32_t tag = lfs_dir_find(lfs, + &root, (const lfs_block_t[2]){0, 1}, false, 0x7fc00000, + LFS_MKTAG(LFS_TYPE_ROOT, 0, 8), "littlefs"); + if (tag < 0) { + err = tag; + goto cleanup; } - lfs_superblock_t superblock; - int32_t res = lfs_dir_get(lfs, &root, 0x7fc00000, + int32_t res = lfs_dir_get(lfs, &root, 0x7c000000, LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)), &superblock); if (res < 0) { @@ -2982,14 +3024,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { } lfs_superblock_fromle32(&superblock); - // find root - int32_t tag = lfs_dir_find(lfs, - &root, (const lfs_block_t[2]){0, 1}, false, 0x7fc00000, - LFS_MKTAG(LFS_TYPE_ROOT, 0, 0), NULL); - if (tag < 0) { - return tag; - } - lfs->root[0] = root.pair[0]; lfs->root[1] = root.pair[1]; @@ -3370,41 +3404,6 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { return 0; } -lfs_ssize_t lfs_fs_getattr(lfs_t *lfs, - uint8_t type, void *buffer, lfs_size_t size) { - lfs_mdir_t superdir; - int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; - } - - int32_t res = lfs_dir_get(lfs, &superdir, 0x7ffff000, - LFS_MKTAG(0x100 | type, 0, - lfs_min(size, lfs->attr_max)), buffer); - if (res < 0) { - return res; - } - - return (res == LFS_ERR_NOENT) ? 0 : lfs_tag_size(res); -} - -int lfs_fs_setattr(lfs_t *lfs, - uint8_t type, const void *buffer, lfs_size_t size) { - if (size > lfs->attr_max) { - return LFS_ERR_NOSPC; - } - - lfs_mdir_t superdir; - int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; - } - - return lfs_dir_commit(lfs, &superdir, - LFS_MKATTR(0x100 | type, 0, buffer, size, - NULL)); -} - static int lfs_fs_size_count(void *p, lfs_block_t block) { (void)block; lfs_size_t *size = p; @@ -94,7 +94,7 @@ enum lfs_type { // internally used types LFS_TYPE_USER = 0x100, LFS_TYPE_SUPERBLOCK = 0x011, - LFS_TYPE_ROOT = 0x012, + LFS_TYPE_ROOT = 0x010, LFS_TYPE_NAME = 0x000, LFS_TYPE_DELETE = 0x030, LFS_TYPE_STRUCT = 0x040, @@ -624,35 +624,6 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); // Returns a negative error code on failure. int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); -// Get custom attributes on the filesystem -// -// Custom attributes are uniquely identified by an 8-bit type and limited -// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than -// the buffer, it will be padded with zeros. If the stored attribute is larger, -// then it will be silently truncated. -// -// Note, filesystem-level attributes are not available for wear-leveling -// -// Returns the size of the attribute, or a negative error code on failure. -// Note, the returned size is the size of the attribute on disk, irrespective -// of the size of the buffer. This can be used to dynamically allocate a buffer -// or check for existance. -lfs_ssize_t lfs_fs_getattr(lfs_t *lfs, - uint8_t type, void *buffer, lfs_size_t size); - -// Set custom attributes on the filesystem -// -// Custom attributes are uniquely identified by an 8-bit type and limited -// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be -// implicitly created, and setting the size of an attribute to zero deletes -// the attribute. -// -// Note, filesystem-level attributes are not available for wear-leveling -// -// Returns a negative error code on failure. -int lfs_fs_setattr(lfs_t *lfs, - uint8_t type, const void *buffer, lfs_size_t size); - #ifdef __cplusplus } /* extern "C" */ diff --git a/tests/debug.py b/tests/debug.py index 58fb81e..65b0ad0 100755 --- a/tests/debug.py +++ b/tests/debug.py @@ -7,7 +7,7 @@ TYPES = { (0x1ff, 0x001): 'reg', (0x1ff, 0x002): 'dir', (0x1ff, 0x011): 'superblock', - (0x1ff, 0x012): 'root', + (0x1ff, 0x010): 'root', (0x1ff, 0x030): 'delete', (0x1f0, 0x080): 'globals', (0x1ff, 0x0c0): 'tail soft', @@ -50,9 +50,13 @@ def main(*blocks): crc = ncrc versions.append((nrev, '%s (rev %d)' % (block, nrev))) - except IOError: + except (IOError, struct.error): pass + if not file: + print 'Bad metadata pair {%s}' % ', '.join(blocks) + return 1 + print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True)) # go through each tag, print useful information @@ -93,6 +97,8 @@ def main(*blocks): if type == 0x0f0: crc = 0 + return 0 + if __name__ == "__main__": import sys - main(*sys.argv[1:]) + sys.exit(main(*sys.argv[1:])) diff --git a/tests/test_attrs.sh b/tests/test_attrs.sh index cb4f4dc..bbe78cc 100755 --- a/tests/test_attrs.sh +++ b/tests/test_attrs.sh @@ -77,55 +77,55 @@ tests/test.py << TEST lfs_unmount(&lfs) => 0; TEST -echo "--- Set/get fs attribute ---" +echo "--- Set/get root attribute ---" tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; - lfs_fs_setattr(&lfs, 'A', "aaaa", 4) => 0; - lfs_fs_setattr(&lfs, 'B', "bbbbbb", 6) => 0; - lfs_fs_setattr(&lfs, 'C', "ccccc", 5) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6; - lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; + lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; + lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; + lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer+4, "bbbbbb", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; - lfs_fs_setattr(&lfs, 'B', "", 0) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 0; - lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; + lfs_setattr(&lfs, "/", 'B', "", 0) => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; - lfs_fs_setattr(&lfs, 'B', "dddddd", 6) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 6; - lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; + lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer+4, "dddddd", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; - lfs_fs_setattr(&lfs, 'B', "eee", 3) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 3; - lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; + lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer+4, "eee\0\0\0", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; - lfs_fs_setattr(&lfs, 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; - lfs_fs_setattr(&lfs, 'B', "fffffffff", 9) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 6) => 9; - lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; + lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; + lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_unmount(&lfs) => 0; TEST tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; - lfs_fs_getattr(&lfs, 'A', buffer, 4) => 4; - lfs_fs_getattr(&lfs, 'B', buffer+4, 9) => 9; - lfs_fs_getattr(&lfs, 'C', buffer+13, 5) => 5; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; + lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; memcmp(buffer, "aaaa", 4) => 0; memcmp(buffer+4, "fffffffff", 9) => 0; memcmp(buffer+13, "ccccc", 5) => 0; |