Reworked how filesystem-level config is stored

Now, instead of storing a single contiguous block of config data, config
is stored as tagged metadata like any other attribute.

This allows more flexibility towards adding/removing config in the
future, without cluttering up the config with deprecated entries (see
ATA's "IDENTIFY DEVICE" response).

Most of the config entries are single leb128 limits on various integer
types, with the exception of the magic string and version (major/minor
pair).

---

Note this also includes some semantic changes to the config:

- Limits are stored as size-1. This avoid issues with integer overflow
  at extreme ranges.

  This was also adopted for block size (block limit) and block count
  (disk limit). This deviation between on-disk config and user-facing
  config risks confusion, but allows the potential for the full 2^31 range
  for these values.

- The default cksum type, crc32c, has been changed to 0.

  Originally this was 2 to allow the type to map to the crc width for
  crc8, crc16, crc32c, crc64, etc. But dropping this idea and numbering
  checksums as they are implemented simplifies things.

  May come back to this.

- Storing these configs as attributes opens up of the option of on-disk
  defaults when configs are missing.

  I'm being a bit conservative with this one, as it's not clear to me if
  we should prefer default configs (less code/storage, risk of untested
  config parsing) or prefer explicit on-disk configs.

  Currently the following have defaults since they seem the most obvious
  to me:

  - cksum type  => defaults to crc32c
  - redund type => defaults to parity (TODO, should this default to
    no redund?)
  - utag_limit  => defaults to 0x7f (no special tag decoding)
  - uattr_limit => defaults to block_limit (implicit)
This commit is contained in:
Christopher Haster
2023-09-15 14:50:47 -05:00
parent 5f3994c83b
commit c1fe64314c
6 changed files with 715 additions and 391 deletions
+396 -280
View File
@@ -578,8 +578,19 @@ static int lfsr_bd_erase(lfs_t *lfs, lfs_block_t block) {
enum lfsr_tag_type {
LFSR_TAG_NULL = 0x0000,
LFSR_TAG_SUPERMAGIC = 0x0003,
LFSR_TAG_SUPERCONFIG = 0x0004,
LFSR_TAG_CONFIG = 0x0000,
LFSR_TAG_MAGIC = 0x0003,
LFSR_TAG_VERSION = 0x0004,
LFSR_TAG_FLAGS = 0x0005,
LFSR_TAG_CKSUMTYPE = 0x0006,
LFSR_TAG_REDUNDTYPE = 0x0007,
LFSR_TAG_BLOCKLIMIT = 0x0008,
LFSR_TAG_DISKLIMIT = 0x0009,
LFSR_TAG_MLEAFLIMIT = 0x000a,
LFSR_TAG_SIZELIMIT = 0x000b,
LFSR_TAG_NAMELIMIT = 0x000c,
LFSR_TAG_UTAGLIMIT = 0x000d,
LFSR_TAG_UATTRLIMIT = 0x000e,
LFSR_TAG_GSTATE = 0x0100,
LFSR_TAG_GRM = 0x0100,
@@ -6187,80 +6198,81 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
/// Superblock things ///
// These are all leb128s, but we can expect smaller encodings
// if we assume the version.
//// TODO rm?
//// These are all leb128s, but we can expect smaller encodings
//// if we assume the version.
////
//// - 7-bit major_version => 1 byte leb128 (worst case)
//// - 7-bit minor_version => 1 byte leb128 (worst case)
//// - 7-bit cksum_type => 1 byte leb128 (worst case)
//// - 7-bit flags => 1 byte leb128 (worst case)
//// - 32-bit block_size => 5 byte leb128 (worst case)
//// - 32-bit block_count => 5 byte leb128 (worst case)
//// - 7-bit utag_limit => 1 byte leb128 (worst case)
//// - 32-bit mtree_limit => 5 byte leb128 (worst case)
//// - 32-bit attr_limit => 5 byte leb128 (worst case)
//// - 32-bit name_limit => 5 byte leb128 (worst case)
//// - 32-bit file_limit => 5 byte leb128 (worst case)
//// => 33 bytes total
////
//#define LFSR_SUPERCONFIG_DSIZE (1+1+1+1+5+5+1+5+5+5+5)
//
// - 7-bit major_version => 1 byte leb128 (worst case)
// - 7-bit minor_version => 1 byte leb128 (worst case)
// - 7-bit cksum_type => 1 byte leb128 (worst case)
// - 7-bit flags => 1 byte leb128 (worst case)
// - 32-bit block_size => 5 byte leb128 (worst case)
// - 32-bit block_count => 5 byte leb128 (worst case)
// - 7-bit utag_limit => 1 byte leb128 (worst case)
// - 32-bit mtree_limit => 5 byte leb128 (worst case)
// - 32-bit attr_limit => 5 byte leb128 (worst case)
// - 32-bit name_limit => 5 byte leb128 (worst case)
// - 32-bit file_limit => 5 byte leb128 (worst case)
// => 33 bytes total
//
#define LFSR_SUPERCONFIG_DSIZE (1+1+1+1+5+5+1+5+5+5+5)
#define LFSR_DATA_FROMSUPERCONFIG(_lfs, _buffer) \
lfsr_data_fromsuperconfig(_lfs, _buffer)
static lfsr_data_t lfsr_data_fromsuperconfig(lfs_t *lfs,
uint8_t buffer[static LFSR_SUPERCONFIG_DSIZE]) {
// TODO most of these should also be in the lfs_config/lfs_t structs
// note we take a shortcut for for single-byte leb128s, but these
// are still leb128s! the top bit must be zero!
// on-disk major version
buffer[0] = LFS_DISK_VERSION_MAJOR;
// on-disk minor version
buffer[1] = LFS_DISK_VERSION_MINOR;
// on-disk cksum type
buffer[2] = 2;
// on-disk flags
buffer[3] = 0;
// on-disk block size
lfs_ssize_t d = 4;
lfs_ssize_t d_ = lfs_toleb128(lfs->cfg->block_size, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
// on-disk block count
d_ = lfs_toleb128(lfs->cfg->block_count, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
// on-disk mleaf limit
d_ = lfs_toleb128(lfsr_mleafweight(lfs)-1, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
// on-disk utag limit
buffer[d] = 0x7f;
d += 1;
// on-disk attr limit
d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
// on-disk name limit
d_ = lfs_toleb128(0xff, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
// on-disk file limit
d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
LFS_ASSERT(d_ >= 0);
d += d_;
return LFSR_DATA_BUF(buffer, d);
}
//#define LFSR_DATA_FROMSUPERCONFIG(_lfs, _buffer)
// lfsr_data_fromsuperconfig(_lfs, _buffer)
//
//static lfsr_data_t lfsr_data_fromsuperconfig(lfs_t *lfs,
// uint8_t buffer[static LFSR_SUPERCONFIG_DSIZE]) {
// // TODO most of these should also be in the lfs_config/lfs_t structs
//
// // note we take a shortcut for for single-byte leb128s, but these
// // are still leb128s! the top bit must be zero!
//
// // on-disk major version
// buffer[0] = LFS_DISK_VERSION_MAJOR;
// // on-disk minor version
// buffer[1] = LFS_DISK_VERSION_MINOR;
// // on-disk cksum type
// buffer[2] = 2;
// // on-disk flags
// buffer[3] = 0;
//
// // on-disk block size
// lfs_ssize_t d = 4;
// lfs_ssize_t d_ = lfs_toleb128(lfs->cfg->block_size, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// // on-disk block count
// d_ = lfs_toleb128(lfs->cfg->block_count, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// // on-disk mleaf limit
// d_ = lfs_toleb128(lfsr_mleafweight(lfs)-1, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// // on-disk utag limit
// buffer[d] = 0x7f;
// d += 1;
//
// // on-disk attr limit
// d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// // on-disk name limit
// d_ = lfs_toleb128(0xff, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// // on-disk file limit
// d_ = lfs_toleb128(0x7fffffff, &buffer[d], 5);
// LFS_ASSERT(d_ >= 0);
// d += d_;
//
// return LFSR_DATA_BUF(buffer, d);
//}
/// Filesystem init functions ///
@@ -6304,215 +6316,325 @@ static int lfsr_mountinited(lfs_t *lfs) {
if (mdir->mid == -1) {
// has magic string?
lfsr_data_t data;
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERMAGIC,
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_MAGIC,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
if (err) {
if (err == LFS_ERR_NOENT) {
LFS_ERROR("No littlefs magic found");
return LFS_ERR_INVAL;
}
return err;
}
if (err != LFS_ERR_NOENT) {
lfs_scmp_t cmp = lfsr_data_cmp(lfs, &data, "littlefs", 8);
if (cmp < 0) {
return cmp;
}
// treat corrupted magic as no magic
if (lfs_cmp(cmp) != 0) {
err = LFS_ERR_NOENT;
}
lfs_scmp_t cmp = lfsr_data_cmp(lfs, &data, "littlefs", 8);
if (cmp < 0) {
return cmp;
}
if (err == LFS_ERR_NOENT) {
// treat corrupted magic as no magic
if (lfs_cmp(cmp) != 0) {
LFS_ERROR("No littlefs magic found");
return LFS_ERR_INVAL;
}
// lookup the superconfig
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERCONFIG,
// check the disk version
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_VERSION,
NULL, &data);
if (err) {
if (err == LFS_ERR_NOENT) {
LFS_ERROR("No littlefs version found");
return LFS_ERR_INVAL;
}
return err;
}
uint32_t major_version;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&major_version);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
major_version = -1;
}
uint32_t minor_version;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&minor_version);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
minor_version = -1;
}
if (major_version != LFS_DISK_VERSION_MAJOR
|| minor_version > LFS_DISK_VERSION_MINOR) {
LFS_ERROR("Incompatible version v%"PRId32".%"PRId32
" (!= v%"PRId32".%"PRId32")",
major_version,
minor_version,
LFS_DISK_VERSION_MAJOR,
LFS_DISK_VERSION_MINOR);
return LFS_ERR_INVAL;
}
// check for any flags
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_FLAGS,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
uint32_t flags = 0;
if (err != LFS_ERR_NOENT) {
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&flags);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
flags = -1;
}
}
if (flags != 0) {
LFS_ERROR("Incompatible flags 0x%"PRIx32, flags);
return LFS_ERR_INVAL;
}
// check checksum type
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_CKSUMTYPE,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
uint32_t cksum_type = 0;
if (err != LFS_ERR_NOENT) {
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&cksum_type);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
cksum_type = -1;
}
}
if (cksum_type != 0) {
LFS_ERROR("Incompatible cksum type 0x%"PRId32, cksum_type);
return LFS_ERR_INVAL;
}
// check redundancy type
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_REDUNDTYPE,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
uint32_t redund_type = 0;
if (err != LFS_ERR_NOENT) {
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&redund_type);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
redund_type = -1;
}
}
if (redund_type != 0) {
LFS_ERROR("Incompatible redund type 0x%"PRId32, redund_type);
return LFS_ERR_INVAL;
}
// check block limit / block size
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_BLOCKLIMIT,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
uint32_t block_limit = 0;
if (err != LFS_ERR_NOENT) {
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
block_limit = -1;
}
}
if (block_limit != lfs->cfg->block_size-1) {
LFS_ERROR("Incompatible block size %"PRId32" "
"(!= %"PRId32")",
block_limit+1,
lfs->cfg->block_size);
return LFS_ERR_INVAL;
}
// check disk limit / block count
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_DISKLIMIT,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
uint32_t disk_limit = 0;
if (err != LFS_ERR_NOENT) {
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&disk_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
disk_limit = -1;
}
}
if (disk_limit != lfs->cfg->block_count-1) {
LFS_ERROR("Incompatible block count %"PRId32" "
"(!= %"PRId32")",
disk_limit+1,
lfs->cfg->block_count);
return LFS_ERR_INVAL;
}
// read the mleaf limit
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_MLEAFLIMIT,
NULL, &data);
if (err) {
if (err == LFS_ERR_NOENT) {
LFS_ERROR("No mleaf limit found");
return LFS_ERR_INVAL;
}
return err;
}
uint32_t mleaf_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&mleaf_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
mleaf_limit = -1;
}
// we only support power-of-two mleaf weights, this unlikely to
// ever to change since mleaf weights are pretty arbitrary
if (lfs_popc(mleaf_limit+1) != 1) {
LFS_ERROR("Incompatible mleaf weight %"PRId32, mleaf_limit+1);
return LFS_ERR_INVAL;
}
lfs->mleaf_bits = lfs_nlog2(mleaf_limit);
// read the size limit
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SIZELIMIT,
NULL, &data);
if (err) {
if (err == LFS_ERR_NOENT) {
LFS_ERROR("No size limit found");
return LFS_ERR_INVAL;
}
return err;
}
uint32_t size_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&size_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
size_limit = -1;
}
if (size_limit > lfs->size_limit) {
LFS_ERROR("Incompatible size limit (%"PRId32" > %"PRId32")",
size_limit,
lfs->size_limit);
return LFS_ERR_INVAL;
}
lfs->size_limit = size_limit;
// read the name limit
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_NAMELIMIT,
NULL, &data);
if (err) {
if (err == LFS_ERR_NOENT) {
LFS_ERROR("No name limit found");
return LFS_ERR_INVAL;
}
return err;
}
uint32_t name_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&name_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT) {
name_limit = -1;
}
if (name_limit > lfs->name_limit) {
LFS_ERROR("Incompatible name limit (%"PRId32" > %"PRId32")",
name_limit,
lfs->name_limit);
return LFS_ERR_INVAL;
}
lfs->name_limit = name_limit;
// check the utag limit
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_UTAGLIMIT,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
if (err != LFS_ERR_NOENT) {
// check the major/minor version
int32_t major_version;
int32_t minor_version;
err = lfsr_data_readleb128(lfs, &data, &major_version);
// treat any leb128 overflows as out-of-range values
uint32_t utag_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&utag_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err != LFS_ERR_CORRUPT) {
err = lfsr_data_readleb128(lfs, &data, &minor_version);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
}
if (err == LFS_ERR_CORRUPT
|| major_version != LFS_DISK_VERSION_MAJOR
|| minor_version > LFS_DISK_VERSION_MINOR) {
LFS_ERROR("Incompatible version v%"PRId32".%"PRId32
" (!= v%"PRId32".%"PRId32")",
(err ? -1 : major_version),
(err ? -1 : minor_version),
LFS_DISK_VERSION_MAJOR,
LFS_DISK_VERSION_MINOR);
return LFS_ERR_INVAL;
if (err == LFS_ERR_CORRUPT) {
utag_limit = -1;
}
// check the on-disk cksum type
int32_t cksum_type;
err = lfsr_data_readleb128(lfs, &data, &cksum_type);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || cksum_type != 2) {
LFS_ERROR("Incompatible cksum type 0x%"PRIx32
" (!= 0x%"PRIx32")",
(err ? -1 : cksum_type),
2);
return LFS_ERR_INVAL;
}
// check for any on-disk flags
int32_t flags;
err = lfsr_data_readleb128(lfs, &data, &flags);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || flags != 0) {
LFS_ERROR("Incompatible flags 0x%"PRIx32
" (!= 0x%"PRIx32")",
(err ? -1 : flags),
0);
return LFS_ERR_INVAL;
}
// check the on-disk block size
// TODO actually use this
lfs_size_t block_size;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_size);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT
|| block_size != lfs->cfg->block_size) {
LFS_ERROR("Incompatible block size 0x%"PRIx32
" (!= 0x%"PRIx32")",
(err ? (lfs_size_t)-1 : block_size),
lfs->cfg->block_size);
return LFS_ERR_INVAL;
}
// check the on-disk block count
// TODO actually use this
lfs_block_t block_count;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&block_count);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT
|| block_count != lfs->cfg->block_count) {
LFS_ERROR("Incompatible block count 0x%"PRIx32
" (!= 0x%"PRIx32")",
(err ? (lfs_block_t)-1 : block_count),
lfs->cfg->block_count);
return LFS_ERR_INVAL;
}
// check the on-disk mtree limit
// TODO actually use this
lfsr_mid_t mleaf_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&mleaf_limit);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT
|| mleaf_limit != lfsr_mleafweight(lfs)-1) {
LFS_ERROR("Incompatible mleaf limit 0x%"PRIx32,
(err ? (lfsr_mid_t)-1 : mleaf_limit));
return LFS_ERR_INVAL;
}
// check the on-disk utag limit
// TODO actually use this
int32_t utag_limit;
err = lfsr_data_readleb128(lfs, &data, &utag_limit);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || utag_limit != 0x7f) {
LFS_ERROR("Incompatible utag limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : utag_limit),
// only 7-bit utags are supported
if (utag_limit != 0x7f) {
LFS_ERROR("Incompatible utag limit "
"(%"PRId32" != %"PRId32")",
utag_limit,
0x7f);
return LFS_ERR_INVAL;
}
}
// check the on-disk attr limit
// TODO actually use this
lfs_ssize_t attr_limit;
err = lfsr_data_readleb128(lfs, &data, &attr_limit);
// treat any leb128 overflows as out-of-range values
// check the uattr limit
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_UATTRLIMIT,
NULL, &data);
if (err && err != LFS_ERR_NOENT) {
return err;
}
if (err != LFS_ERR_NOENT) {
uint32_t uattr_limit;
err = lfsr_data_readleb128(lfs, &data, (int32_t*)&uattr_limit);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || attr_limit != 0x7fffffff) {
LFS_ERROR("Incompatible attr limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : attr_limit),
0x7fffffff);
return LFS_ERR_INVAL;
if (err == LFS_ERR_CORRUPT) {
uattr_limit = -1;
}
// check the on-disk name limit
// TODO actually use this
lfs_ssize_t name_limit;
err = lfsr_data_readleb128(lfs, &data, &name_limit);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || name_limit != 0xff) {
LFS_ERROR("Incompatible name limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : name_limit),
0xff);
return LFS_ERR_INVAL;
}
// check the on-disk file limit
// TODO actually use this
lfs_soff_t file_limit;
err = lfsr_data_readleb128(lfs, &data, &file_limit);
// treat any leb128 overflows as out-of-range values
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
if (err == LFS_ERR_CORRUPT || file_limit != 0x7fffffff) {
LFS_ERROR("Incompatible file limit 0x%"PRIx32
" (> 0x%"PRIx32")",
(err ? -1 : file_limit),
0x7fffffff);
// only >=block_size uattrs are (implicitly) supported
if (uattr_limit < lfs->cfg->block_size-1) {
LFS_ERROR("Incompatible uattr limit "
"(%"PRId32" < %"PRId32")",
uattr_limit,
lfs->cfg->block_size-1);
return LFS_ERR_INVAL;
}
}
@@ -6563,11 +6685,6 @@ static int lfsr_mountinited(lfs_t *lfs) {
}
static int lfsr_formatinited(lfs_t *lfs) {
// create superconfig
uint8_t superconfig_buf[LFSR_SUPERCONFIG_DSIZE];
lfsr_data_t superconfig_data = lfsr_data_fromsuperconfig(lfs,
superconfig_buf);
for (int i = 0; i < 2; i++) {
// write superblock to both rbyds in the root mroot to hopefully
// avoid mounting an older filesystem on disk
@@ -6588,11 +6705,18 @@ static int lfsr_formatinited(lfs_t *lfs) {
// our initial superblock contains a couple things:
// - our magic string, "littlefs"
// - the superconfig, format-time configuration
// - any format-time configuration
// - the root's bookmark tag, which reserves did = 0 for the root
err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
LFSR_ATTR(-1, SUPERMAGIC, 0, BUF("littlefs", 8)),
LFSR_ATTR(-1, SUPERCONFIG, 0, DATA(superconfig_data)),
LFSR_ATTR(-1, MAGIC, 0, BUF("littlefs", 8)),
LFSR_ATTR(-1, VERSION, 0, BUF(((const uint8_t[2]){
LFS_DISK_VERSION_MAJOR,
LFS_DISK_VERSION_MINOR}), 2)),
LFSR_ATTR(-1, BLOCKLIMIT, 0, LEB128(lfs->cfg->block_size-1)),
LFSR_ATTR(-1, DISKLIMIT, 0, LEB128(lfs->cfg->block_count-1)),
LFSR_ATTR(-1, MLEAFLIMIT, 0, LEB128(lfsr_mleafweight(lfs)-1)),
LFSR_ATTR(-1, SIZELIMIT, 0, LEB128(0x7fffffff)),
LFSR_ATTR(-1, NAMELIMIT, 0, LEB128(0xff)),
LFSR_ATTR(0, BOOKMARK, +1, NAME(0, NULL, 0))));
if (err) {
return err;
@@ -6794,7 +6918,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
}
// check that name fits
if (name_size > lfs->name_max) {
if (name_size > lfs->name_limit) {
return LFS_ERR_NAMETOOLONG;
}
@@ -7019,7 +7143,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
// there are a few cases we need to watch out for
if (!exists) {
// check that name fits
if (new_name_size > lfs->name_max) {
if (new_name_size > lfs->name_limit) {
return LFS_ERR_NAMETOOLONG;
}
@@ -10848,26 +10972,18 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->lookahead.acked = 0;
// check that the size limits are sane
LFS_ASSERT(lfs->cfg->name_max <= LFS_NAME_MAX);
lfs->name_max = lfs->cfg->name_max;
if (!lfs->name_max) {
lfs->name_max = LFS_NAME_MAX;
LFS_ASSERT(lfs->cfg->name_limit <= LFS_NAME_MAX);
lfs->name_limit = lfs->cfg->name_limit;
if (!lfs->name_limit) {
lfs->name_limit = LFS_NAME_MAX;
}
LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX);
lfs->file_max = lfs->cfg->file_max;
if (!lfs->file_max) {
lfs->file_max = LFS_FILE_MAX;
LFS_ASSERT(lfs->cfg->size_limit <= LFS_FILE_MAX);
lfs->size_limit = lfs->cfg->size_limit;
if (!lfs->size_limit) {
lfs->size_limit = LFS_FILE_MAX;
}
LFS_ASSERT(lfs->cfg->attr_max <= LFS_ATTR_MAX);
lfs->attr_max = lfs->cfg->attr_max;
if (!lfs->attr_max) {
lfs->attr_max = LFS_ATTR_MAX;
}
LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
// setup default state
lfs->root[0] = LFS_BLOCK_NULL;
lfs->root[1] = LFS_BLOCK_NULL;