From 799fe4e68476f7499aca5560557ff4cdb81f83c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=98=95?= Date: Fri, 16 Sep 2022 15:35:30 +0800 Subject: [PATCH] testing/mtd_config_fs:more test cases for garbage collection. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 田昕 --- .../mtd_config_fs/mtd_config_fs_test_main.c | 488 ++++++++++++++++++ 1 file changed, 488 insertions(+) diff --git a/testing/mtd_config_fs/mtd_config_fs_test_main.c b/testing/mtd_config_fs/mtd_config_fs_test_main.c index 33b30843b..b11b9351c 100644 --- a/testing/mtd_config_fs/mtd_config_fs_test_main.c +++ b/testing/mtd_config_fs/mtd_config_fs_test_main.c @@ -1979,6 +1979,491 @@ test_fail: return; } +/**************************************************************************** + * Name: test_nvs_gc_touched_deleted_ate + * Description: Test case when writing and gc touched A prev entry + * which was deleted. + ****************************************************************************/ + +static void test_nvs_gc_touched_deleted_ate(struct mtdnvs_ctx_s *ctx) +{ + int ret; + uint16_t filling_id = 0; + uint16_t i; + uint16_t data_read; + int fd = -1; + struct config_data_s data; + + printf("%s: test begin\n", __func__); + ret = setup(ctx); + if (ret < 0) + { + printf("%s:setup failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + fd = open("/dev/config", 0); + if (fd < 0) + { + printf("%s:open failed, ret=%d\n", __func__, fd); + goto test_fail; + } + + while (1) + { + sprintf(data.name, "k%04x", filling_id); + data.configdata = (FAR uint8_t *)&filling_id; + data.len = sizeof(filling_id); + + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + + /* ENOSPC will be accompanied by gc 3 times(if 3 blocks) + * block will change three times: + * block: 0, 1, 2 + * A B gc + * (gc==1) gc B A + * (gc==2) B gc A + * (gc==3) B A gc + */ + + if (ret == -1 && errno == ENOSPC) + { + break; + } + else if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + filling_id++; + } + + /* Now delete last record. + * The layout should be: + * block: 0, 1, 2 + * B(deleted) A gc + */ + + sprintf(data.name, "k%04x", filling_id - 1); + data.configdata = NULL; + data.len = 0; + ret = ioctl(fd, CFGDIOC_DELCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_DELCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* Now input B again, + * we should trigger gc for once, and we needn't search for + * the old one again because it is expired. + */ + + filling_id -= 1; + sprintf(data.name, "k%04x", filling_id); + data.configdata = (FAR uint8_t *)&filling_id; + data.len = sizeof(filling_id); + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* Sanitycheck on NVS content */ + + for (i = 0; i <= filling_id; i++) + { + sprintf(data.name, "k%04x", i); + data.configdata = (FAR uint8_t *)&data_read; + data.len = sizeof(data_read); + + ret = ioctl(fd, CFGDIOC_GETCONFIG, &data); + + if (ret != 0) + { + printf("%s:CFGDIOC_GETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + else + { + if (data_read != i) + { + printf("%s:read data %d \n", __func__, data_read); + printf("%s:read expected %d\n", __func__, i); + printf("%s:read unexpected data: %d instead of %d\n", + __func__, data_read, i); + ret = -EIO; + goto test_fail; + } + } + } + + close(fd); + + /* At the end of test, erase all blocks */ + + ret = teardown(); + if (ret < 0) + { + printf("%s:teardown failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + printf("%s: success\n", __func__); + return; + +test_fail: + if (fd >= 0) + { + close(fd); + } + + printf("%s: failed\n", __func__); + return; +} + +/**************************************************************************** + * Name: test_nvs_gc_touched_expired_ate + * Description: Test case when writing and gc touched A prev entry + * which was moved by gc. + ****************************************************************************/ + +static void test_nvs_gc_touched_expired_ate(struct mtdnvs_ctx_s *ctx) +{ + int ret; + uint16_t filling_id = 0; + uint16_t update_id; + uint16_t i; + uint16_t data_read; + int fd = -1; + struct config_data_s data; + + printf("%s: test begin\n", __func__); + ret = setup(ctx); + if (ret < 0) + { + printf("%s:setup failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + fd = open("/dev/config", 0); + if (fd < 0) + { + printf("%s:open failed, ret=%d\n", __func__, fd); + goto test_fail; + } + + while (1) + { + sprintf(data.name, "k%04x", filling_id); + data.configdata = (FAR uint8_t *)&filling_id; + data.len = sizeof(filling_id); + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + if (ret == -1 && errno == ENOSPC) + { + break; + } + else if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + filling_id++; + } + + /* Now delete, + * the layout should be: + * block: 0, 1, 2 + * B A(deleted) gc + */ + + sprintf(data.name, "k%04x", 1); + data.configdata = NULL; + data.len = 0; + ret = ioctl(fd, CFGDIOC_DELCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_DELCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* The last sector is full now, test re-initialization */ + + close(fd); + fd = -1; + mtdconfig_unregister(); + ret = setup(ctx); + if (ret < 0) + { + printf("%s:setup failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + fd = open("/dev/config", 0); + if (fd < 0) + { + printf("%s:open failed, ret=%d\n", __func__, fd); + goto test_fail; + } + + /* Now update A. + * It should trigger gc for twice, and we need to search for + * the old one again as gc has touched the old one. We will + * find it and expire the old A. + */ + + update_id = 3; + sprintf(data.name, "k%04x", 2); + data.configdata = (FAR uint8_t *)&update_id; + data.len = sizeof(update_id); + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* Sanitycheck on NVS content */ + + for (i = 0; i <= filling_id - 1; i++) + { + sprintf(data.name, "k%04x", i); + data.configdata = (FAR uint8_t *)&data_read; + data.len = sizeof(data_read); + ret = ioctl(fd, CFGDIOC_GETCONFIG, &data); + if (i == 1) + { + if (ret != -1 || errno != ENOENT) + { + printf("%s:shouldn't found the entry: %d\n", __func__, i); + ret = -EIO; + goto test_fail; + } + } + else if (ret != 0) + { + printf("%s:CFGDIOC_GETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + else if (i == 2) + { + if (data_read != 3) + { + printf("%s:read data %d \n", __func__, data_read); + printf("%s:read expected %d\n", __func__, 3); + printf("%s:read unexpected data: %d instead of %d\n", + __func__, data_read, 3); + ret = -EIO; + goto test_fail; + } + } + else + { + if (data_read != i) + { + printf("%s:read data %d \n", __func__, data_read); + printf("%s:read expected %d\n", __func__, i); + printf("%s:read unexpected data: %d instead of %d\n", + __func__, data_read, i); + ret = -EIO; + goto test_fail; + } + } + } + + close(fd); + + /* At the end of test, erase all blocks */ + + ret = teardown(); + if (ret < 0) + { + printf("%s:teardown failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + printf("%s: success\n", __func__); + return; + +test_fail: + if (fd >= 0) + { + close(fd); + } + + printf("%s: failed\n", __func__); + return; +} + +/**************************************************************************** + * Name: test_nvs_gc_not_touched_expired_ate + * Description: Test case when writing and gc not touched a prev entry + * which was moved by gc. + ****************************************************************************/ + +static void test_nvs_gc_not_touched_expired_ate(struct mtdnvs_ctx_s *ctx) +{ + int ret; + uint16_t filling_id = 0; + uint16_t update_id; + uint16_t i; + uint16_t data_read; + int fd = -1; + struct config_data_s data; + + printf("%s: test begin\n", __func__); + ret = setup(ctx); + if (ret < 0) + { + printf("%s:setup failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + fd = open("/dev/config", 0); + if (fd < 0) + { + printf("%s:open failed, ret=%d\n", __func__, fd); + goto test_fail; + } + + while (1) + { + sprintf(data.name, "k%04x", filling_id); + data.configdata = (FAR uint8_t *)&filling_id; + data.len = sizeof(filling_id); + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + if (ret == -1 && errno == ENOSPC) + { + break; + } + else if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + filling_id++; + } + + /* Now delete last record, + * the layout should be: + * block: 0, 1, 2 + * B(deleted) A gc + */ + + sprintf(data.name, "k%04x", filling_id - 1); + data.configdata = NULL; + data.len = 0; + ret = ioctl(fd, CFGDIOC_DELCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_DELCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* Now udpate A again. + * We should trigger gc for once, and we won't need to search for + * the old one again after gc. + */ + + update_id = 3; + sprintf(data.name, "k%04x", 2); + data.configdata = (FAR uint8_t *)&update_id; + data.len = sizeof(update_id); + ret = ioctl(fd, CFGDIOC_SETCONFIG, &data); + if (ret != 0) + { + printf("%s:CFGDIOC_SETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + + /* Sanitycheck on NVS content */ + + for (i = 0; i <= filling_id - 1; i++) + { + sprintf(data.name, "k%04x", i); + data.configdata = (FAR uint8_t *)&data_read; + data.len = sizeof(data_read); + ret = ioctl(fd, CFGDIOC_GETCONFIG, &data); + if (i == filling_id - 1) + { + if (ret != -1 || errno != ENOENT) + { + printf("%s:shouldn't found the entry: %d\n", __func__, i); + ret = -EIO; + goto test_fail; + } + } + else if (ret != 0) + { + printf("%s:CFGDIOC_GETCONFIG failed, ret=%d\n", __func__, ret); + ret = -EIO; + goto test_fail; + } + else if (i == 2) + { + if (data_read != 3) + { + printf("%s:read data %d \n", __func__, data_read); + printf("%s:read expected %d\n", __func__, 3); + printf("%s:read unexpected data: %d instead of %d\n", + __func__, data_read, 3); + ret = -EIO; + goto test_fail; + } + } + else + { + if (data_read != i) + { + printf("%s:read data %d \n", __func__, data_read); + printf("%s:read expected %d\n", __func__, i); + printf("%s:read unexpected data: %d instead of %d\n", + __func__, data_read, i); + ret = -EIO; + goto test_fail; + } + } + } + + close(fd); + + /* At the end of test, erase all blocks */ + + ret = teardown(); + if (ret < 0) + { + printf("%s:teardown failed, ret=%d\n", __func__, ret); + goto test_fail; + } + + printf("%s: success\n", __func__); + return; + +test_fail: + if (fd >= 0) + { + close(fd); + } + + printf("%s: failed\n", __func__); + return; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -2043,6 +2528,9 @@ int main(int argc, FAR char *argv[]) test_nvs_full_sector(ctx); test_nvs_gc_corrupt_close_ate(ctx); test_nvs_gc_corrupt_ate(ctx); + test_nvs_gc_touched_deleted_ate(ctx); + test_nvs_gc_touched_expired_ate(ctx); + test_nvs_gc_not_touched_expired_ate(ctx); /* Show memory usage */