Skip to content

Commit 49a2df0

Browse files
committed
[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 based on an `#ifdef`. 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, use a `memset` which the compiler can optimize away 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 11e2cd69f89595f6eaafc74a75a78121532b8885)
1 parent dacbe34 commit 49a2df0

File tree

4 files changed

+94
-31
lines changed

4 files changed

+94
-31
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: 10 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"

subsys/fs/zms/zms.c

Lines changed: 39 additions & 23 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,26 @@ 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+
#elif defined(CONFIG_ZMS_ID_64BIT)
61+
/* 64-bit integer hash function found by https://github.com/skeeto/hash-prospector. */
62+
uint64_t hash = id;
63+
64+
hash ^= hash >> 32;
65+
hash *= 0x42ab4abe4c475039ULL;
66+
hash ^= hash >> 31;
67+
hash *= 0xfa90c4424c537791ULL;
68+
hash ^= hash >> 32;
6169
#else
6270
/* 32-bit integer hash function found by https://github.com/skeeto/hash-prospector. */
71+
uint32_t hash = id;
72+
6373
hash ^= hash >> 16;
6474
hash *= 0x7feb352dU;
6575
hash ^= hash >> 15;
@@ -239,7 +249,7 @@ static int zms_flash_ate_wrt(struct zms_fs *fs, const struct zms_ate *entry)
239249
goto end;
240250
}
241251
#ifdef CONFIG_ZMS_LOOKUP_CACHE
242-
/* 0xFFFFFFFF is a special-purpose identifier. Exclude it from the cache */
252+
/* ZMS_HEAD_ID is a special-purpose identifier. Exclude it from the cache */
243253
if (entry->id != ZMS_HEAD_ID) {
244254
fs->lookup_cache[zms_lookup_cache_pos(entry->id)] = fs->ate_wra;
245255
}
@@ -487,7 +497,7 @@ static bool zms_close_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
487497
/* zms_empty_ate_valid validates an sector empty ate.
488498
* A valid sector empty ate should be:
489499
* - a valid ate
490-
* - with len = 0xffff and id = 0xffffffff
500+
* - with len = 0xffff and id = ZMS_HEAD_ID
491501
* return true if valid, false otherwise
492502
*/
493503
static bool zms_empty_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
@@ -500,7 +510,7 @@ static bool zms_empty_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
500510
* Valid gc_done_ate:
501511
* - valid ate
502512
* - len = 0
503-
* - id = 0xffffffff
513+
* - id = ZMS_HEAD_ID
504514
* return true if valid, false otherwise
505515
*/
506516
static bool zms_gc_done_ate_valid(struct zms_fs *fs, const struct zms_ate *entry)
@@ -536,7 +546,7 @@ static int zms_validate_closed_sector(struct zms_fs *fs, uint64_t addr, struct z
536546
}
537547

538548
/* 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)
549+
static int zms_flash_write_entry(struct zms_fs *fs, zms_id_t id, const void *data, size_t len)
540550
{
541551
int rc;
542552
struct zms_ate entry;
@@ -549,13 +559,13 @@ static int zms_flash_write_entry(struct zms_fs *fs, uint32_t id, const void *dat
549559
entry.cycle_cnt = fs->sector_cycle;
550560

551561
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-
}
562+
#ifdef CONFIG_ZMS_DATA_CRC
563+
/* only compute CRC if data is to be stored outside of entry */
564+
entry.data_crc = crc32_ieee(data, len);
565+
#endif
556566
entry.offset = (uint32_t)SECTOR_OFFSET(fs->data_wra);
557567
} else if ((len > 0) && (len <= ZMS_DATA_IN_ATE_SIZE)) {
558-
/* Copy data into entry for small data ( < 8B) */
568+
/* Copy data into entry if data is sufficiently small */
559569
memcpy(&entry.data, data, len);
560570
}
561571

@@ -688,10 +698,12 @@ static int zms_sector_close(struct zms_fs *fs)
688698
struct zms_ate close_ate;
689699
struct zms_ate garbage_ate;
690700

