This is an automated email from the ASF dual-hosted git repository. jerzy pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit c63619e8750747d9a3f6c26319cdff6ffeca1ca6 Author: Jerzy Kasenberg <[email protected]> AuthorDate: Mon Aug 5 15:13:47 2024 +0200 fs/fcb: Add support for backward walk This extends fcb_entry structure with field that can change direction of the walk. fcb_getnext() function can now walk in backward direction. Signed-off-by: Jerzy Kasenberg <[email protected]> --- fs/fcb/include/fcb/fcb.h | 65 +++++++ fs/fcb/src/fcb.c | 3 + fs/fcb/src/fcb_append.c | 2 + fs/fcb/src/fcb_getnext.c | 480 ++++++++++++++++++++++++++++++++++++++++++----- fs/fcb/src/fcb_priv.h | 13 ++ fs/fcb/src/fcb_walk.c | 28 +++ fs/fcb/syscfg.yml | 28 +++ 7 files changed, 574 insertions(+), 45 deletions(-) diff --git a/fs/fcb/include/fcb/fcb.h b/fs/fcb/include/fcb/fcb.h index 4e43e7f0b..d382521fe 100644 --- a/fs/fcb/include/fcb/fcb.h +++ b/fs/fcb/include/fcb/fcb.h @@ -38,6 +38,17 @@ extern "C" { #define FCB_MAX_LEN (CHAR_MAX | CHAR_MAX << 7) /* Max length of element */ +struct fcb_entry_cache { + /* Sector number in FCB */ + uint16_t sector_ix; + /* Number of entries that cache can keep */ + uint16_t cache_size; + /* Number of entries in cache */ + uint16_t cache_count; + /* Cached data */ + uint16_t *cache_data; +}; + /** * Entry location is pointer to area (within fcb->f_sectors), and offset * within that area. @@ -47,6 +58,9 @@ struct fcb_entry { uint32_t fe_elem_off; /* start of entry */ uint32_t fe_data_off; /* start of data */ uint16_t fe_data_len; /* size of data area */ + uint16_t fe_elem_ix; /* Element index in current sector */ + struct fcb_entry_cache *fe_cache; + bool fe_step_back; /* walk backwards */ }; struct fcb { @@ -55,6 +69,8 @@ struct fcb { uint8_t f_version; /* Current version number of the data */ uint16_t f_sector_cnt; /* Number of elements in sector array */ uint16_t f_scratch_cnt; /* How many sectors should be kept empty */ + /** Number of element in active sector (f_active) */ + uint16_t f_active_sector_entry_count; struct flash_area *f_sectors; /* Array of sectors, must be contiguous */ /* Flash circular buffer internal state */ @@ -65,6 +81,41 @@ struct fcb { uint8_t f_align; /* writes to flash have to aligned to this */ }; +/** + * Init FCB cache that can be used for walking back optimization. + * + * Note: Cache can be used to speed up walk back functionality. + * Cache uses memory allocated by os_malloc/os_realloc and must + * be freed after use with fcb_cache_free(). + * + * To setup cache: + * struct fcb_entry_cache cache; + * struct fcb_entry loc = {}; + * + * loc.fe_cache = &cache; + * fcb_cache_init(fcb, &cache, 100); + * loc.fe_step_back = true; + * + * fcb_getnext(fcb, &loc); + * + * fcb_cache_free(fcb, cache); + * + * @param fcb - fcb to init cache for + * @param cache - cache to init + * @param initial_entry_count - initial number of entries in the cache + * @return 0 - on success + * SYS_ENOMEM - when cache memory can't be allocated. + */ +int fcb_cache_init(struct fcb *fcb, struct fcb_entry_cache *cache, int initial_entry_count); + +/** + * Free memory allocate by fcb cache. + * + * @param fcb - fcb associated with cache + * @param cache - cache to free + */ +void fcb_cache_free(struct fcb *fcb, struct fcb_entry_cache *cache); + /** * Error codes. */ @@ -102,6 +153,20 @@ typedef int (*fcb_walk_cb)(struct fcb_entry *loc, void *arg); int fcb_walk(struct fcb *, struct flash_area *, fcb_walk_cb cb, void *cb_arg); int fcb_getnext(struct fcb *, struct fcb_entry *loc); +#if MYNEWT_VAL_FCB_BIDIRECTIONAL +/** + * Call 'cb' for every element in flash circular buffer moving + * from the newest to oldest entries. + * + * @param fcb - fcb to walk through + * @param cb - function to call for each entry + * @param cb_arg - argument to pass to cb + * @return 0 after whole buffer was traversed + * non zero value if cb requested termination of the walk + */ +int fcb_walk_back(struct fcb *fcb, fcb_walk_cb cb, void *cb_arg); +#endif + /** * Erases the data from oldest sector. */ diff --git a/fs/fcb/src/fcb.c b/fs/fcb/src/fcb.c index 4e18fb867..967f5b460 100644 --- a/fs/fcb/src/fcb.c +++ b/fs/fcb/src/fcb.c @@ -82,6 +82,7 @@ fcb_init(struct fcb *fcb) fcb->f_active.fe_area = newest_fap; fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)); fcb->f_active_id = newest; + fcb->f_active.fe_elem_ix = 0; /* Require alignment to be a power of two. Some code depends on this * assumption. @@ -98,6 +99,8 @@ fcb_init(struct fcb *fcb) break; } } + fcb->f_active_sector_entry_count = fcb->f_active.fe_elem_ix; + os_mutex_init(&fcb->f_mtx); return rc; } diff --git a/fs/fcb/src/fcb_append.c b/fs/fcb/src/fcb_append.c index bc44b13ee..b23f43a60 100644 --- a/fs/fcb/src/fcb_append.c +++ b/fs/fcb/src/fcb_append.c @@ -101,6 +101,7 @@ fcb_append(struct fcb *fcb, uint16_t len, struct fcb_entry *append_loc) fcb->f_active.fe_area = fa; fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)); fcb->f_active_id++; + fcb->f_active_sector_entry_count = 0; } rc = flash_area_write(active->fe_area, active->fe_elem_off, tmp_str, cnt); @@ -131,6 +132,7 @@ fcb_append_finish(struct fcb *fcb, struct fcb_entry *loc) uint8_t crc8; uint32_t off; + fcb->f_active_sector_entry_count++; rc = fcb_elem_crc8(fcb, loc, &crc8); if (rc) { return rc; diff --git a/fs/fcb/src/fcb_getnext.c b/fs/fcb/src/fcb_getnext.c index 2cf97f696..6c9d17c63 100644 --- a/fs/fcb/src/fcb_getnext.c +++ b/fs/fcb/src/fcb_getnext.c @@ -20,6 +20,47 @@ #include "fcb/fcb.h" #include "fcb_priv.h" +#include "defs/error.h" + +#if MYNEWT_VAL_FCB_BIDIRECTIONAL +#define FCB_STEP_BACK(loc) ((loc)->fe_step_back) +#else +#define FCB_STEP_BACK(loc) (false) +#endif +#if MYNEWT_VAL_FCB_BIDIRECTIONAL && MYNEWT_VAL_FCB_BIDIRECTIONAL_CACHE +#define FCB_ENTRY_CACHE(loc) ((loc)->fe_cache) +#define FCB_ENTRY_CACHE_DATA(loc) ((loc)->fe_cache->cache_data) +#else +#define FCB_ENTRY_CACHE(loc) (NULL) +#define FCB_ENTRY_CACHE_DATA(loc) (NULL) +#endif + +/** + * Return flash sector size + * + * @param fcb - fcb to check sector size from + * @param sector - 0 base index of sector + * @return sector size + */ +static int +fcb_sector_size(struct fcb *fcb, int sector) +{ + return (int)fcb->f_sectors[sector].fa_size; +} + +/** + * Return offset in flash sector where first entry resides + * + * This points past FCB header that is present in each sector. + * + * @param fcb - fcb to test + * @return offset of first entry in sector (aligned according to flash) + */ +static int +fcb_start_offset(struct fcb *fcb) +{ + return fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)); +} int fcb_getnext_in_area(struct fcb *fcb, struct fcb_entry *loc) @@ -30,12 +71,10 @@ fcb_getnext_in_area(struct fcb *fcb, struct fcb_entry *loc) if (rc == 0 || rc == FCB_ERR_CRC) { do { loc->fe_elem_off = loc->fe_data_off + - fcb_len_in_flash(fcb, loc->fe_data_len) + - fcb_len_in_flash(fcb, FCB_CRC_SZ); + fcb_len_in_flash(fcb, loc->fe_data_len) + + fcb_len_in_flash(fcb, FCB_CRC_SZ); + loc->fe_elem_ix++; rc = fcb_elem_info(fcb, loc); - if (rc != FCB_ERR_CRC) { - break; - } } while (rc == FCB_ERR_CRC); } return rc; @@ -51,63 +90,375 @@ fcb_getnext_area(struct fcb *fcb, struct flash_area *fap) return fap; } +static int +fcb_get_sector_ix(struct fcb *fcb, struct flash_area *fa) +{ + return fa - fcb->f_sectors; +} + +static struct flash_area * +fcb_get_prev_area(struct fcb *fcb, struct flash_area *fap) +{ + fap--; + if (fap < fcb->f_sectors) { + fap = &fcb->f_sectors[fcb->f_sector_cnt - 1]; + } + return fap; +} + +/** + * Return number of bytes needed to encode entry of given length. + * + * Up to 127 bytes are encoded in single byte. + * + * @param len + * @return 1 when len < 0 otherwise 2 + */ +static int +fcb_len_bytes(uint16_t len) +{ + return len > 127 ? 2 : 1; +} + int -fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc) +fcb_entry_total_len(struct fcb *fcb, int len) +{ + return fcb_len_in_flash(fcb, fcb_len_bytes(len)) + + fcb_len_in_flash(fcb, len) + + fcb_len_in_flash(fcb, FCB_CRC_SZ); +} + +/** + * Compute total bytes that fcb_entry occupies in flash. + * + * @param fcb - fcb to get information from. + * @param loc - entry information as filled with fcb_getnext() + * @return number of bytes that entry occupies in flash. + */ +static int +fcb_entry_len_in_flash(struct fcb *fcb, struct fcb_entry *loc) +{ + return fcb_entry_total_len(fcb, loc->fe_data_len); +} + +/** + * Read length of fcb entry that is located at given flash area offset. + * + * @param fcb - fcb to read length from + * @param fa - flash area to read + * @param offset - offset of entry to read + * @return entry length on success + * FCB_ERR_NOVAR - when specified location was not written yet + * FCB_ERR_FLASH - when flash read occurs (flash is corrupted or + * offset is outside flash area range). + */ +static int +fcb_read_entry_len(struct fcb *fcb, struct flash_area *fa, int offset) { int rc; + uint8_t buf[2]; + uint16_t len; - if (loc->fe_area == NULL) { - /* - * Find the first one we have in flash. - */ - loc->fe_area = fcb->f_oldest; + (void)fcb; + + rc = flash_area_read_is_empty(fa, offset, buf, 2); + + if (rc < 0) { + return FCB_ERR_FLASH; + } else if (rc == 1) { + return FCB_ERR_NOVAR; } - if (loc->fe_elem_off == 0) { - /* - * If offset is zero, we serve the first entry from the area. - */ - loc->fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)); - rc = fcb_elem_info(fcb, loc); + + fcb_get_len(buf, &len); + return len; +} + +/** + * Reads entry length from flash and updates fcb_entry + * + * fe_data_off and fe_data_len are updated only if record exists in flash. + * + * @param fcb - fcb to use + * @param loc - entry location description to update + * @return 0 on success + * FCB_ERR_NOVAR - when specified location was not written yet + * FCB_ERR_FLASH - when flash read occurs (flash is corrupted or + * offset is outside flash area range). + */ +static int +fcb_update_entry_len(struct fcb *fcb, struct fcb_entry *loc) +{ + int rc; + + rc = fcb_read_entry_len(fcb, loc->fe_area, (int)loc->fe_elem_off); + + if (rc >= 0) { + loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(fcb, fcb_len_bytes(rc)); + loc->fe_data_len = rc; + rc = 0; + } + + return rc; +} + +/** + * Invalidate entry cache + * + * Called when sector change during walk backward. + * + * @param fcb - fcb to invalidate cache + * @param cache - cache to invalidate + */ +static void +fcb_cache_invalidate(struct fcb *fcb, struct fcb_entry_cache *cache) +{ + (void)fcb; + + if (cache) { + cache->cache_count = 0; + cache->sector_ix = 0xFFFF; + } +} + +/** + * Function invalidates cache if sector changes + * + * If sector number is different that one that was cached all entries are + * removed. + * + * @param fcb - fcb to invalidate cache + * @param cache - cache to invalidate if needed + * @param sector_ix - sector number + */ +static void +fcb_cache_switch_to_sector(struct fcb *fcb, struct fcb_entry_cache *cache, int sector_ix) +{ + if (cache != NULL && cache->sector_ix != sector_ix) { + fcb_cache_invalidate(fcb, cache); + cache->sector_ix = sector_ix; + } +} + +/** + * Retrieve element length from cache + * + * @param fcb - fcb to use + * @param cache - cache to use + * @param elem_ix - element index + * @return element length if present in cache + * SYS_NOENT if cache does not have element + */ +static int +fcb_cache_elem_len(struct fcb *fcb, struct fcb_entry_cache *cache, int elem_ix) +{ + int len; + + (void)fcb; + + if (cache && cache->cache_count > elem_ix) { + len = cache->cache_data[elem_ix]; } else { - rc = fcb_getnext_in_area(fcb, loc); + len = SYS_ENOENT; } - switch (rc) { - case 0: - return 0; - case FCB_ERR_CRC: - break; - default: - goto next_sector; + return len; +} + +/** + * Store entry information in cache. + * + * Stores entry + * @param fcb - fcb to use + * @param cache - cache to store information (can be NULL) + * @param entry_ix - index of entry in cache + * @param offset - offset of entry + * @param elem_size - FCB entry size in bytes + */ +static void +fcb_cache_add(struct fcb *fcb, struct fcb_entry_cache *cache, int entry_ix, int offset, uint16_t elem_size) +{ + /* Total bytes for entries in sector */ + int sector_data_size; + int first_entry_offset; + + if (cache == NULL || cache->cache_data == NULL) { + return; } - while (rc == FCB_ERR_CRC) { - rc = fcb_getnext_in_area(fcb, loc); - if (rc == 0) { - return 0; + + first_entry_offset = fcb_start_offset(fcb); + + /* Data size is size of sector minus sector header */ + sector_data_size = fcb_sector_size(fcb, cache->sector_ix) - first_entry_offset; + + if (entry_ix >= cache->cache_size) { + assert(cache->cache_count == cache->cache_size); + + int average_entry_size = (offset - first_entry_offset) / entry_ix; + /* guess cache size based on entries currently in flash */ + int new_size = cache->cache_size + 5 + (sector_data_size - offset) / average_entry_size; + size_t cache_byte_count = new_size * sizeof(cache->cache_data[0]); + + cache->cache_data = os_realloc(cache->cache_data, cache_byte_count); + if (cache->cache_data == NULL) { + cache->sector_ix = 0xFFFF; + cache->cache_size = 0; + cache->cache_count = 0; + } else { + cache->cache_size = new_size; } + } + + if (cache->cache_data) { + cache->cache_data[entry_ix] = elem_size; + cache->cache_count++; + } +} - if (rc != FCB_ERR_CRC) { +int +fcb_step(struct fcb *fcb, struct fcb_entry *loc, int previous_error) +{ + int offset; + int entry_len; + int rc = 0; + int first_entry_offset = fcb_start_offset(fcb); + + if (FCB_STEP_BACK(loc)) { + if (loc->fe_area == NULL) { /* - * Moving to next sector. + * Stepping back with empty fcb_entry means that walks starts from + * last entry in active sector. + * If FCB is not empty f_active has inconsistent data: fe_data_len and fe_data_off + * refer to last saved entry while fe_elem_off points past this entry where new + * record should be written hence loc is is reconstructed. */ -next_sector: - if (loc->fe_area == fcb->f_active.fe_area) { - return FCB_ERR_NOVAR; + if (fcb->f_active.fe_elem_off != first_entry_offset) { + loc->fe_area = fcb->f_active.fe_area; + loc->fe_elem_ix = fcb->f_active_sector_entry_count - 1; + loc->fe_elem_off = + fcb->f_active.fe_data_off - fcb_len_in_flash(fcb, fcb_len_bytes(fcb->f_active.fe_data_len)); + loc->fe_data_off = fcb->f_active.fe_data_off; + loc->fe_data_len = fcb->f_active.fe_data_len; + } else { + /* FCB is empty */ + rc = FCB_ERR_NOVAR; } - loc->fe_area = fcb_getnext_area(fcb, loc->fe_area); - loc->fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)); - rc = fcb_elem_info(fcb, loc); - switch (rc) { - case 0: - return 0; - case FCB_ERR_CRC: - break; - default: - goto next_sector; + } else { + struct fcb_entry loc1 = *loc; + int target_ix = loc->fe_elem_ix - 1; + loc1.fe_data_len = 0; + + /* Begin of sector ? */ + if (loc->fe_elem_off == first_entry_offset) { + /* Oldest sector, nowhere to go */ + if (fcb->f_oldest == loc->fe_area) { + rc = FCB_ERR_NOVAR; + } else { + /* Switch to previous sector and find last entry */ + loc1.fe_area = fcb_get_prev_area(fcb, loc->fe_area); + loc1.fe_elem_off = 0; + loc1.fe_elem_ix = 0; + } + } + if (rc != FCB_ERR_NOVAR) { + int data_len; + struct fcb_entry_cache *cache = FCB_ENTRY_CACHE(loc); + /* Empty cache if sector changed */ + fcb_cache_switch_to_sector(fcb, cache, fcb_get_sector_ix(fcb, loc1.fe_area)); + + if (loc->fe_elem_off && target_ix >= 0 && (data_len = fcb_cache_elem_len(fcb, cache, target_ix)) > 0) { + loc->fe_elem_ix = target_ix; + loc->fe_data_len = data_len; + loc->fe_elem_off = loc->fe_elem_off - fcb_entry_total_len(fcb, data_len); + loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(fcb, data_len); + } else { + loc1.fe_elem_off = first_entry_offset; + loc1.fe_data_len = 0; + loc1.fe_elem_ix = 0; + if (cache && cache->cache_data) { + for (loc1.fe_elem_ix = 0; + loc1.fe_elem_ix < cache->cache_count && loc1.fe_elem_ix < target_ix;) { + loc1.fe_data_len = fcb_cache_elem_len(fcb, cache, loc1.fe_elem_ix); + loc1.fe_elem_off += fcb_entry_total_len(fcb, loc1.fe_data_len); + loc1.fe_elem_ix++; + } + } + + entry_len = 0; + while (true) { + rc = fcb_update_entry_len(fcb, &loc1); + if (rc < 0) { + /* + * Here either there is no more entries or there is flash error. + * Get data from loc1 that was set from previous entry. + * If entry_len == 0 it means that not even single entry was found. + * It means that there was no entry in sector return rc without + * modifying loc. + */ + if (entry_len) { + /* data_off and data_len are intact from previous read */ + *loc = loc1; + /* fe_elem_off and fe_elem_ix were already moved, correct to last entry */ + loc->fe_elem_off -= entry_len; + loc->fe_elem_ix--; + rc = 0; + } + break; + } else if (loc1.fe_elem_ix == target_ix) { + *loc = loc1; + break; + } + fcb_cache_add(fcb, cache, loc1.fe_elem_ix, loc1.fe_elem_off, loc1.fe_data_len); + entry_len = fcb_entry_len_in_flash(fcb, &loc1); + offset = (int)loc1.fe_elem_off + entry_len; + loc1.fe_elem_off = offset; + loc1.fe_elem_ix++; + } + } } } + } else { + if (loc->fe_area == NULL) { + loc->fe_area = fcb->f_oldest; + loc->fe_elem_off = fcb_start_offset(fcb); + loc->fe_elem_ix = 0; + loc->fe_data_len = 0; + } else if (previous_error == FCB_ERR_NOVAR) { + /* If there are more sectors, move to next one */ + if (loc->fe_area != fcb->f_active.fe_area) { + loc->fe_area = fcb_getnext_area(fcb, loc->fe_area); + loc->fe_elem_off = fcb_start_offset(fcb); + loc->fe_elem_ix = 0; + loc->fe_data_len = 0; + } else { + /* No more sectors NOVAR sticks */ + rc = FCB_ERR_NOVAR; + } + } else if (loc->fe_elem_off == 0) { + loc->fe_elem_off = fcb_start_offset(fcb); + loc->fe_elem_ix = 0; + loc->fe_data_len = 0; + } else { + loc->fe_elem_off += fcb_entry_len_in_flash(fcb, loc); + loc->fe_elem_ix++; + } } - return 0; + return rc; +} + +int +fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc) +{ + int rc = 0; + + do { + rc = fcb_step(fcb, loc, rc); + if (rc) { + break; + } + rc = fcb_elem_info(fcb, loc); + } while (rc == FCB_ERR_CRC || rc == FCB_ERR_NOVAR); + + return rc; } int @@ -124,3 +475,42 @@ fcb_getnext(struct fcb *fcb, struct fcb_entry *loc) return rc; } + +int +fcb_cache_init(struct fcb *fcb, struct fcb_entry_cache *cache, int initial_entry_count) +{ + int rc; + size_t cache_byte_count; + + (void)fcb; + + cache->sector_ix = 0xFFFF; + cache->cache_count = 0; + + cache_byte_count = initial_entry_count * sizeof(cache->cache_data[0]); + cache->cache_data = os_malloc(cache_byte_count); + + if (cache->cache_data) { + cache->cache_size = initial_entry_count; + rc = 0; + } else { + cache->cache_size = 0; + rc = SYS_ENOMEM; + } + + return rc; +} + +void +fcb_cache_free(struct fcb *fcb, struct fcb_entry_cache *cache) +{ + (void)fcb; + + if (cache && cache->cache_data) { + os_free(cache->cache_data); + cache->cache_data = NULL; + cache->cache_size = 0; + cache->cache_count = 0; + cache->sector_ix = 0xFFFF; + } +} diff --git a/fs/fcb/src/fcb_priv.h b/fs/fcb/src/fcb_priv.h index d87c0ed34..352aa969a 100644 --- a/fs/fcb/src/fcb_priv.h +++ b/fs/fcb/src/fcb_priv.h @@ -58,6 +58,19 @@ int fcb_sector_hdr_init(struct fcb *, struct flash_area *fap, uint16_t id); int fcb_sector_hdr_read(struct fcb *, struct flash_area *fap, struct fcb_disk_area *fdap); +/** + * Compute total bytes needed to store entry of given length in flash. + * + * Returned value includes size of header (just length) size of entry + * and size of CRC8. Each of those filed can take more space when flash + * alignment is greater then 1. + * + * @param fcb - fcb with alignment restriction field. + * @param len - entry user data length. + * @return number of bytes that entry will occupy in flash. + */ +int fcb_entry_total_len(struct fcb *fcb, int len); + #ifdef __cplusplus } #endif diff --git a/fs/fcb/src/fcb_walk.c b/fs/fcb/src/fcb_walk.c index 17f4be173..b3e61fde6 100644 --- a/fs/fcb/src/fcb_walk.c +++ b/fs/fcb/src/fcb_walk.c @@ -51,3 +51,31 @@ fcb_walk(struct fcb *fcb, struct flash_area *fap, fcb_walk_cb cb, void *cb_arg) os_mutex_release(&fcb->f_mtx); return 0; } + +#if MYNEWT_VAL_FCB_BIDIRECTIONAL +int +fcb_walk_back(struct fcb *fcb, fcb_walk_cb cb, void *cb_arg) +{ + struct fcb_entry loc = { + .fe_step_back = true, + }; + int rc; + + rc = os_mutex_pend(&fcb->f_mtx, OS_WAIT_FOREVER); + if (rc && rc != OS_NOT_STARTED) { + return FCB_ERR_ARGS; + } + while ((rc = fcb_getnext_nolock(fcb, &loc)) != FCB_ERR_NOVAR) { + os_mutex_release(&fcb->f_mtx); + rc = cb(&loc, cb_arg); + if (rc) { + return rc; + } + os_mutex_pend(&fcb->f_mtx, OS_WAIT_FOREVER); + } + os_mutex_release(&fcb->f_mtx); + + return 0; +} + +#endif diff --git a/fs/fcb/syscfg.yml b/fs/fcb/syscfg.yml new file mode 100644 index 000000000..9d4374439 --- /dev/null +++ b/fs/fcb/syscfg.yml @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + FCB_BIDIRECTIONAL: + description: > + Enable support for FCB backward walk. + value: 0 + FCB_BIDIRECTIONAL_CACHE: + description: > + Use heap to cache sector information during walk back. + value: 0
