Skip to content

Commit 620bf58

Browse files
57300cfriedt
authored andcommitted
zms: Initial support for 64 bit IDs
Allow the ZMS API to optionally accept 64 bit IDs. A typedef `zms_id_t` is added, so that the maximum ID width can be controlled using Kconfig. The current ATE structure is already large enough that it is possible to reserve 64 bits for IDs without increasing its total size (128 bits). This makes the feature a natural, low footprint alternative to Settings, for cases where the supported key namespace must be larger than 32 bit but not arbitrarily large. The ATE format does have to be altered to accommodate larger IDs, but the default "32 bit" format is left as is. Now, the `struct zms_ate` describes one of two supported formats, selected by an `#if` condition. In the future, it may be possible to support multiple ATE formats at runtime, in which case the structure can be turned into a union. In the new, "64 bit" ATEs, the `offset` and `metadata` fields are moved into a union, because they are found to be mutually exclusive. With the old format, the same fields are in different locations, but one of them always gets filled with a dummy value, depending on the given ATE type. To cover both cases, a `memset` is used, which should be optimized away by the compiler when appropriate. The only limitation is that the new ATE format has no room for data CRC, but an alternative integrity check can be implemented by the caller. Signed-off-by: Grzegorz Swiderski <[email protected]>
1 parent cfbe649 commit 620bf58

File tree

4 files changed

+135
-40
lines changed

4 files changed

+135
-40
lines changed

include/zephyr/fs/zms.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ struct zms_fs {
7777
* @{
7878
*/
7979

80+
/**
81+
* @brief ID type used in the ZMS API.
82+
*
83+
* @note The width of this type depends on @kconfig{CONFIG_ZMS_ID_64BIT}.
84+
*/
85+
#if CONFIG_ZMS_ID_64BIT
86+
typedef uint64_t zms_id_t;
87+
#else
88+
typedef uint32_t zms_id_t;
89+
#endif
90+
8091
/**
8192
* @brief Mount a ZMS file system onto the device specified in `fs`.
8293
*
@@ -128,7 +139,7 @@ int zms_clear(struct zms_fs *fs);
128139
* @retval -EINVAL if `fs` is NULL or `len` is invalid.
129140
* @retval -ENOSPC if no space is left on the device.
130141
*/
131-
ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len);
142+
ssize_t zms_write(struct zms_fs *fs, zms_id_t id, const void *data, size_t len);
132143

133144
/**
134145
* @brief Delete an entry from the file system
@@ -142,7 +153,7 @@ ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len);
142153
* @retval -EIO if there is a memory read/write error.
143154
* @retval -EINVAL if `fs` is NULL.
144155
*/
145-
int zms_delete(struct zms_fs *fs, uint32_t id);
156+
int zms_delete(struct zms_fs *fs, zms_id_t id);
146157

147158
/**
148159
* @brief Read an entry from the file system.
@@ -161,7 +172,7 @@ int zms_delete(struct zms_fs *fs, uint32_t id);
161172
* @retval -ENOENT if there is no entry with the given `id`.
162173
* @retval -EINVAL if `fs` is NULL.
163174
*/
164-
ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len);
175+
ssize_t zms_read(struct zms_fs *fs, zms_id_t id, void *data, size_t len);
165176

166177
/**
167178
* @brief Read a history entry from the file system.
@@ -182,7 +193,7 @@ ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len);
182193
* @retval -ENOENT if there is no entry with the given `id` and history counter.
183194
* @retval -EINVAL if `fs` is NULL.
184195
*/
185-
ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt);
196+
ssize_t zms_read_hist(struct zms_fs *fs, zms_id_t id, void *data, size_t len, uint32_t cnt);
186197

187198
/**
188199
* @brief Gets the length of the data that is stored in an entry with a given `id`
@@ -198,7 +209,7 @@ ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, ui
198209
* @retval -ENOENT if there is no entry with the given id.
199210
* @retval -EINVAL if `fs` is NULL.
200211
*/
201-
ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id);
212+
ssize_t zms_get_data_length(struct zms_fs *fs, zms_id_t id);
202213

