This is an automated email from the ASF dual-hosted git repository. marko pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 43da6d720ba4bfb608c1766f949b8a47dd5253b2 Author: Marko Kiiskila <ma...@apache.org> AuthorDate: Wed Aug 28 10:33:03 2019 +0300 fs/fcb2; add fcb_getprev() to walk backwards within FCB. --- fs/fcb2/include/fcb/fcb.h | 3 +- fs/fcb2/selftest/src/fcb_test.c | 2 + fs/fcb2/selftest/src/testcases/fcb_test_getprev.c | 140 +++++++++++++++++++++ .../selftest/src/testcases/fcb_test_last_of_n.c | 34 ++--- fs/fcb2/src/fcb.c | 27 ++-- fs/fcb2/src/fcb_elem_info.c | 2 +- fs/fcb2/src/fcb_getnext.c | 6 - fs/fcb2/src/fcb_getprev.c | 102 +++++++++++++++ fs/fcb2/src/fcb_priv.h | 1 - 9 files changed, 276 insertions(+), 41 deletions(-) diff --git a/fs/fcb2/include/fcb/fcb.h b/fs/fcb2/include/fcb/fcb.h index 83b99fd..1b4049d 100644 --- a/fs/fcb2/include/fcb/fcb.h +++ b/fs/fcb2/include/fcb/fcb.h @@ -138,6 +138,7 @@ int fcb_append_finish(struct fcb_entry *append_loc); typedef int (*fcb_walk_cb)(struct fcb_entry *loc, void *arg); int fcb_walk(struct fcb *, int sector, fcb_walk_cb cb, void *cb_arg); int fcb_getnext(struct fcb *fcb, struct fcb_entry *loc); +int fcb_getprev(struct fcb *fcb, struct fcb_entry *loc); int fcb_read(struct fcb_entry *loc, uint16_t off, void *buf, uint16_t len); /** @@ -165,7 +166,7 @@ int fcb_is_empty(struct fcb *fcb); */ int fcb_offset_last_n(struct fcb *fcb, uint8_t entries, - struct fcb_entry *last_n_entry); + struct fcb_entry *last_n_entry); /** * Erase sector in FCB diff --git a/fs/fcb2/selftest/src/fcb_test.c b/fs/fcb2/selftest/src/fcb_test.c index a16e40c..0a29f55 100644 --- a/fs/fcb2/selftest/src/fcb_test.c +++ b/fs/fcb2/selftest/src/fcb_test.c @@ -141,6 +141,7 @@ TEST_CASE_DECL(fcb_test_rotate) TEST_CASE_DECL(fcb_test_multiple_scratch) TEST_CASE_DECL(fcb_test_last_of_n) TEST_CASE_DECL(fcb_test_area_info) +TEST_CASE_DECL(fcb_test_getprev) TEST_SUITE(fcb_test_all) { @@ -154,6 +155,7 @@ TEST_SUITE(fcb_test_all) fcb_test_multiple_scratch(); fcb_test_last_of_n(); fcb_test_area_info(); + fcb_test_getprev(); } int diff --git a/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c b/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c new file mode 100644 index 0000000..ec1a255 --- /dev/null +++ b/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c @@ -0,0 +1,140 @@ +/* + * 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. + */ +#include "fcb_test.h" + +TEST_CASE_SELF(fcb_test_getprev) +{ + struct fcb *fcb = &test_fcb; + struct fcb_entry loc; + struct fcb_entry prev; + int rc; + int i, j; + + fcb_tc_pretest(3); + + prev.fe_range = NULL; + + /* + * Empty FCB returns error. + */ + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT_FATAL(rc == FCB_ERR_NOVAR); + + /* + * Add one entry. getprev should find that guy, and then error. + */ + rc = fcb_append(fcb, 8, &loc); + TEST_ASSERT(rc == 0); + rc = fcb_append_finish(&loc); + TEST_ASSERT(rc == 0); + + prev.fe_range = NULL; + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(!memcmp(&loc, &prev, sizeof(loc))); + + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT(rc == FCB_ERR_NOVAR); + + /* + * Add enough entries to go to 2 sectors, should find them all. + */ + fcb_tc_pretest(3); + for (i = 0; ; i++) { + rc = fcb_append(fcb, i + 1, &loc); + TEST_ASSERT(rc == 0); + rc = fcb_append_finish(&loc); + TEST_ASSERT(rc == 0); + + if (loc.fe_sector == prev.fe_sector + 2) { + break; + } + } + + prev.fe_range = NULL; + for (j = i; j >= 0; j--) { + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT(rc == 0); + TEST_ASSERT(prev.fe_data_len == j + 1); + } + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT(rc == FCB_ERR_NOVAR); + + /* + * Clean the area. Fill 2 whole sectors with corrupt entries. And one + * good one. Should find the one good one, followed by error + */ + fcb_tc_pretest(3); + + for (i = 0; ; i++) { + rc = fcb_append(fcb, i + 1, &loc); + TEST_ASSERT(rc == 0); + + if (loc.fe_sector == prev.fe_sector + 2) { + rc = fcb_append_finish(&loc); + TEST_ASSERT(rc == 0); + break; + } + } + + prev.fe_range = NULL; + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT_FATAL(rc == 0); + TEST_ASSERT(!memcmp(&loc, &prev, sizeof(loc))); + + rc = fcb_getprev(fcb, &prev); + TEST_ASSERT(rc == FCB_ERR_NOVAR); + + /* + * Create new. Rotate one sector, should be able to follow + * from end of range to start. + */ + + fcb_tc_pretest(3); + + for (i = 0; ; i++) { + rc = fcb_append(fcb, i + 8, &loc); + if (rc == FCB_ERR_NOSPACE) { + break; + } + TEST_ASSERT(rc == 0); + rc = fcb_append_finish(&loc); + TEST_ASSERT(rc == 0); + } + + /* + * Full. Rotate, add one more, and then walk backwards. + */ + fcb_rotate(fcb); + + rc = fcb_append(fcb, i + 8, &loc); + TEST_ASSERT(rc == 0); + rc = fcb_append_finish(&loc); + TEST_ASSERT(rc == 0); + + for (j = i; j >= 0; j--) { + rc = fcb_getprev(fcb, &prev); + if (rc == FCB_ERR_NOVAR) { + TEST_ASSERT(i > 0); + break; + } + TEST_ASSERT(rc == 0); + TEST_ASSERT(prev.fe_data_len == j + 8); + } +} diff --git a/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c b/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c index 10ca3d7..2a6c3cd 100644 --- a/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c +++ b/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c @@ -35,7 +35,7 @@ TEST_CASE_SELF(fcb_test_last_of_n) /* No fcbs available */ rc = fcb_offset_last_n(fcb, 1, &loc); - assert (rc != 0); + TEST_ASSERT(rc != 0); /* * Add some fcbs. @@ -57,29 +57,29 @@ TEST_CASE_SELF(fcb_test_last_of_n) /* last entry */ rc = fcb_offset_last_n(fcb, 1, &loc); - assert (rc == 0); - assert (areas[4].fe_sector == loc.fe_sector); - assert (areas[4].fe_data_off == loc.fe_data_off); - assert (areas[4].fe_data_len == loc.fe_data_len); + TEST_ASSERT(rc == 0); + TEST_ASSERT(areas[4].fe_sector == loc.fe_sector); + TEST_ASSERT(areas[4].fe_data_off == loc.fe_data_off); + TEST_ASSERT(areas[4].fe_data_len == loc.fe_data_len); /* somewhere in the middle */ rc = fcb_offset_last_n(fcb, 3, &loc); - assert (rc == 0); - assert (areas[2].fe_sector == loc.fe_sector); - assert (areas[2].fe_data_off == loc.fe_data_off); - assert (areas[2].fe_data_len == loc.fe_data_len); + TEST_ASSERT(rc == 0); + TEST_ASSERT(areas[2].fe_sector == loc.fe_sector); + TEST_ASSERT(areas[2].fe_data_off == loc.fe_data_off); + TEST_ASSERT(areas[2].fe_data_len == loc.fe_data_len); /* first entry */ rc = fcb_offset_last_n(fcb, 5, &loc); - assert (rc == 0); - assert (areas[0].fe_sector == loc.fe_sector); - assert (areas[0].fe_data_off == loc.fe_data_off); - assert (areas[0].fe_data_len == loc.fe_data_len); + TEST_ASSERT(rc == 0); + TEST_ASSERT(areas[0].fe_sector == loc.fe_sector); + TEST_ASSERT(areas[0].fe_data_off == loc.fe_data_off); + TEST_ASSERT(areas[0].fe_data_len == loc.fe_data_len); /* after last valid entry, returns the first one like for 5 */ rc = fcb_offset_last_n(fcb, 6, &loc); - assert (rc == 0); - assert (areas[0].fe_sector == loc.fe_sector); - assert (areas[0].fe_data_off == loc.fe_data_off); - assert (areas[0].fe_data_len == loc.fe_data_len); + TEST_ASSERT(rc == 0); + TEST_ASSERT(areas[0].fe_sector == loc.fe_sector); + TEST_ASSERT(areas[0].fe_data_off == loc.fe_data_off); + TEST_ASSERT(areas[0].fe_data_len == loc.fe_data_len); } diff --git a/fs/fcb2/src/fcb.c b/fs/fcb2/src/fcb.c index 3ec9cf2..80451d6 100644 --- a/fs/fcb2/src/fcb.c +++ b/fs/fcb2/src/fcb.c @@ -122,7 +122,8 @@ fcb_is_empty(struct fcb *fcb) { return (fcb->f_active.fe_sector == fcb->f_oldest_sec && fcb->f_active.fe_data_off == - fcb_len_in_flash(fcb->f_active.fe_range, sizeof(struct fcb_disk_area))); + fcb_len_in_flash(fcb->f_active.fe_range, + sizeof(struct fcb_disk_area))); } struct flash_sector_range * @@ -217,10 +218,8 @@ fcb_sector_hdr_read(struct fcb *fcb, struct flash_sector_range *srp, * @return 0 on there are any fcbs aviable; OS_ENOENT otherwise */ int -fcb_offset_last_n(struct fcb *fcb, uint8_t entries, - struct fcb_entry *last_n_entry) +fcb_offset_last_n(struct fcb *fcb, uint8_t entries, struct fcb_entry *loc) { - struct fcb_entry loc; int i; /* assure a minimum amount of entries */ @@ -229,19 +228,16 @@ fcb_offset_last_n(struct fcb *fcb, uint8_t entries, } i = 0; - memset(&loc, 0, sizeof(loc)); - while (!fcb_getnext(fcb, &loc)) { - if (i == 0) { - /* Start from the beginning of fcb entries */ - *last_n_entry = loc; - } else if (i > (entries - 1)) { - /* Update last_n_entry after n entries and keep updating */ - fcb_getnext(fcb, last_n_entry); - } + memset(loc, 0, sizeof(*loc)); + while (!fcb_getprev(fcb, loc)) { + --entries; i++; + if (entries == 0) { + break; + } } - return (i == 0) ? OS_ENOENT : 0; + return (i == 0) ? FCB_ERR_NOVAR : 0; } /** @@ -285,7 +281,8 @@ fcb_init_flash_area(struct fcb *fcb, int flash_area_id, uint32_t magic, assert(rc == 0 && sector_range_cnt > 0); sector_ranges = malloc(sizeof(struct flash_sector_range) * sector_range_cnt); assert(sector_ranges); - rc = flash_area_to_sector_ranges(flash_area_id, §or_range_cnt, sector_ranges); + rc = flash_area_to_sector_ranges(flash_area_id, §or_range_cnt, + sector_ranges); assert(rc == 0 && sector_range_cnt > 0); fcb->f_ranges = sector_ranges; diff --git a/fs/fcb2/src/fcb_elem_info.c b/fs/fcb2/src/fcb_elem_info.c index 413eea2..a222f36 100644 --- a/fs/fcb2/src/fcb_elem_info.c +++ b/fs/fcb2/src/fcb_elem_info.c @@ -57,7 +57,7 @@ fcb_elem_crc16(struct fcb_entry *loc, uint16_t *c16p) return 0; } -int +static int fcb_read_entry(struct fcb_entry *loc) { uint8_t buf[FCB_ENTRY_SIZE]; diff --git a/fs/fcb2/src/fcb_getnext.c b/fs/fcb2/src/fcb_getnext.c index 4284afe..f90e26d 100644 --- a/fs/fcb2/src/fcb_getnext.c +++ b/fs/fcb2/src/fcb_getnext.c @@ -59,9 +59,6 @@ fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc) * If offset is zero, we serve the first entry from the area. */ loc->fe_entry_num = 1; - loc->fe_data_off = - fcb_len_in_flash(loc->fe_range, sizeof(struct fcb_disk_area)); - loc->fe_data_len = 0; rc = fcb_elem_info(loc); } else { rc = fcb_getnext_in_area(fcb, loc); @@ -91,9 +88,6 @@ next_sector: loc->fe_sector = fcb_getnext_sector(fcb, loc->fe_sector); loc->fe_range = fcb_get_sector_range(fcb, loc->fe_sector); loc->fe_entry_num = 1; - loc->fe_data_off = - fcb_len_in_flash(loc->fe_range, sizeof(struct fcb_disk_area)); - loc->fe_data_len = 0; rc = fcb_elem_info(loc); switch (rc) { case 0: diff --git a/fs/fcb2/src/fcb_getprev.c b/fs/fcb2/src/fcb_getprev.c new file mode 100644 index 0000000..6cdbe33 --- /dev/null +++ b/fs/fcb2/src/fcb_getprev.c @@ -0,0 +1,102 @@ +/* + * 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. + */ +#include <stddef.h> + +#include "fcb/fcb.h" +#include "fcb_priv.h" + +static int +fcb_sector_find_last(struct fcb *fcb, struct fcb_entry *loc) +{ + int rc; + int last_valid = 0; + + loc->fe_entry_num = 1; + + do { + rc = fcb_elem_info(loc); + if (rc == 0) { + last_valid = loc->fe_entry_num; + } + if (rc == FCB_ERR_NOVAR) { + /* + * Out entries in this sector + */ + if (last_valid == 0) { + loc->fe_entry_num = 1; + /* + * No valid entries in this sector. + */ + return FCB_ERR_NOVAR; + } else { + loc->fe_entry_num = last_valid; + rc = fcb_elem_info(loc); + assert(rc == 0); /* must be; just succeeded a bit earlier */ + return rc; + } + } + loc->fe_entry_num++; + } while (1); + return rc; +} + +int +fcb_getprev(struct fcb *fcb, struct fcb_entry *loc) +{ + int rc; + + rc = os_mutex_pend(&fcb->f_mtx, OS_WAIT_FOREVER); + if (rc && rc != OS_NOT_STARTED) { + return FCB_ERR_ARGS; + } + if (loc->fe_range == NULL) { + /* + * Find the last element. + */ + *loc = fcb->f_active; + } + do { + loc->fe_entry_num--; + if (loc->fe_entry_num < 1) { + /* + * Need to get from previous sector. + */ + if (loc->fe_sector == fcb->f_oldest_sec) { + return FCB_ERR_NOVAR; + } + if (loc->fe_sector == 0) { + loc->fe_sector = fcb->f_sector_cnt - 1; + } else { + loc->fe_sector--; + } + loc->fe_range = fcb_get_sector_range(fcb, loc->fe_sector); + rc = fcb_sector_find_last(fcb, loc); + if (rc == 0) { + break; + } + } else { + rc = fcb_elem_info(loc); + if (rc == 0) { + break; + } + } + } while (1); + os_mutex_release(&fcb->f_mtx); + return rc; +} diff --git a/fs/fcb2/src/fcb_priv.h b/fs/fcb2/src/fcb_priv.h index 63f18e3..a1ec9d5 100644 --- a/fs/fcb2/src/fcb_priv.h +++ b/fs/fcb2/src/fcb_priv.h @@ -67,7 +67,6 @@ int fcb_elem_crc16(struct fcb_entry *loc, uint16_t *c16p); int fcb_sector_hdr_init(struct fcb *fcb, int sector, uint16_t id); int fcb_entry_location_in_range(const struct fcb_entry *loc); - struct flash_sector_range *fcb_get_sector_range(const struct fcb *fcb, int sector);