701+
/* Initialize all members to 0xff */
702+
memset(&close_ate, 0xff, sizeof(struct zms_ate));
703+
691704
close_ate.id = ZMS_HEAD_ID;
692705
close_ate.len = 0U;
693706
close_ate.offset = (uint32_t)SECTOR_OFFSET(fs->ate_wra + fs->ate_size);
694-
close_ate.metadata = 0xffffffff;
695707
close_ate.cycle_cnt = fs->sector_cycle;
696708

697709
/* When we close the sector, we must write all non used ATE with
@@ -740,11 +752,13 @@ static int zms_add_gc_done_ate(struct zms_fs *fs)
740752
{
741753
struct zms_ate gc_done_ate;
742754

755+
/* Initialize all members to 0xff */
756+
memset(&gc_done_ate, 0xff, sizeof(struct zms_ate));
757+
743758
LOG_DBG("Adding gc done ate at %llx", fs->ate_wra);
744759
gc_done_ate.id = ZMS_HEAD_ID;
745760
gc_done_ate.len = 0U;
746761
gc_done_ate.offset = (uint32_t)SECTOR_OFFSET(fs->data_wra);
747-
gc_done_ate.metadata = 0xffffffff;
748762
gc_done_ate.cycle_cnt = fs->sector_cycle;
749763

750764
zms_ate_crc8_update(&gc_done_ate);
@@ -793,12 +807,14 @@ static int zms_add_empty_ate(struct zms_fs *fs, uint64_t addr)
793807
int rc = 0;
794808
uint64_t previous_ate_wra;
795809

810+
/* Initialize all members to 0 */
811+
memset(&empty_ate, 0, sizeof(struct zms_ate));
812+
796813
addr &= ADDR_SECT_MASK;
797814

798815
LOG_DBG("Adding empty ate at %llx", (uint64_t)(addr + fs->sector_size - fs->ate_size));
799816
empty_ate.id = ZMS_HEAD_ID;
800817
empty_ate.len = 0xffff;
801-
empty_ate.offset = 0U;
802818
empty_ate.metadata =
803819
FIELD_PREP(ZMS_MAGIC_NUMBER_MASK, ZMS_MAGIC_NUMBER) | ZMS_DEFAULT_VERSION;
804820

