Skip to content

Commit 019a9eb

Browse files
57300anangl
authored andcommitted
[nrf fromlist] zms: Initial support for 64 bit IDs
Upstream PR #: 94330 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]> (cherry picked from commit ec7a4ad199b0a87e5d604cbea20c8e2f4f741303)
1 parent 5d39c92 commit 019a9eb

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
*
@@ -127,7 +138,7 @@ int zms_clear(struct zms_fs *fs);
127138
* @retval -EINVAL if `len` is invalid.
128139
* @retval -ENOSPC if no space is left on the device.
129140
*/
130-
ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len);
141+
ssize_t zms_write(struct zms_fs *fs, zms_id_t id, const void *data, size_t len);
131142

132143
/**
133144
* @brief Delete an entry from the file system
@@ -140,7 +151,7 @@ ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len);
140151
* @retval -ENXIO if there is a device error.
141152
* @retval -EIO if there is a memory read/write error.
142153
*/
143-
int zms_delete(struct zms_fs *fs, uint32_t id);
154+
int zms_delete(struct zms_fs *fs, zms_id_t id);
144155

145156
/**
146157
* @brief Read an entry from the file system.
@@ -158,7 +169,7 @@ int zms_delete(struct zms_fs *fs, uint32_t id);
158169
* @retval -EIO if there is a memory read/write error.
159170
* @retval -ENOENT if there is no entry with the given `id`.
160171
*/
161-
ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len);
172+
ssize_t zms_read(struct zms_fs *fs, zms_id_t id, void *data, size_t len);
162173

163174
/**
164175
* @brief Read a history entry from the file system.
@@ -178,7 +189,7 @@ ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len);
178189
* @retval -EIO if there is a memory read/write error.
179190
* @retval -ENOENT if there is no entry with the given `id` and history counter.
180191
*/
181-
ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt);
192+
ssize_t zms_read_hist(struct zms_fs *fs, zms_id_t id, void *data, size_t len, uint32_t cnt);
182193

183194
/**
184195
* @brief Gets the length of the data that is stored in an entry with a given `id`
@@ -193,7 +204,7 @@ ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, ui
193204
* @retval -EIO if there is a memory read/write error.
194205
* @retval -ENOENT if there is no entry with the given id and history counter.
195206
*/
196-
ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id);
207+
ssize_t zms_get_data_length(struct zms_fs *fs, zms_id_t id);
197208

198209
/**
199210
* @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
@@ -15,6 +15,15 @@ config ZMS
1515

1616
if ZMS
1717

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

3443
config ZMS_DATA_CRC
3544
bool "ZMS data CRC"
45+
depends on !ZMS_ID_64BIT
3646

3747
config ZMS_CUSTOMIZE_BLOCK_SIZE
3848
bool "Customize the size of the buffer used internally for reads and writes"
@@ -53,6 +63,7 @@ config ZMS_CUSTOM_BLOCK_SIZE
5363
config ZMS_LOOKUP_CACHE_FOR_SETTINGS
5464
bool "ZMS Storage lookup cache optimized for settings"
5565
depends on ZMS_LOOKUP_CACHE && SETTINGS_ZMS
66+
depends on !ZMS_ID_64BIT
5667
help
5768
Enable usage of lookup cache based on hashes to get, the best ZMS performance,
5869
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);
@@ -1151,16 +1180,28 @@ static int zms_init(struct zms_fs *fs)
11511180
for (i = 0; i < fs->sector_count; i++) {
11521181
addr = zms_close_ate_addr(fs, ((uint64_t)i << ADDR_SECT_SHIFT));
11531182

1154-
/* verify if the sector is closed */
1155-
sec_closed = zms_validate_closed_sector(fs, addr, &empty_ate, &close_ate);
1156-
if (sec_closed < 0) {
1157-
rc = sec_closed;
1183+
/* read the header ATEs */
1184+
rc = zms_get_sector_header(fs, addr, &empty_ate, &close_ate);
1185+
if (rc) {
11581186
goto end;
11591187
}
11601188
/* update cycle count */
11611189
fs->sector_cycle = empty_ate.cycle_cnt;
11621190

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

1221-
if (zms_empty_ate_valid(fs, &empty_ate)) {
1262+
if ((ZMS_GET_ATE_FORMAT(empty_ate.metadata) == ZMS_DEFAULT_ATE_FORMAT) &&
1263+
zms_empty_ate_valid(fs, &empty_ate)) {
12221264
/* Empty ATE is valid, let's verify that this is a ZMS storage system */
12231265
if (ZMS_GET_MAGIC_NUMBER(empty_ate.metadata) == ZMS_MAGIC_NUMBER) {
12241266
zms_magic_exist = true;
@@ -1458,7 +1500,7 @@ int zms_mount(struct zms_fs *fs)
14581500
return 0;
14591501
}
14601502

1461-
ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
1503+
ssize_t zms_write(struct zms_fs *fs, zms_id_t id, const void *data, size_t len)
14621504
{
14631505
int rc;
14641506
size_t data_size;
@@ -1598,12 +1640,12 @@ ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
15981640
return rc;
15991641
}
16001642

1601-
int zms_delete(struct zms_fs *fs, uint32_t id)
1643+
int zms_delete(struct zms_fs *fs, zms_id_t id)
16021644
{
16031645
return zms_write(fs, id, NULL, 0);
16041646
}
16051647

1606-
ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt)
1648+
ssize_t zms_read_hist(struct zms_fs *fs, zms_id_t id, void *data, size_t len, uint32_t cnt)
16071649
{
16081650
int rc;
16091651
int prev_found = 0;
@@ -1700,7 +1742,7 @@ ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, ui
17001742
return rc;
17011743
}
17021744

1703-
ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
1745+
ssize_t zms_read(struct zms_fs *fs, zms_id_t id, void *data, size_t len)
17041746
{
17051747
int rc;
17061748

@@ -1713,7 +1755,7 @@ ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
17131755
return MIN(rc, len);
17141756
}
17151757

1716-
ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id)
1758+
ssize_t zms_get_data_length(struct zms_fs *fs, zms_id_t id)
17171759
{
17181760
int rc;
17191761

0 commit comments

Comments
 (0)