203214
/**
204215
* @brief Calculate the available free space in the file system.

subsys/fs/zms/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ config ZMS
1616

1717
if ZMS
1818

19+
config ZMS_ID_64BIT
20+
bool "64 bit ZMS IDs"
21+
help
22+
When this option is true, the `zms_id_t` values passed to ZMS APIs will be 64 bit,
23+
as opposed to the default 32 bit.
24+
This option will also change the format of allocation table entries (ATEs) in memory
25+
to accommodate larger IDs. Currently, this will make ZMS unable to mount an existing
26+
file system if it has been initialized with a different ATE format.
27+
1928
config ZMS_LOOKUP_CACHE
2029
bool "ZMS lookup cache"
2130
help
@@ -34,6 +43,7 @@ config ZMS_LOOKUP_CACHE_SIZE
3443

3544
config ZMS_DATA_CRC
3645
bool "ZMS data CRC"
46+
depends on !ZMS_ID_64BIT
3747

3848
config ZMS_CUSTOMIZE_BLOCK_SIZE
3949
bool "Customize the size of the buffer used internally for reads and writes"
@@ -54,6 +64,7 @@ config ZMS_CUSTOM_BLOCK_SIZE
5464
config ZMS_LOOKUP_CACHE_FOR_SETTINGS
5565
bool "ZMS Storage lookup cache optimized for settings"
5666
depends on ZMS_LOOKUP_CACHE && SETTINGS_ZMS
67+
depends on !ZMS_ID_64BIT
5768
help
5869
Enable usage of lookup cache based on hashes to get, the best ZMS performance,
5970
provided that the ZMS is used only for the purpose of providing the settings

subsys/fs/zms/zms.c

Lines changed: 75 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@ static int zms_ate_valid_different_sector(struct zms_fs *fs, const struct zms_at
2929

3030
#ifdef CONFIG_ZMS_LOOKUP_CACHE
3131

32-
static inline size_t zms_lookup_cache_pos(uint32_t id)
32+
static inline size_t zms_lookup_cache_pos(zms_id_t id)
3333
{
34-
uint32_t hash = id;
35-
3634
#ifdef CONFIG_ZMS_LOOKUP_CACHE_FOR_SETTINGS
3735
/*
3836
* 1. Settings subsystem is storing the name ID and the linked list node ID
@@ -52,14 +50,27 @@ static inline size_t zms_lookup_cache_pos(uint32_t id)
5250
uint32_t key_value_bit;
5351
uint32_t key_value_hash;
5452
uint32_t key_value_ll;
53+
uint32_t hash;
5554

5655
key_value_bit = (id >> LOG2(ZMS_DATA_ID_OFFSET)) & 1;
5756
key_value_hash = (id & ZMS_HASH_MASK) >> (CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1);
5857
key_value_ll = id & BIT(0);
5958

6059
hash = (key_value_hash << 2) | (key_value_bit << 1) | key_value_ll;
60+
61+
#elif defined(CONFIG_ZMS_ID_64BIT)
62+
/* 64-bit integer hash function found by https://github.com/skeeto/hash-prospector. */
63+
uint64_t hash = id;
64+
65+
hash ^= hash >> 32;
66+
hash *= 0x42ab4abe4c475039ULL;
67+
hash ^= hash >> 31;
68+
hash *= 0xfa90c4424c537791ULL;
69+
hash ^= hash >> 32;
6170
#else
6271
/* 32-bit integer hash function found by https://github.com/skeeto/hash-prospector. */
72+
uint32_t hash = id;
73+
6374
hash ^= hash >> 16;
6475
hash *= 0x7feb352dU;
6576
hash ^= hash >> 15;
@@ -239,7 +250,7 @@ static int zms_flash_ate_wrt(struct zms_fs *fs, const struct zms_ate *entry)
239250
goto end;
240251
}
241252
#ifdef CONFIG_ZMS_LOOKUP_CACHE
242-
/* 0xFFFFFFFF is a special-purpose identifier. Exclude it from the cache */
253+
/* ZMS_HEAD_ID is a special-purpose identifier. Exclude it from the cache */
243254
if (entry->id != ZMS_HEAD_ID) {
244255
fs->lookup_cache[zms_lookup_cache_pos(entry->id)] = fs->ate_wra;
245256
}
@@ -487,7 +498,7 @@ static bool zms_close_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
487498
/* zms_empty_ate_valid validates an sector empty ate.
488499
* A valid sector empty ate should be:
489500
* - a valid ate
490-
* - with len = 0xffff and id = 0xffffffff
501+
* - with len = 0xffff and id = ZMS_HEAD_ID
491502
* return true if valid, false otherwise
492503
*/
493504
static bool zms_empty_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
@@ -500,7 +511,7 @@ static bool zms_empty_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
500511
* Valid gc_done_ate:
501512
* - valid ate
502513
* - len = 0
503-
* - id = 0xffffffff
514+
* - id = ZMS_HEAD_ID
504515
* return true if valid, false otherwise
505516
*/
506517
static bool zms_gc_done_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
@@ -509,6 +520,18 @@ static bool zms_gc_done_ate_valid(struct zms_fs *fs, const struct zms_ate *entry
509520
(entry->id == ZMS_HEAD_ID));
510521
}
511522