@@ -893,7 +909,7 @@ static int zms_get_sector_header(struct zms_fs *fs, uint64_t addr, struct zms_at
893909
* @retval 1 valid ATE with same ID found
894910
* @retval < 0 An error happened
895911
*/
896-
static int zms_find_ate_with_id(struct zms_fs *fs, uint32_t id, uint64_t start_addr,
912+
static int zms_find_ate_with_id(struct zms_fs *fs, zms_id_t id, uint64_t start_addr,
897913
uint64_t end_addr, struct zms_ate *ate, uint64_t *ate_addr)
898914
{
899915
int rc;
@@ -1044,10 +1060,10 @@ static int zms_gc(struct zms_fs *fs)
10441060
*/
10451061
if (wlk_prev_addr == gc_prev_addr) {
10461062
/* copy needed */
1047-
LOG_DBG("Moving %d, len %d", gc_ate.id, gc_ate.len);
1063+
LOG_DBG("Moving %lld, len %d", (long long)gc_ate.id, gc_ate.len);
10481064

10491065
if (gc_ate.len > ZMS_DATA_IN_ATE_SIZE) {
1050-
/* Copy Data only when len > 8
1066+
/* Only copy Data with large enough len
10511067
* Otherwise, Data is already inside ATE
10521068
*/
10531069
data_addr = (gc_prev_addr & ADDR_SECT_MASK);
@@ -1458,7 +1474,7 @@ int zms_mount(struct zms_fs *fs)
14581474
return 0;
14591475
}
14601476

1461-
ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
1477+
ssize_t zms_write(struct zms_fs *fs, zms_id_t id, const void *data, size_t len)
14621478
{
14631479
int rc;
14641480
size_t data_size;
@@ -1598,12 +1614,12 @@ ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len)
15981614
return rc;
15991615
}
16001616

1601-
int zms_delete(struct zms_fs *fs, uint32_t id)
1617+
int zms_delete(struct zms_fs *fs, zms_id_t id)
16021618
{
16031619
return zms_write(fs, id, NULL, 0);
16041620
}
16051621

1606-
ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt)
1622+
ssize_t zms_read_hist(struct zms_fs *fs, zms_id_t id, void *data, size_t len, uint32_t cnt)
16071623
{
16081624
int rc;
16091625
int prev_found = 0;
@@ -1700,7 +1716,7 @@ ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, ui
17001716
return rc;
17011717
}
17021718

1703-
ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
1719+
ssize_t zms_read(struct zms_fs *fs, zms_id_t id, void *data, size_t len)
17041720
{
17051721
int rc;
17061722

@@ -1713,7 +1729,7 @@ ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len)
17131729
return MIN(rc, len);
17141730
}
17151731

1716-
ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id)
1732+
ssize_t zms_get_data_length(struct zms_fs *fs, zms_id_t id)
17171733
{
17181734
int rc;
17191735

subsys/fs/zms/zms_priv.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,21 @@
2828
#endif
2929

3030
#define ZMS_LOOKUP_CACHE_NO_ADDR GENMASK64(63, 0)
31-
#define ZMS_HEAD_ID GENMASK(31, 0)
3231

3332
#define ZMS_VERSION_MASK GENMASK(7, 0)
3433
#define ZMS_GET_VERSION(x) FIELD_GET(ZMS_VERSION_MASK, x)
3534
#define ZMS_DEFAULT_VERSION 1
36-
#define ZMS_MAGIC_NUMBER 0x42 /* murmur3a hash of "ZMS" (MSB) */
3735
#define ZMS_MAGIC_NUMBER_MASK GENMASK(15, 8)
3836
#define ZMS_GET_MAGIC_NUMBER(x) FIELD_GET(ZMS_MAGIC_NUMBER_MASK, x)
3937
#define ZMS_MIN_ATE_NUM 5
4038

4139
#define ZMS_INVALID_SECTOR_NUM -1
42-
#define ZMS_DATA_IN_ATE_SIZE 8
4340

4441
/**
4542
* @ingroup zms_data_structures
4643
* ZMS Allocation Table Entry (ATE) structure
44+
*
45+
* @note This structure depends on @kconfig{CONFIG_ZMS_ID_64BIT}.
4746
*/
4847
struct zms_ate {
4948
/** crc8 check of the entry */
@@ -52,6 +51,8 @@ struct zms_ate {
5251
uint8_t cycle_cnt;
5352
/** data len within sector */
5453
uint16_t len;
54+
55+
#if !defined(CONFIG_ZMS_ID_64BIT)
5556
/** data id */
5657
uint32_t id;
5758
union {
@@ -75,6 +76,31 @@ struct zms_ate {
7576
};
7677
};
7778
};
79+
#else
80+
/** data id */
81+
uint64_t id;
82+
union {
83+
/** data field used to store small sized data */
84+
uint8_t data[4];
85+
/** data offset within sector */
86+
uint32_t offset;
87+
/** Used to store metadata information such as storage version. */
88+
uint32_t metadata;
89+
};
90+
#endif /* CONFIG_ZMS_ID_64BIT */
91+
7892
} __packed;
7993

94+
#define ZMS_DATA_IN_ATE_SIZE SIZEOF_FIELD(struct zms_ate, data)
95+
96+
#if !defined(CONFIG_ZMS_ID_64BIT)
97+
#define ZMS_HEAD_ID GENMASK(31, 0)
98+
#define ZMS_MAGIC_NUMBER 0x42 /* murmur3a hash of "ZMS" (MSB) */
99+
100+
#else
101+
#define ZMS_HEAD_ID GENMASK64(63, 0)
102+
#define ZMS_MAGIC_NUMBER 0xb8 /* murmur3a hash of "ZMS64" (MSB) */
103+
104+
#endif /* CONFIG_ZMS_ID_64BIT */
105+
80106
#endif /* __ZMS_PRIV_H_ */

0 commit comments

Comments
 (0)