523+
/* zms_sector_closed checks whether the current sector is closed, which would imply
524+
* that the empty ATE and close ATE are both valid and have matching cycle counters
525+
*
526+
* return true if closed, false otherwise
527+
*/
528+
static bool zms_sector_closed(struct zms_fs *fs, struct zms_ate *empty_ate,
529+
struct zms_ate *close_ate)
530+
{
531+
return (zms_empty_ate_valid(fs, empty_ate) && zms_close_ate_valid(fs, close_ate) &&
532+
(empty_ate->cycle_cnt == close_ate->cycle_cnt));
533+
}
534+
512535
/* Read empty and close ATE of the sector where belongs address "addr" and
513536
* validates that the sector is closed.
514537
* retval: 0 if sector is not close
@@ -526,8 +549,7 @@ static int zms_validate_closed_sector(struct zms_fs *fs, uint64_t addr, struct z
526549
return rc;
527550
}
528551

529-
if (zms_empty_ate_valid(fs, empty_ate) && zms_close_ate_valid(fs, close_ate) &&
530-
(empty_ate->cycle_cnt == close_ate->cycle_cnt)) {
552+
if (zms_sector_closed(fs, empty_ate, close_ate)) {
531553
/* Closed sector validated */
532554
return 1;
533555
}
@@ -536,7 +558,7 @@ static int zms_validate_closed_sector(struct zms_fs *fs, uint64_t addr, struct z
536558
}
537559

538560
/* store an entry in flash */
539-
static int zms_flash_write_entry(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
561+
static int zms_flash_write_entry(struct zms_fs *fs, zms_id_t id, const void *data, size_t len)
540562
{
541563
int rc;
542564
struct zms_ate entry;
@@ -549,13 +571,13 @@ static int zms_flash_write_entry(struct zms_fs *fs, uint32_t id, const void *dat
549571
entry.cycle_cnt = fs->sector_cycle;
550572

551573
if (len > ZMS_DATA_IN_ATE_SIZE) {
552-
/* only compute CRC if len is greater than 8 bytes */
553-
if (IS_ENABLED(CONFIG_ZMS_DATA_CRC)) {
554-
entry.data_crc = crc32_ieee(data, len);
555-
}
574+
#ifdef CONFIG_ZMS_DATA_CRC
575+
/* only compute CRC if data is to be stored outside of entry */
576+
entry.data_crc = crc32_ieee(data, len);
577+
#endif
556578
entry.offset = (uint32_t)SECTOR_OFFSET(fs->data_wra);
557579
} else if ((len > 0) && (len <= ZMS_DATA_IN_ATE_SIZE)) {
558-
/* Copy data into entry for small data ( < 8B) */
580+
/* Copy data into entry for small data (at most ZMS_DATA_IN_ATE_SIZE bytes) */
559581
memcpy(&entry.data, data, len);
560582
}
561583

@@ -688,10 +710,12 @@ static int zms_sector_close(struct zms_fs *fs)
688710
struct zms_ate close_ate;
689711
struct zms_ate garbage_ate;
690712

713+
/* Initialize all members to 0xff */
714+
memset(&close_ate, 0xff, sizeof(struct zms_ate));
715+
691716
close_ate.id = ZMS_HEAD_ID;
692717
close_ate.len = 0U;
693718
close_ate.offset = (uint32_t)SECTOR_OFFSET(fs->ate_wra + fs->ate_size);
694-
close_ate.metadata = 0xffffffff;
695719
close_ate.cycle_cnt = fs->sector_cycle;
696720

697721
/* When we close the sector, we must write all non used ATE with
@@ -740,11 +764,13 @@ static int zms_add_gc_done_ate(struct zms_fs *fs)
740764
{
741765
struct zms_ate gc_done_ate;
742766

767+
/* Initialize all members to 0xff */
768+
memset(&gc_done_ate, 0xff, sizeof(struct zms_ate));
769+
743770
LOG_DBG("Adding gc done ate at %llx", fs->ate_wra);
744771
gc_done_ate.id = ZMS_HEAD_ID;
745772
gc_done_ate.len = 0U;
746773
gc_done_ate.offset = (uint32_t)SECTOR_OFFSET(fs->data_wra);
747-
gc_done_ate.metadata = 0xffffffff;
748774
gc_done_ate.cycle_cnt = fs->sector_cycle;
749775

750776
zms_ate_crc8_update(&gc_done_ate);
@@ -793,14 +819,17 @@ static int zms_add_empty_ate(struct zms_fs *fs, uint64_t addr)
793819
int rc = 0;
794820
uint64_t previous_ate_wra;
795821

822+
/* Initialize all members to 0 */
823+
memset(&empty_ate, 0, sizeof(struct zms_ate));
824+
796825
addr &= ADDR_SECT_MASK;
797826

798827
LOG_DBG("Adding empty ate at %llx", (uint64_t)(addr + fs->sector_size - fs->ate_size));
799828
empty_ate.id = ZMS_HEAD_ID;
800829
empty_ate.len = 0xffff;
801-
empty_ate.offset = 0U;
802-
empty_ate.metadata =
803-
FIELD_PREP(ZMS_MAGIC_NUMBER_MASK, ZMS_MAGIC_NUMBER) | ZMS_DEFAULT_VERSION;
830+
empty_ate.metadata = FIELD_PREP(ZMS_VERSION_MASK, ZMS_DEFAULT_VERSION) |
831+
FIELD_PREP(ZMS_MAGIC_NUMBER_MASK, ZMS_MAGIC_NUMBER) |
832+
FIELD_PREP(ZMS_ATE_FORMAT_MASK, ZMS_DEFAULT_ATE_FORMAT);
804833

805834
rc = zms_get_sector_cycle(fs, addr, &cycle_cnt);
806835
if (rc == -ENOENT) {
@@ -893,7 +922,7 @@ static int zms_get_sector_header(struct zms_fs *fs, uint64_t addr, struct zms_at
893922
* @retval 1 valid ATE with same ID found
894923
* @retval < 0 An error happened
895924
*/
896-
static int zms_find_ate_with_id(struct zms_fs *fs, uint32_t id, uint64_t start_addr,
925+
static int zms_find_ate_with_id(struct zms_fs *fs, zms_id_t id, uint64_t start_addr,
897926
uint64_t end_addr, struct zms_ate *ate, uint64_t *ate_addr)
898927
{
899928
int rc;
@@ -1044,10 +1073,10 @@ static int zms_gc(struct zms_fs *fs)
10441073
*/
10451074
if (wlk_prev_addr == gc_prev_addr) {
10461075
/* copy needed */
1047-
LOG_DBG("Moving %d, len %d", gc_ate.id, gc_ate.len);
1076+
LOG_DBG("Moving %lld, len %d", (long long)gc_ate.id, gc_ate.len);
10481077

10491078
if (gc_ate.len > ZMS_DATA_IN_ATE_SIZE) {
1050-
/* Copy Data only when len > 8
1079+
/* Copy Data only when len > ZMS_DATA_IN_ATE_SIZE
10511080
* Otherwise, Data is already inside ATE
10521081
*/
10531082
data_addr = (gc_prev_addr & ADDR_SECT_MASK);
@@ -1156,16 +1185,28 @@ static int zms_init(struct zms_fs *fs)
11561185
for (i = 0; i < fs->sector_count; i++) {
11571186
addr = zms_close_ate_addr(fs, ((uint64_t)i << ADDR_SECT_SHIFT));
11581187

1159-
/* verify if the sector is closed */
1160-
sec_closed = zms_validate_closed_sector(fs, addr, &empty_ate, &close_ate);
1161-
if (sec_closed < 0) {
1162-
rc = sec_closed;
1188+
/* read the header ATEs */
1189+
rc = zms_get_sector_header(fs, addr, &empty_ate, &close_ate);
1190+
if (rc) {
11631191
goto end;
11641192
}
11651193
/* update cycle count */
11661194
fs->sector_cycle = empty_ate.cycle_cnt;
11671195

1168-
if (sec_closed == 1) {
1196+
/* Check the ATE format indicator so that we know how to validate ATEs.
1197+
* The metadata field has the same offset and size in all ATE formats
1198+
* (the same is guaranteed for crc8 and cycle_cnt).
1199+
* Currently, ZMS can only recognize one of its supported ATE formats
1200+
* (the one chosen at build time), so their indicators are defined for
1201+
* the possibility of a future extension.
1202+
* If this indicator is unknown, then consider the header ATEs invalid,
1203+
* because we might not be dealing with ZMS contents at all.
1204+
*/
1205+
if (ZMS_GET_ATE_FORMAT(empty_ate.metadata) != ZMS_DEFAULT_ATE_FORMAT) {
1206+
continue;
1207+
}
1208+
1209+
if (zms_sector_closed(fs, &empty_ate, &close_ate)) {
11691210
/* closed sector */
11701211
closed_sectors++;
11711212
/* Let's verify that this is a ZMS storage system */
@@ -1223,7 +1264,8 @@ static int zms_init(struct zms_fs *fs)
12231264
goto end;
12241265
}
12251266

1226-
if (zms_empty_ate_valid(fs, &empty_ate)) {
1267+
if ((ZMS_GET_ATE_FORMAT(empty_ate.metadata) == ZMS_DEFAULT_ATE_FORMAT) &&
1268+
zms_empty_ate_valid(fs, &empty_ate)) {
12271269
/* Empty ATE is valid, let's verify that this is a ZMS storage system */
12281270
if (ZMS_GET_MAGIC_NUMBER(empty_ate.metadata) == ZMS_MAGIC_NUMBER) {
12291271
zms_magic_exist = true;
@@ -1468,7 +1510,7 @@ int zms_mount(struct zms_fs *fs)
14681510
return 0;
14691511
}
14701512

1471-
ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
1513+
ssize_t zms_write(struct zms_fs *fs, zms_id_t id, const void *data, size_t len)
14721514
{
14731515
int rc;
14741516
size_t data_size;
@@ -1620,12 +1662,12 @@ ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
16201662
return rc;
16211663
}
16221664

1623-
int zms_delete(struct zms_fs *fs, uint32_t id)
1665+
int zms_delete(struct zms_fs *fs, zms_id_t id)
16241666
{
16251667
return zms_write(fs, id, NULL, 0);
16261668
}
16271669

1628-
ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt)
1670+
ssize_t zms_read_hist(struct zms_fs *fs, zms_id_t id, void *data, size_t len, uint32_t cnt)
16291671
{
16301672
int rc;
16311673
int prev_found = 0;
@@ -1726,7 +1768,7 @@ ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, ui
17261768
return rc;
17271769
}
17281770

1729-
ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
1771+
ssize_t zms_read(struct zms_fs *fs, zms_id_t id, void *data, size_t len)
17301772
{
17311773
int rc;
17321774

@@ -1739,7 +1781,7 @@ ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
17391781
return MIN(rc, len);
17401782
}
17411783

1742-
ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id)
1784+
ssize_t zms_get_data_length(struct zms_fs *fs, zms_id_t id)
17431785
{
17441786
int rc;
17451787

0 commit comments

Comments
 (0)