Compare commits
45 commits
e089e2ba4e
...
adbd045af5
Author | SHA1 | Date | |
---|---|---|---|
adbd045af5 | |||
23b478e582 | |||
635df8e06f | |||
9a2888341d | |||
5cc4824fdb | |||
1638f9b0f1 | |||
4c2f4eab24 | |||
dddba0af8f | |||
52a7ec1fae | |||
bf1f0f4bee | |||
0d1ffa71fb | |||
bea048006a | |||
65d269e2d4 | |||
e40bd819d6 | |||
fc1476d9dd | |||
851c0cb7a6 | |||
ae3b7933b7 | |||
f3eb5df644 | |||
5004fed4aa | |||
6243dabea8 | |||
920a59499b | |||
b8426f12f2 | |||
1153f2bdcd | |||
6dcfd0d322 | |||
d778e5a325 | |||
c6744d6975 | |||
73057f6f25 | |||
0da262cc0f | |||
bbfb9ca800 | |||
8e4dc856e7 | |||
2ff1003430 | |||
c1a7b885f2 | |||
d2aa954573 | |||
f951d695e8 | |||
b4ecfb527c | |||
ed49402e3b | |||
3e0df6537a | |||
108178d1be | |||
a63e7656fe | |||
e84226657c | |||
18d2adcb85 | |||
f0a8439c51 | |||
bbc799f805 | |||
b29e0b945d | |||
82d765bee3 |
41 changed files with 2710 additions and 112 deletions
32
Makefile
32
Makefile
|
@ -14,23 +14,26 @@ all: $(BUILD)/tbm
|
|||
|
||||
CFLAGS += -DTBM_VERSION=\"2017-07-27-dev\"
|
||||
CFLAGS += -Iinclude
|
||||
CFLAGS += -Wall -Wundef -Wextra -Wshadow -Wimplicit-function-declaration
|
||||
CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes -pedantic
|
||||
CFLAGS += -Wall -Wextra -Wshadow -Wimplicit-function-declaration
|
||||
CFLAGS += -Wredundant-decls -pedantic
|
||||
CFLAGS += -D_XOPEN_SOURCE
|
||||
|
||||
CFLAGS += -std=c99
|
||||
CFLAGS += -Os -flto
|
||||
LDFLAGS += -Os -flto
|
||||
|
||||
TEST_LIBS += -lcmocka
|
||||
|
||||
-include source/Makefile
|
||||
|
||||
obj-y += source/bitops.o
|
||||
obj-y += source/main.o
|
||||
|
||||
obj-y += source/core/flash.o
|
||||
|
||||
obj = $(addprefix $(BUILD)/, $(obj-y))
|
||||
|
||||
tbm-obj = $(addprefix $(BUILD)/, $(tbm-obj-y))
|
||||
tbm-obj += $(obj)
|
||||
|
||||
test-obj = $(addprefix $(BUILD)/, $(test-obj-y))
|
||||
test-obj += $(obj)
|
||||
|
||||
# Include the dependencies.
|
||||
-include $(obj:.o=.d)
|
||||
|
||||
|
@ -52,9 +55,18 @@ $(BUILD)/%.o: %.c
|
|||
@mkdir -p $(dir $@)
|
||||
@$(CC) -c $< -o $@ $(CFLAGS) -MT $@ -MMD -MP -MF $(@:.o=.d)
|
||||
|
||||
$(BUILD)/tbm: $(obj) $(LDSCRIPT)
|
||||
$(BUILD)/tbm: $(tbm-obj) $(LDSCRIPT)
|
||||
@echo "LD $@"
|
||||
@mkdir -p $(dir $@)
|
||||
@$(LD) -o $@ $(CFLAGS) $(LDFLAGS) $(obj) $(LIBS)
|
||||
@$(LD) -o $@ $(CFLAGS) $(LDFLAGS) $(tbm-obj) $(LIBS)
|
||||
|
||||
.PHONY: clean
|
||||
$(BUILD)/test: CFLAGS += $(TEST_CFLAGS)
|
||||
$(BUILD)/test: $(test-obj)
|
||||
@echo "LD $@"
|
||||
@mkdir -p $(dir $@)
|
||||
@$(LD) -o $@ $(CFLAGS) $(LDFLAGS) $(TEST_LDFLAGS) $(test-obj) $(LIBS) $(TEST_LIBS)
|
||||
|
||||
test: $(BUILD)/test
|
||||
@$(BUILD)/test
|
||||
|
||||
.PHONY: clean test
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
struct console {
|
||||
FILE *fp;
|
||||
};
|
||||
|
|
|
@ -15,11 +15,14 @@ struct ftl_page_desc {
|
|||
uint32_t subtrees[32];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ftl_tlb_entry {
|
||||
uint32_t va, page;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
struct ftl_map {
|
||||
struct flash_dev *dev;
|
||||
unsigned flags;
|
||||
uint32_t last_va;
|
||||
uint32_t last_pa;
|
||||
struct ftl_tlb_entry outstanding;
|
||||
uint32_t offset;
|
||||
uint32_t head, tail;
|
||||
uint32_t root;
|
||||
|
@ -33,9 +36,9 @@ struct ftl_map {
|
|||
uint8_t epoch;
|
||||
};
|
||||
|
||||
#define FTL_CACHED_VA BIT(0)
|
||||
#define FTL_UNMAPPED BIT(1)
|
||||
#define FTL_DIRTY BIT(2)
|
||||
#define FTL_PRESENT BIT(7)
|
||||
#define FTL_NO_MAPPING BIT(6)
|
||||
#define FTL_AGE(x) (x & BITS(0, 3))
|
||||
|
||||
#define FTL_MAX_ATTEMPTS 8
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct flash_dev;
|
||||
struct mufs;
|
||||
struct mufs_dir;
|
||||
|
|
3
include/shell/progress.h
Normal file
3
include/shell/progress.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void draw_progress(FILE *fp, unsigned long pos, unsigned max);
|
|
@ -1,7 +1,5 @@
|
|||
CFLAGS += -g
|
||||
|
||||
obj-y += source/drivers/sandbox_flash.o
|
||||
obj-y += source/drivers/stdio_console.o
|
||||
CFLAGS += -DHAVE_SYS_TYPES_H=1
|
||||
|
||||
tools: $(BUILD)/create-image
|
||||
all: tools
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
-include source/core/Makefile
|
||||
-include source/ftl/Makefile
|
||||
-include source/mufs/Makefile
|
||||
-include source/platform/Makefile
|
||||
-include source/shell/Makefile
|
||||
-include source/tests/Makefile
|
||||
|
||||
obj-y += source/bitops.o
|
||||
|
||||
tbm-obj-y += source/main.o
|
||||
|
|
1
source/core/Makefile
Normal file
1
source/core/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
tbm-obj-y += source/core/flash.o
|
|
@ -5,9 +5,9 @@
|
|||
#include <flash.h>
|
||||
#include <macros.h>
|
||||
|
||||
static int default_flash_is_val(struct flash_dev *dev, uint32_t addr, char val)
|
||||
static int default_flash_is_val(struct flash_dev *dev, uint32_t addr, uint8_t val)
|
||||
{
|
||||
char data[32];
|
||||
uint8_t data[32];
|
||||
size_t i, nbytes, len = 1 << dev->log2_block_size;
|
||||
|
||||
addr <<= dev->log2_block_size;
|
||||
|
@ -88,6 +88,11 @@ size_t flash_get_capacity(struct flash_dev *dev)
|
|||
return dev->ops->get_capacity(dev);
|
||||
}
|
||||
|
||||
#ifdef flash_read
|
||||
#undef flash_read
|
||||
#define flash_read __real_flash_read
|
||||
#endif
|
||||
|
||||
size_t flash_read(struct flash_dev *dev, uint32_t addr, void *data, size_t len)
|
||||
{
|
||||
if (!dev)
|
||||
|
@ -96,6 +101,16 @@ size_t flash_read(struct flash_dev *dev, uint32_t addr, void *data, size_t len)
|
|||
return dev->ops->read(dev, addr, data, len);
|
||||
}
|
||||
|
||||
#ifdef flash_read
|
||||
#undef flash_read
|
||||
#define flash_read __wrap_flash_read
|
||||
#endif
|
||||
|
||||
#ifdef flash_write
|
||||
#undef flash_write
|
||||
#define flash_write __real_flash_write
|
||||
#endif
|
||||
|
||||
size_t flash_write(struct flash_dev *dev, uint32_t addr, const void *data,
|
||||
size_t len)
|
||||
{
|
||||
|
@ -105,6 +120,16 @@ size_t flash_write(struct flash_dev *dev, uint32_t addr, const void *data,
|
|||
return dev->ops->write(dev, addr, data, len);
|
||||
}
|
||||
|
||||
#ifdef flash_write
|
||||
#undef flash_write
|
||||
#define flash_write __wrap_flash_write
|
||||
#endif
|
||||
|
||||
#ifdef flash_write0
|
||||
#undef flash_write0
|
||||
#define flash_write0 __real_flash_write0
|
||||
#endif
|
||||
|
||||
size_t flash_write0(struct flash_dev *dev, uint32_t addr, size_t len)
|
||||
{
|
||||
uint8_t data[32];
|
||||
|
@ -126,6 +151,16 @@ size_t flash_write0(struct flash_dev *dev, uint32_t addr, size_t len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef flash_write0
|
||||
#undef flash_write0
|
||||
#define flash_write0 __wrap_flash_write0
|
||||
#endif
|
||||
|
||||
#ifdef flash_copy
|
||||
#undef flash_copy
|
||||
#define flash_copy __real_flash_copy
|
||||
#endif
|
||||
|
||||
size_t flash_copy(struct flash_dev *dev, uint32_t dst, uint32_t src, size_t len)
|
||||
{
|
||||
if (!dev)
|
||||
|
@ -134,6 +169,16 @@ size_t flash_copy(struct flash_dev *dev, uint32_t dst, uint32_t src, size_t len)
|
|||
return dev->ops->copy(dev, dst, src, len);
|
||||
}
|
||||
|
||||
#ifdef flash_copy
|
||||
#undef flash_copy
|
||||
#define flash_copy __wrap_flash_copy
|
||||
#endif
|
||||
|
||||
#ifdef flash_is_erased
|
||||
#undef flash_is_erased
|
||||
#define flash_is_erased __real_flash_is_erased
|
||||
#endif
|
||||
|
||||
int flash_is_erased(struct flash_dev *dev, uint32_t addr, size_t len)
|
||||
{
|
||||
if (!dev)
|
||||
|
@ -149,6 +194,11 @@ int flash_is_erased(struct flash_dev *dev, uint32_t addr, size_t len)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef flash_is_erased
|
||||
#undef flash_is_erased
|
||||
#define flash_is_erased __wrap_flash_is_erased
|
||||
#endif
|
||||
|
||||
int flash_erase(struct flash_dev *dev, uint32_t addr, size_t len)
|
||||
{
|
||||
if (!dev)
|
||||
|
|
|
@ -32,7 +32,7 @@ static struct flash_ops stdio_flash_ops = {
|
|||
.read = stdio_flash_read,
|
||||
.write = stdio_flash_write,
|
||||
.copy = default_flash_copy,
|
||||
.is_erased = default_flash_is_erased,
|
||||
.is_erased = default_flash_is_one,
|
||||
.erase = stdio_flash_erase,
|
||||
};
|
||||
|
||||
|
|
|
@ -44,11 +44,41 @@ size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va)
|
|||
len);
|
||||
}
|
||||
|
||||
static int ftl_start_transaction(struct ftl_map *map, uint32_t va)
|
||||
{
|
||||
uint32_t page;
|
||||
int ret;
|
||||
|
||||
if ((map->outstanding.flags & FTL_PRESENT) && map->outstanding.va == va)
|
||||
return 0;
|
||||
|
||||
if (ftl_sync(map) < 0)
|
||||
return -1;
|
||||
|
||||
if ((ret = trace_path(map, NULL, &page, va)) < 0 && ret != -ERR_NOT_FOUND)
|
||||
return -1;
|
||||
|
||||
if (prepare_head(map) < 0)
|
||||
return -1;
|
||||
|
||||
map->outstanding.flags |= FTL_PRESENT;
|
||||
map->outstanding.va = va;
|
||||
map->outstanding.page = page;
|
||||
|
||||
if (ret == -ERR_NOT_FOUND) {
|
||||
map->outstanding.flags |= FTL_NO_MAPPING;
|
||||
++map->nused_pages;
|
||||
}
|
||||
|
||||
map->offset = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftl_seek(struct ftl_map *map, uint32_t va)
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
uint32_t offset, page, dst, src;
|
||||
uint32_t offset, dst, src;
|
||||
|
||||
if (va >= ftl_get_capacity(map))
|
||||
return -1;
|
||||
|
@ -56,12 +86,7 @@ static int ftl_seek(struct ftl_map *map, uint32_t va)
|
|||
offset = va & ((1 << map->log2_page_size) - 1);
|
||||
va >>= map->log2_page_size;
|
||||
|
||||
if ((map->flags & FTL_CACHED_VA) && map->last_va != va &&
|
||||
ftl_sync(map) < 0)
|
||||
return -1;
|
||||
|
||||
if ((ret = trace_path(map, NULL, &page, va)) < 0 &&
|
||||
ret != -ERR_NOT_FOUND)
|
||||
if (ftl_start_transaction(map, va) < 0)
|
||||
return -1;
|
||||
|
||||
if (offset < map->offset)
|
||||
|
@ -70,19 +95,11 @@ static int ftl_seek(struct ftl_map *map, uint32_t va)
|
|||
if (offset == map->offset)
|
||||
return 0;
|
||||
|
||||
if (map->offset == 0) {
|
||||
if (prepare_head(map) < 0)
|
||||
return -1;
|
||||
|
||||
if (ret == -ERR_NOT_FOUND)
|
||||
++map->nused_pages;
|
||||
}
|
||||
|
||||
dst = map->head << map->log2_page_size;
|
||||
src = page << map->log2_page_size;
|
||||
src = map->outstanding.page << map->log2_page_size;
|
||||
len = offset - map->offset;
|
||||
|
||||
if (ret == -ERR_NOT_FOUND)
|
||||
if (map->outstanding.flags & FTL_NO_MAPPING)
|
||||
flash_write0(map->dev, dst, len);
|
||||
else
|
||||
flash_copy(map->dev, dst, src, len);
|
||||
|
@ -107,7 +124,6 @@ size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata,
|
|||
return 0;
|
||||
|
||||
map->offset += len;
|
||||
map->flags |= FTL_DIRTY;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -117,31 +133,31 @@ int ftl_sync(struct ftl_map *map)
|
|||
struct ftl_page_desc page_desc;
|
||||
size_t len;
|
||||
int ret;
|
||||
uint32_t page, dst, src;
|
||||
uint32_t dst, src;
|
||||
|
||||
if (!(map->flags & FTL_DIRTY))
|
||||
if (!(map->outstanding.flags & FTL_PRESENT))
|
||||
return 0;
|
||||
|
||||
if ((ret = trace_path(map, &page_desc, &page, map->last_va)) < 0 &&
|
||||
ret != -ERR_NOT_FOUND)
|
||||
return -1;
|
||||
|
||||
dst = (map->head << map->log2_page_size) + map->offset;
|
||||
src = (page << map->log2_page_size) + map->offset;
|
||||
src = (map->outstanding.page << map->log2_page_size) + map->offset;
|
||||
len = (1 << map->log2_page_size) - map->offset;
|
||||
|
||||
if (map->flags & FTL_UNMAPPED)
|
||||
if (map->outstanding.flags & FTL_NO_MAPPING)
|
||||
flash_write0(map->dev, dst, len);
|
||||
else
|
||||
flash_copy(map->dev, dst, src, len);
|
||||
|
||||
page_desc.nused_pages = map->nused_pages;
|
||||
|
||||
if ((ret = trace_path(map, &page_desc, NULL, map->outstanding.va)) < 0 &&
|
||||
ret != -ERR_NOT_FOUND)
|
||||
return -1;
|
||||
|
||||
if (write_page_desc(map, &page_desc) < 0)
|
||||
return -1;
|
||||
|
||||
map->offset = 0;
|
||||
map->flags &= ~(FTL_CACHED_VA | FTL_UNMAPPED | FTL_DIRTY);
|
||||
map->outstanding.flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -163,8 +179,6 @@ int ftl_trim(struct ftl_map *map, uint32_t va)
|
|||
return ret;
|
||||
}
|
||||
|
||||
--map->nused_pages;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
level = 32 - i - 1;
|
||||
|
||||
|
@ -174,6 +188,7 @@ int ftl_trim(struct ftl_map *map, uint32_t va)
|
|||
|
||||
if (i == 32) {
|
||||
map->root = UINT32_MAX;
|
||||
map->nused_pages = 0;
|
||||
|
||||
memset(&page_desc, 0xff, sizeof page_desc);
|
||||
page_desc.nused_pages = 0;
|
||||
|
@ -184,6 +199,8 @@ int ftl_trim(struct ftl_map *map, uint32_t va)
|
|||
if (read_page_desc(map, &alt_page_desc, alt_page) < 0)
|
||||
return -1;
|
||||
|
||||
--map->nused_pages;
|
||||
|
||||
page_desc.va = alt_page_desc.va;
|
||||
page_desc.nused_pages = map->nused_pages;
|
||||
page_desc.subtrees[level] = UINT32_MAX;
|
||||
|
|
|
@ -114,6 +114,11 @@ static int free_tail(struct ftl_map *map)
|
|||
* nothing to be done. Otherwise, we free the tail if necessary and erase the
|
||||
* block for writing.
|
||||
*/
|
||||
#ifdef prepare_head
|
||||
#undef prepare_head
|
||||
#define prepare_head __real_prepare_head
|
||||
#endif
|
||||
|
||||
int prepare_head(struct ftl_map *map)
|
||||
{
|
||||
size_t log2_pages_per_block = map->log2_pages_per_group +
|
||||
|
|
123
source/ftl/map.c
123
source/ftl/map.c
|
@ -12,9 +12,14 @@
|
|||
/* Given the group number, this function checks if a page group is erased by
|
||||
* checking if the pages that compose the page group are erased.
|
||||
*/
|
||||
static int is_group_erased(struct ftl_map *map, uint32_t group)
|
||||
#ifdef is_group_erased
|
||||
#undef is_group_erased
|
||||
#define is_group_erased __real_is_group_erased
|
||||
#endif
|
||||
|
||||
int is_group_erased(struct ftl_map *map, uint32_t group)
|
||||
{
|
||||
char data[32];
|
||||
uint8_t data[32];
|
||||
struct flash_dev *dev = map->dev;
|
||||
uint32_t addr = group << (map->log2_pages_per_group + map->log2_page_size);
|
||||
size_t i, nbytes, len = 1 << (map->log2_pages_per_group + map->log2_page_size);
|
||||
|
@ -37,6 +42,13 @@ static int is_group_erased(struct ftl_map *map, uint32_t group)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef is_group_erased
|
||||
#undef is_group_erased
|
||||
#define is_group_erased __wrap_is_group_erased
|
||||
#endif
|
||||
|
||||
int __wrap_is_group_erased(struct ftl_map *map, uint32_t group);
|
||||
|
||||
/* Given the current user page, this function computes the page number of the
|
||||
* next user page by incrementing the page number. However, if incrementing the
|
||||
* page number results in the page number of a page containing page
|
||||
|
@ -46,7 +58,7 @@ static int is_group_erased(struct ftl_map *map, uint32_t group)
|
|||
* possible pages on the devices, the page number of the very first user page
|
||||
* is returned instead.
|
||||
*/
|
||||
static uint32_t next_upage(struct ftl_map *map, uint32_t p)
|
||||
uint32_t next_upage(struct ftl_map *map, uint32_t p)
|
||||
{
|
||||
size_t log2_pages_per_block = map->log2_pages_per_group +
|
||||
map->log2_groups_per_block;
|
||||
|
@ -75,6 +87,9 @@ int read_page_group(struct ftl_map *map,
|
|||
if (flash_read(map->dev, addr, group, sizeof *group) == 0)
|
||||
return -1;
|
||||
|
||||
if (memcmp(group->magic, "FTL", 3) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -82,16 +97,25 @@ int read_page_group(struct ftl_map *map,
|
|||
* with the user page by locating the footer and more specifically the page
|
||||
* descriptor within the page group.
|
||||
*/
|
||||
#ifdef read_page_desc
|
||||
#undef read_page_desc
|
||||
#define read_page_desc __real_read_page_desc
|
||||
#endif
|
||||
|
||||
int read_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc, uint32_t upage)
|
||||
{
|
||||
uint32_t addr, offset;
|
||||
|
||||
addr = align(upage, map->log2_pages_per_group) +
|
||||
(1 << map->log2_pages_per_group) - 1;
|
||||
|
||||
if (addr == upage)
|
||||
return -1;
|
||||
|
||||
addr <<= map->log2_page_size;
|
||||
offset = sizeof(struct ftl_page_group) +
|
||||
BIT_MASK(upage, map->log2_pages_per_group) * sizeof *page_desc;
|
||||
upage = align(upage, map->log2_pages_per_group) +
|
||||
(1 << map->log2_pages_per_group) - 1;
|
||||
addr = upage << map->log2_page_size;
|
||||
|
||||
if (flash_read(map->dev, addr + offset, page_desc, sizeof *page_desc) == 0)
|
||||
return -1;
|
||||
|
@ -102,9 +126,19 @@ int read_page_desc(struct ftl_map *map,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef read_page_desc
|
||||
#undef read_page_desc
|
||||
#define read_page_desc __wrap_read_page_desc
|
||||
#endif
|
||||
|
||||
/* Writes the page descriptor to the footer of the current page group and
|
||||
* increments the head to point to the next free user page.
|
||||
*/
|
||||
#ifdef write_page_desc
|
||||
#undef write_page_desc
|
||||
#define write_page_desc __real_write_page_desc
|
||||
#endif
|
||||
|
||||
int write_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc)
|
||||
{
|
||||
|
@ -144,6 +178,11 @@ int write_page_desc(struct ftl_map *map,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef write_page_desc
|
||||
#undef write_page_desc
|
||||
#define write_page_desc __wrap_write_page_desc
|
||||
#endif
|
||||
|
||||
/* Prepares the head for writing, writes the user page to the current available
|
||||
* user page and finally writes the page descriptor to the footer of the page
|
||||
* group, whereupon the head is incremented to point to the next available user
|
||||
|
@ -170,7 +209,7 @@ int write_upage(struct ftl_map *map, const void *page,
|
|||
* can also be determined, as a single page group may not cover a whole erase
|
||||
* block.
|
||||
*/
|
||||
static int find_block_div(struct ftl_map *map)
|
||||
int find_block_div(struct ftl_map *map)
|
||||
{
|
||||
size_t log2_pages_per_block = map->log2_block_size - map->log2_page_size;
|
||||
size_t nbytes_avail = (1 << map->log2_page_size) -
|
||||
|
@ -198,7 +237,12 @@ static int find_block_div(struct ftl_map *map)
|
|||
* use, as a block can only be erased as a whole. Therefore, if the first page
|
||||
* group is not in use, neither will the other page groups in a block.
|
||||
*/
|
||||
static int find_block(struct ftl_map *map, struct ftl_page_group *group,
|
||||
#ifdef find_block
|
||||
#undef find_block
|
||||
#define find_block __real_find_block
|
||||
#endif
|
||||
|
||||
int find_block(struct ftl_map *map, struct ftl_page_group *group,
|
||||
uint32_t *where, uint32_t block)
|
||||
{
|
||||
uint32_t page;
|
||||
|
@ -223,43 +267,46 @@ static int find_block(struct ftl_map *map, struct ftl_page_group *group,
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef find_block
|
||||
#undef find_block
|
||||
#define find_block __wrap_find_block
|
||||
#endif
|
||||
|
||||
int find_block(struct ftl_map *map, struct ftl_page_group *group,
|
||||
uint32_t *where, uint32_t block);
|
||||
|
||||
/* Given the block number of the first block, attempts to use binary search to
|
||||
* find the last block that is in use.
|
||||
*/
|
||||
static uint32_t find_last_block(struct ftl_map *map, uint32_t first)
|
||||
uint32_t find_last_block(struct ftl_map *map, uint32_t first)
|
||||
{
|
||||
struct ftl_page_group group;
|
||||
uint32_t mid, low = first, high = map->nblocks - 1;
|
||||
uint32_t found, next;
|
||||
|
||||
while (low <= high) {
|
||||
while (low < high) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
if (find_block(map, &group, &found, mid) < 0 ||
|
||||
group.epoch != map->epoch) {
|
||||
if (!mid)
|
||||
return first;
|
||||
|
||||
high = mid - 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (((found + 1) > map->nblocks) ||
|
||||
find_block(map, &group, &next, found + 1) < 0 ||
|
||||
if (find_block(map, &group, &next, found + 1) < 0 ||
|
||||
group.epoch != map->epoch)
|
||||
return found;
|
||||
|
||||
low = next;
|
||||
}
|
||||
|
||||
return first;
|
||||
return low;
|
||||
}
|
||||
|
||||
/* Attempts to find the last page group that is in use within a block by
|
||||
* performing a binary search on the page groups.
|
||||
*/
|
||||
static uint32_t find_last_group(struct ftl_map *map, uint32_t block)
|
||||
uint32_t find_last_group(struct ftl_map *map, uint32_t block)
|
||||
{
|
||||
uint32_t ngroups = UINT32_C(1) << map->log2_groups_per_block;
|
||||
uint32_t mid, low = 0, high = ngroups - 1;
|
||||
|
@ -267,7 +314,7 @@ static uint32_t find_last_group(struct ftl_map *map, uint32_t block)
|
|||
low += block << map->log2_groups_per_block;
|
||||
high += block << map->log2_groups_per_block;
|
||||
|
||||
while (low <= high) {
|
||||
while (low < high) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
if (is_group_erased(map, mid)) {
|
||||
|
@ -281,10 +328,10 @@ static uint32_t find_last_group(struct ftl_map *map, uint32_t block)
|
|||
low = mid + 1;
|
||||
}
|
||||
|
||||
return block << map->log2_groups_per_block;
|
||||
return low;
|
||||
}
|
||||
|
||||
static int find_root(struct ftl_map *map, uint32_t group)
|
||||
int find_root(struct ftl_map *map, uint32_t group)
|
||||
{
|
||||
struct ftl_page_desc page_desc;
|
||||
uint32_t upage;
|
||||
|
@ -306,7 +353,7 @@ static int find_root(struct ftl_map *map, uint32_t group)
|
|||
* within the page group, the first user page of the next page group should be
|
||||
* used as that page group should not be in use.
|
||||
*/
|
||||
static int find_head(struct ftl_map *map)
|
||||
int find_head(struct ftl_map *map)
|
||||
{
|
||||
size_t log2_pages_per_block = map->log2_pages_per_group +
|
||||
map->log2_groups_per_block;
|
||||
|
@ -333,9 +380,8 @@ static void reset_map(struct ftl_map *map)
|
|||
|
||||
map->nblocks = flash_get_size(map->dev) >> map->log2_block_size;
|
||||
|
||||
map->flags = 0;
|
||||
map->last_va = 0;
|
||||
map->last_pa = 0;
|
||||
memset(&map->outstanding, 0, sizeof map->outstanding);
|
||||
|
||||
map->offset = 0;
|
||||
map->head = 0;
|
||||
map->tail = 0;
|
||||
|
@ -400,6 +446,11 @@ int ftl_resume_map(struct ftl_map *map)
|
|||
* depth until we have either found that there is no further subtree to
|
||||
* traverse or until we have found the actual user page.
|
||||
*/
|
||||
#ifdef trace_path
|
||||
#undef trace_path
|
||||
#define trace_path __real_trace_path
|
||||
#endif
|
||||
|
||||
int trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
|
||||
uint32_t *page, uint32_t va)
|
||||
{
|
||||
|
@ -407,21 +458,6 @@ int trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
|
|||
uint8_t depth = 0;
|
||||
uint32_t upage = map->root;
|
||||
|
||||
#if 0
|
||||
/* FIXME */
|
||||
if (!new_page_desc && (map->flags & FTL_CACHED_VA) && map->last_va == va) {
|
||||
if (map->flags & FTL_UNMAPPED)
|
||||
return -1;
|
||||
|
||||
if (page)
|
||||
*page = map->last_pa;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
map->flags &= ~(FTL_CACHED_VA | FTL_UNMAPPED);
|
||||
|
||||
if (new_page_desc)
|
||||
new_page_desc->va = va;
|
||||
|
||||
|
@ -457,10 +493,6 @@ int trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
|
|||
if (page)
|
||||
*page = upage;
|
||||
|
||||
map->flags |= FTL_CACHED_VA;
|
||||
map->last_va = va;
|
||||
map->last_pa = upage;
|
||||
|
||||
return 0;
|
||||
|
||||
err_not_found:
|
||||
|
@ -470,8 +502,5 @@ err_not_found:
|
|||
}
|
||||
}
|
||||
|
||||
map->flags |= FTL_CACHED_VA | FTL_UNMAPPED;
|
||||
map->last_va = va;
|
||||
|
||||
return -ERR_NOT_FOUND;
|
||||
}
|
||||
|
|
|
@ -75,8 +75,8 @@ long mufs_seek(struct mufs_file *file, long offset, int whence)
|
|||
|
||||
switch (whence) {
|
||||
case SEEK_SET: break;
|
||||
case SEEK_CUR: offset = file->va + offset; break;
|
||||
case SEEK_END: offset = file->tree->file_size; break;
|
||||
case SEEK_CUR: offset += file->va; break;
|
||||
case SEEK_END: offset += file->tree->file_size; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -278,6 +278,7 @@ static size_t mufs_do_write(struct mufs_tree *tree,
|
|||
{
|
||||
struct mufs *fs = tree->fs;
|
||||
struct flash_dev *dev = fs->dev;
|
||||
size_t ret;
|
||||
uint32_t page, offset;
|
||||
|
||||
offset = va & ((UINT32_C(1) << dev->log2_block_size) - 1);
|
||||
|
@ -287,8 +288,16 @@ static size_t mufs_do_write(struct mufs_tree *tree,
|
|||
if (mufs_alloc_page(tree, &page, va) < 0)
|
||||
return 0;
|
||||
|
||||
return flash_write(dev, (page << dev->log2_block_size) + offset, data,
|
||||
ret = flash_write(dev, (page << dev->log2_block_size) + offset, data,
|
||||
len);
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
if (flash_sync(dev) < 0)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t mufs_tree_write(struct mufs_tree *tree, void *data,
|
||||
|
@ -326,5 +335,5 @@ int mufs_sync_tree(struct mufs_tree *tree)
|
|||
if (flash_write(dev, tree->va, &dtree, sizeof dtree) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return flash_sync(dev);
|
||||
}
|
||||
|
|
|
@ -1,7 +1 @@
|
|||
ifeq ($(TARGET),host)
|
||||
else
|
||||
obj-y += source/platform/spi_flash.o
|
||||
obj-y += source/platform/usart.o
|
||||
endif
|
||||
|
||||
-include source/platform/$(TARGET)/Makefile
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
obj-y += source/platform/spi_flash.o
|
||||
obj-y += source/platform/usart.o
|
||||
|
||||
obj-y += source/platform/stm32f0/gpio.o
|
||||
obj-y += source/platform/stm32f0/rcc.o
|
||||
obj-y += source/platform/stm32f0/rtc.o
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
obj-y += source/platform/spi_flash.o
|
||||
obj-y += source/platform/usart.o
|
||||
|
||||
obj-y += source/platform/stm32f1/gpio.o
|
||||
obj-y += source/platform/stm32f1/rcc.o
|
||||
obj-y += source/platform/stm32f1/rtc.o
|
||||
|
|
|
@ -5,5 +5,6 @@ obj-y += source/shell/echo.o
|
|||
obj-y += source/shell/flash.o
|
||||
obj-y += source/shell/ftl.o
|
||||
obj-y += source/shell/mufs.o
|
||||
obj-y += source/shell/progress.o
|
||||
obj-y += source/shell/rtc.o
|
||||
obj-y += source/shell/version.o
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <shell.h>
|
||||
|
||||
#include <shell/mufs.h>
|
||||
#include <shell/progress.h>
|
||||
|
||||
extern struct flash_dev *flash;
|
||||
struct mufs *mufs = NULL;
|
||||
|
@ -144,12 +145,12 @@ int shell_stat(struct console *con, size_t argc, const char **argv)
|
|||
}
|
||||
|
||||
switch (stat.type) {
|
||||
case MUFS_DIR: printf(" type: directory\n"); break;
|
||||
case MUFS_FILE: printf(" type: file\n"); break;
|
||||
case MUFS_DIR: fprintf(con->fp, " type: directory\n"); break;
|
||||
case MUFS_FILE: fprintf(con->fp, " type: file\n"); break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
printf(" file size: %" PRIu32 " bytes\n", stat.file_size);
|
||||
fprintf(con->fp, " file size: %" PRIu32 " bytes\n", stat.file_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -274,6 +275,76 @@ int shell_mv(struct console *con, size_t argc, const char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int shell_cp(struct console *con, size_t argc, const char **argv)
|
||||
{
|
||||
struct mufs_stat stat;
|
||||
struct mufs_file *in, *out;
|
||||
char data[256];
|
||||
size_t ret;
|
||||
size_t count = 0;
|
||||
size_t total;
|
||||
|
||||
if (!mufs) {
|
||||
fprintf(con->fp, "error: no file system mounted.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(con->fp, "usage: mufs cp <src> <dst>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mufs_stat(mufs, argv[0], &stat) < 0) {
|
||||
fprintf(con->fp, "error: unable to stat the file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stat.type != MUFS_FILE) {
|
||||
fprintf(con->fp, "error: only able to copy files\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
total = stat.file_size;
|
||||
|
||||
if (!(in = mufs_open(mufs, argv[0], MUFS_READ))) {
|
||||
fprintf(con->fp, "error: unable to open the file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(out = mufs_open(mufs, argv[1], MUFS_WRITE))) {
|
||||
fprintf(con->fp, "error: unable to open the file\n");
|
||||
goto err_close_in;
|
||||
}
|
||||
|
||||
draw_progress(con->fp, count, total);
|
||||
|
||||
while (count < total) {
|
||||
ret = mufs_read(in, data, sizeof data);
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
ret = mufs_write(out, data, ret);
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
count += ret;
|
||||
draw_progress(con->fp, count, total);
|
||||
}
|
||||
|
||||
fputc('\n', con->fp);
|
||||
|
||||
mufs_close(out);
|
||||
mufs_close(in);
|
||||
|
||||
return 0;
|
||||
|
||||
err_close_in:
|
||||
mufs_close(in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int shell_rm(struct console *con, size_t argc, const char **argv)
|
||||
{
|
||||
if (argc < 1) {
|
||||
|
@ -334,6 +405,7 @@ static struct cmd mufs_cmds[] = {
|
|||
{ "write", NULL, shell_write },
|
||||
{ "append", NULL, shell_append },
|
||||
{ "mv", NULL, shell_mv, },
|
||||
{ "cp", NULL, shell_cp, },
|
||||
{ "rm", NULL, shell_rm, },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
|
26
source/shell/progress.c
Normal file
26
source/shell/progress.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define TERM_WIDTH 80
|
||||
|
||||
void draw_progress(FILE *fp, unsigned long pos, unsigned long max)
|
||||
{
|
||||
unsigned long head, i;
|
||||
|
||||
if (pos > max)
|
||||
pos = max;
|
||||
|
||||
head = (TERM_WIDTH - 2) * pos / max;
|
||||
|
||||
fputc('[', fp);
|
||||
|
||||
for (i = 0; i < head; ++i)
|
||||
fputc('#', fp);
|
||||
|
||||
for (; i < (TERM_WIDTH - 2); ++i)
|
||||
fputc(' ', fp);
|
||||
|
||||
fputc(']', fp);
|
||||
|
||||
for (i = 0; i < TERM_WIDTH; ++i)
|
||||
fputc('\b', fp);
|
||||
}
|
34
source/tests/Makefile
Normal file
34
source/tests/Makefile
Normal file
|
@ -0,0 +1,34 @@
|
|||
test-obj-y += source/tests/main.o
|
||||
|
||||
test-obj-y += source/tests/flash/mock.o
|
||||
|
||||
test-obj-y += source/tests/ftl/main.o
|
||||
test-obj-y += source/tests/ftl/mock.o
|
||||
test-obj-y += source/tests/ftl/find_block.o
|
||||
test-obj-y += source/tests/ftl/find_block_div.o
|
||||
test-obj-y += source/tests/ftl/find_last_block.o
|
||||
test-obj-y += source/tests/ftl/find_last_group.o
|
||||
test-obj-y += source/tests/ftl/find_head.o
|
||||
test-obj-y += source/tests/ftl/find_root.o
|
||||
test-obj-y += source/tests/ftl/next_upage.o
|
||||
test-obj-y += source/tests/ftl/read_page_group.o
|
||||
test-obj-y += source/tests/ftl/read_page_desc.o
|
||||
test-obj-y += source/tests/ftl/write_page_desc.o
|
||||
test-obj-y += source/tests/ftl/write_upage.o
|
||||
test-obj-y += source/tests/ftl/trace_path.o
|
||||
|
||||
test-obj-y += source/tests/ftl/ftl_is_mapped.o
|
||||
test-obj-y += source/tests/ftl/ftl_read.o
|
||||
|
||||
TEST_CFLAGS += -Dflash_read=__wrap_flash_read
|
||||
TEST_CFLAGS += -Dflash_write=__wrap_flash_write
|
||||
TEST_CFLAGS += -Dflash_write0=__wrap_flash_write0
|
||||
TEST_CFLAGS += -Dflash_copy=__wrap_flash_copy
|
||||
TEST_CFLAGS += -Dflash_is_erased=__wrap_flash_is_erased
|
||||
|
||||
TEST_CFLAGS += -Dis_group_erased=__wrap_is_group_erased
|
||||
TEST_CFLAGS += -Dfind_block=__wrap_find_block
|
||||
TEST_CFLAGS += -Dprepare_head=__wrap_prepare_head
|
||||
TEST_CFLAGS += -Dread_page_desc=__wrap_read_page_desc
|
||||
TEST_CFLAGS += -Dwrite_page_desc=__wrap_write_page_desc
|
||||
TEST_CFLAGS += -Dtrace_path=__wrap_trace_path
|
89
source/tests/flash/mock.c
Normal file
89
source/tests/flash/mock.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
size_t __wrap_flash_read(struct flash_dev *dev, uint32_t addr,
|
||||
void *data, size_t len)
|
||||
{
|
||||
const void *ret_data;
|
||||
size_t ret_len;
|
||||
|
||||
(void)dev;
|
||||
|
||||
check_expected(addr);
|
||||
check_expected(len);
|
||||
|
||||
ret_len = mock_type(size_t);
|
||||
ret_data = mock_type(const void *);
|
||||
|
||||
if (len > ret_len)
|
||||
len = ret_len;
|
||||
|
||||
if (len && ret_data)
|
||||
memcpy(data, ret_data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t __wrap_flash_write(struct flash_dev *dev, uint32_t addr,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
void *ret_data;
|
||||
size_t ret_len;
|
||||
|
||||
(void)dev;
|
||||
|
||||
check_expected(addr);
|
||||
check_expected(len);
|
||||
|
||||
ret_len = mock_type(size_t);
|
||||
ret_data = mock_type(void *);
|
||||
|
||||
if (len > ret_len)
|
||||
len = ret_len;
|
||||
|
||||
if (len)
|
||||
memcpy(ret_data, data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t __wrap_flash_write0(struct flash_dev *dev, uint32_t addr, size_t len)
|
||||
{
|
||||
(void)dev;
|
||||
|
||||
check_expected(addr);
|
||||
check_expected(len);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
size_t __wrap_flash_copy(struct flash_dev *dev, uint32_t dst, uint32_t src, size_t len)
|
||||
{
|
||||
(void)dev;
|
||||
|
||||
check_expected(dst);
|
||||
check_expected(src);
|
||||
check_expected(len);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_flash_is_erased(struct flash_dev *dev, uint32_t addr, size_t len)
|
||||
{
|
||||
(void)dev;
|
||||
|
||||
check_expected(addr);
|
||||
check_expected(len);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
170
source/tests/ftl/find_block.c
Normal file
170
source/tests/ftl/find_block.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int __real_find_block(struct ftl_map *map, struct ftl_page_group *group,
|
||||
uint32_t *where, uint32_t block);
|
||||
|
||||
static void test_block0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
int ret;
|
||||
uint32_t where;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(1 * KIB);
|
||||
map.log2_pages_per_group = ilog2(8);
|
||||
map.nblocks = 64;
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
ret = __real_find_block(&map, &ret_group, &where, 0);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(where, 0);
|
||||
}
|
||||
|
||||
static void test_block3(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
int ret;
|
||||
uint32_t where;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(1 * KIB);
|
||||
map.log2_pages_per_group = ilog2(8);
|
||||
map.nblocks = 64;
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (1 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (2 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (3 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
ret = __real_find_block(&map, &ret_group, &where, 0);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(where, 3);
|
||||
}
|
||||
|
||||
static void test_block8_offset5(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
int ret;
|
||||
uint32_t where;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(1 * KIB);
|
||||
map.log2_pages_per_group = ilog2(8);
|
||||
map.nblocks = 64;
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (5 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (6 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (7 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (8 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
ret = __real_find_block(&map, &ret_group, &where, 5);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(where, 8);
|
||||
}
|
||||
|
||||
static void test_no_block(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
int ret;
|
||||
uint32_t where;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(1 * KIB);
|
||||
map.log2_pages_per_group = ilog2(8);
|
||||
map.nblocks = 64;
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (61 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (62 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (63 * 64 + 8 - 1) * 1 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, 0);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
ret = __real_find_block(&map, &ret_group, &where, 61);
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
int test_find_block(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_block: block=0, offset=0", test_block0, NULL, NULL, NULL },
|
||||
{ "find_block: block=3, offset=0", test_block3, NULL, NULL, NULL },
|
||||
{ "find_block: block=8, offset=5", test_block8_offset5, NULL, NULL, NULL },
|
||||
{ "find_block: no block, offset=61", test_no_block, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_block", tests, NULL, NULL);
|
||||
}
|
70
source/tests/ftl/find_block_div.c
Normal file
70
source/tests/ftl/find_block_div.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int find_block_div(struct ftl_map *map);
|
||||
|
||||
static void test_4k_page_64k_block(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
find_block_div(&map);
|
||||
|
||||
assert_int_equal(1 << map.log2_pages_per_group, 16);
|
||||
assert_int_equal(1 << map.log2_groups_per_block, 1);
|
||||
}
|
||||
|
||||
static void test_4k_page_16k_block(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_block_size = ilog2(16 * KIB);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
find_block_div(&map);
|
||||
|
||||
assert_int_equal(1 << map.log2_pages_per_group, 4);
|
||||
assert_int_equal(1 << map.log2_groups_per_block, 1);
|
||||
}
|
||||
|
||||
static void test_1k_page_64k_block(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_block_size = ilog2(64 * KIB);
|
||||
map.log2_page_size = ilog2(1 * KIB);
|
||||
|
||||
find_block_div(&map);
|
||||
|
||||
assert_int_equal(1 << map.log2_pages_per_group, 8);
|
||||
assert_int_equal(1 << map.log2_groups_per_block, 8);
|
||||
}
|
||||
|
||||
int test_find_block_div(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_block_div: 4K page, 64K block", test_4k_page_64k_block, NULL, NULL, NULL },
|
||||
{ "find_block_div: 4K page, 16K block", test_4k_page_16k_block, NULL, NULL, NULL },
|
||||
{ "find_block_div: 1K page, 64K block", test_1k_page_64k_block, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_block_div", tests, NULL, NULL);
|
||||
}
|
104
source/tests/ftl/find_head.c
Normal file
104
source/tests/ftl/find_head.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int find_head(struct ftl_map *map);
|
||||
|
||||
static void test_erased(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
map.root = 4;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 5);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 1);
|
||||
|
||||
ret = find_head(&map);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map.head, 5);
|
||||
}
|
||||
|
||||
static void test_end_of_block(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
map.root = 4;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 5);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 6);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 7);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 8);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 9);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 10);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 11);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 12);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 13);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 14);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
ret = find_head(&map);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map.head, 16);
|
||||
}
|
||||
|
||||
int test_find_head(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_head: erased", test_erased, NULL, NULL, NULL },
|
||||
{ "find_head: end of block", test_end_of_block, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_head", tests, NULL, NULL);
|
||||
}
|
291
source/tests/ftl/find_last_block.c
Normal file
291
source/tests/ftl/find_last_block.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
uint32_t find_last_block(struct ftl_map *map, uint32_t first);
|
||||
|
||||
static void test_middle(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
group.epoch = 0;
|
||||
|
||||
map.nblocks = 64;
|
||||
map.epoch = 0;
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 31);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 31);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 32);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
ret = find_last_block(&map, 0);
|
||||
assert_int_equal(ret, 31);
|
||||
}
|
||||
|
||||
static void test_first(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
group.epoch = 0;
|
||||
|
||||
map.nblocks = 64;
|
||||
map.epoch = 0;
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 31);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 15);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 7);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 3);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 1);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 0);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
ret = find_last_block(&map, 0);
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_last(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
group.epoch = 0;
|
||||
|
||||
map.nblocks = 64;
|
||||
map.epoch = 0;
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 31);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 31);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 32);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 32);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 47);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 47);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 48);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 48);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 55);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 55);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 56);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 56);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 59);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 59);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 60);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 60);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 61);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 61);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 62);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 62);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 62);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 62);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 63);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 63);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
ret = find_last_block(&map, 0);
|
||||
assert_int_equal(ret, 63);
|
||||
}
|
||||
|
||||
static void test_left_right(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
group.epoch = 0;
|
||||
|
||||
map.nblocks = 64;
|
||||
map.epoch = 0;
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 31);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 31);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 15);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 15);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 16);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 16);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 23);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 23);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 24);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 24);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
ret = find_last_block(&map, 0);
|
||||
assert_int_equal(ret, 23);
|
||||
}
|
||||
|
||||
static void test_right_left(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(group.magic, "FTL", 3);
|
||||
group.epoch = 0;
|
||||
|
||||
map.nblocks = 64;
|
||||
map.epoch = 0;
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 31);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 31);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 32);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 32);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 47);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 47);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 39);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 39);
|
||||
will_return(__wrap_find_block, 0);
|
||||
|
||||
expect_value(__wrap_find_block, map, &map);
|
||||
expect_value(__wrap_find_block, block, 40);
|
||||
will_return(__wrap_find_block, &group);
|
||||
will_return(__wrap_find_block, 40);
|
||||
will_return(__wrap_find_block, -1);
|
||||
|
||||
ret = find_last_block(&map, 0);
|
||||
assert_int_equal(ret, 39);
|
||||
}
|
||||
|
||||
int test_find_last_block(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_last_block: middle", test_middle, NULL, NULL, NULL },
|
||||
{ "find_last_block: first", test_first, NULL, NULL, NULL },
|
||||
{ "find_last_block: last", test_last, NULL, NULL, NULL },
|
||||
{ "find_last_block: left right", test_left_right, NULL, NULL, NULL },
|
||||
{ "find_last_block: right left", test_right_left, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_last_block", tests, NULL, NULL);
|
||||
}
|
156
source/tests/ftl/find_last_group.c
Normal file
156
source/tests/ftl/find_last_group.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
uint32_t find_last_group(struct ftl_map *map, uint32_t block);
|
||||
|
||||
static void test_middle(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_groups_per_block = ilog2(8);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 3);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 4);
|
||||
will_return(__wrap_is_group_erased, 1);
|
||||
|
||||
ret = find_last_group(&map, 4);
|
||||
assert_int_equal(ret, 32 + 3);
|
||||
}
|
||||
|
||||
static void test_first(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_groups_per_block = ilog2(8);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 3);
|
||||
will_return(__wrap_is_group_erased, 1);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 1);
|
||||
will_return(__wrap_is_group_erased, 1);
|
||||
|
||||
ret = find_last_group(&map, 4);
|
||||
assert_int_equal(ret, 32);
|
||||
}
|
||||
|
||||
static void test_last(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_groups_per_block = ilog2(8);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 3);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 4);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 5);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 6);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 6);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 7);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
ret = find_last_group(&map, 4);
|
||||
assert_int_equal(ret, 32 + 7);
|
||||
}
|
||||
|
||||
static void test_left_right(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_groups_per_block = ilog2(8);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 3);
|
||||
will_return(__wrap_is_group_erased, 1);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 1);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 2);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
ret = find_last_group(&map, 4);
|
||||
assert_int_equal(ret, 32 + 2);
|
||||
}
|
||||
|
||||
static void test_right_left(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_groups_per_block = ilog2(8);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 3);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 4);
|
||||
will_return(__wrap_is_group_erased, 0);
|
||||
|
||||
expect_value(__wrap_is_group_erased, map, &map);
|
||||
expect_value(__wrap_is_group_erased, group, 32 + 5);
|
||||
will_return(__wrap_is_group_erased, 1);
|
||||
|
||||
ret = find_last_group(&map, 4);
|
||||
assert_int_equal(ret, 32 + 4);
|
||||
}
|
||||
|
||||
int test_find_last_group(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_last_group: middle", test_middle, NULL, NULL, NULL },
|
||||
{ "find_last_group: first", test_first, NULL, NULL, NULL },
|
||||
{ "find_last_group: last", test_last, NULL, NULL, NULL },
|
||||
{ "find_last_group: left right", test_left_right, NULL, NULL, NULL },
|
||||
{ "find_last_group: right left", test_right_left, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_last_group", tests, NULL, NULL);
|
||||
}
|
153
source/tests/ftl/find_root.c
Normal file
153
source/tests/ftl/find_root.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int find_root(struct ftl_map *map, uint32_t group);
|
||||
|
||||
static void test_group0_upage0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 0);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, -1);
|
||||
|
||||
ret = find_root(&map, 0);
|
||||
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
static void test_group0_upage5(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 0);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 1);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 2);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 3);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 4);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 5);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 6);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, -1);
|
||||
|
||||
ret = find_root(&map, 0);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map.root, 5);
|
||||
}
|
||||
|
||||
static void test_group1_upage5(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 1);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 2);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 3);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 4);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 5);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 16 + 6);
|
||||
will_return(__wrap_read_page_desc, &page_desc);
|
||||
will_return(__wrap_read_page_desc, -1);
|
||||
|
||||
ret = find_root(&map, 1);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map.root, 16 + 5);
|
||||
}
|
||||
|
||||
int test_find_root(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "find_root: group=0, upage=0 (no root)", test_group0_upage0, NULL, NULL, NULL },
|
||||
{ "find_root: group=0, upage=5", test_group0_upage5, NULL, NULL, NULL },
|
||||
{ "find_root: group=1, upage=5", test_group1_upage5, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("find_root", tests, NULL, NULL);
|
||||
}
|
62
source/tests/ftl/ftl_is_mapped.c
Normal file
62
source/tests/ftl/ftl_is_mapped.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
static void test_unmapped(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
expect_value(__wrap_trace_path, map, &map);
|
||||
expect_value(__wrap_trace_path, new_page_desc, NULL);
|
||||
expect_value(__wrap_trace_path, page, NULL);
|
||||
expect_value(__wrap_trace_path, va, 42);
|
||||
will_return(__wrap_trace_path, NULL);
|
||||
will_return(__wrap_trace_path, 0);
|
||||
will_return(__wrap_trace_path, -1);
|
||||
|
||||
ret = ftl_is_mapped(&map, 42);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_mapped(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
expect_value(__wrap_trace_path, map, &map);
|
||||
expect_value(__wrap_trace_path, new_page_desc, NULL);
|
||||
expect_value(__wrap_trace_path, page, NULL);
|
||||
expect_value(__wrap_trace_path, va, 42);
|
||||
will_return(__wrap_trace_path, NULL);
|
||||
will_return(__wrap_trace_path, 0);
|
||||
will_return(__wrap_trace_path, 0);
|
||||
|
||||
ret = ftl_is_mapped(&map, 42);
|
||||
|
||||
assert_int_equal(ret, 1);
|
||||
}
|
||||
|
||||
int test_ftl_is_mapped(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "ftl_is_mapped: unmapped", test_unmapped, NULL, NULL, NULL },
|
||||
{ "ftl_is_mapped: mapped", test_mapped, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("ftl_is_unmapped", tests, NULL, NULL);
|
||||
}
|
80
source/tests/ftl/ftl_read.c
Normal file
80
source/tests/ftl/ftl_read.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
static void test_basic_read(void **state)
|
||||
{
|
||||
char data[24];
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.outstanding.flags = 0;
|
||||
|
||||
expect_value(__wrap_trace_path, map, &map);
|
||||
expect_value(__wrap_trace_path, new_page_desc, NULL);
|
||||
expect_not_value(__wrap_trace_path, page, NULL);
|
||||
expect_value(__wrap_trace_path, va, 4);
|
||||
will_return(__wrap_trace_path, NULL);
|
||||
will_return(__wrap_trace_path, 42);
|
||||
will_return(__wrap_trace_path, 0);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, 42 << 12 | 0x321);
|
||||
expect_value(__wrap_flash_read, len, 24);
|
||||
will_return(__wrap_flash_read, 24);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
ret = ftl_read(&map, data, 24, 0x4321);
|
||||
|
||||
assert_int_equal(ret, 24);
|
||||
}
|
||||
|
||||
static void test_boundary(void **state)
|
||||
{
|
||||
char data[32];
|
||||
struct ftl_map map;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.outstanding.flags = 0;
|
||||
|
||||
expect_value(__wrap_trace_path, map, &map);
|
||||
expect_value(__wrap_trace_path, new_page_desc, NULL);
|
||||
expect_not_value(__wrap_trace_path, page, NULL);
|
||||
expect_value(__wrap_trace_path, va, 4);
|
||||
will_return(__wrap_trace_path, NULL);
|
||||
will_return(__wrap_trace_path, 42);
|
||||
will_return(__wrap_trace_path, 0);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, 42 << 12 | 0xff0);
|
||||
expect_value(__wrap_flash_read, len, 16);
|
||||
will_return(__wrap_flash_read, 16);
|
||||
will_return(__wrap_flash_read, NULL);
|
||||
|
||||
ret = ftl_read(&map, data, 32, 0x4ff0);
|
||||
|
||||
assert_int_equal(ret, 16);
|
||||
}
|
||||
|
||||
int test_ftl_read(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "ftl_read: basic read", test_basic_read, NULL, NULL, NULL },
|
||||
{ "ftl_read: boundary", test_boundary, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("ftl_read", tests, NULL, NULL);
|
||||
}
|
51
source/tests/ftl/main.c
Normal file
51
source/tests/ftl/main.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int test_find_block(void);
|
||||
int test_find_block_div(void);
|
||||
int test_find_last_block(void);
|
||||
int test_find_last_group(void);
|
||||
int test_find_head(void);
|
||||
int test_find_root(void);
|
||||
int test_next_upage(void);
|
||||
int test_read_page_group(void);
|
||||
int test_read_page_desc(void);
|
||||
int test_write_page_desc(void);
|
||||
int test_write_upage(void);
|
||||
int test_trace_path(void);
|
||||
|
||||
int test_ftl_is_mapped(void);
|
||||
int test_ftl_read(void);
|
||||
|
||||
int test_ftl(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += test_find_block();
|
||||
count += test_find_block_div();
|
||||
count += test_find_last_block();
|
||||
count += test_find_last_group();
|
||||
count += test_find_head();
|
||||
count += test_find_root();
|
||||
count += test_next_upage();
|
||||
count += test_read_page_group();
|
||||
count += test_read_page_desc();
|
||||
count += test_write_page_desc();
|
||||
count += test_write_upage();
|
||||
count += test_trace_path();
|
||||
|
||||
count += test_ftl_is_mapped();
|
||||
count += test_ftl_read();
|
||||
|
||||
return count;
|
||||
}
|
87
source/tests/ftl/mock.c
Normal file
87
source/tests/ftl/mock.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <ftl.h>
|
||||
|
||||
int __wrap_is_group_erased(struct ftl_map *map, uint32_t group)
|
||||
{
|
||||
check_expected_ptr(map);
|
||||
check_expected(group);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_find_block(struct ftl_map *map, struct ftl_page_group *group,
|
||||
uint32_t *where, uint32_t block)
|
||||
{
|
||||
struct ftl_page_group *ret_group;
|
||||
|
||||
check_expected_ptr(map);
|
||||
check_expected(block);
|
||||
|
||||
ret_group = mock_type(struct ftl_page_group *);
|
||||
|
||||
if (ret_group)
|
||||
memcpy(group, ret_group, sizeof *group);
|
||||
|
||||
*where = mock_type(uint32_t);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_prepare_head(struct ftl_map *map)
|
||||
{
|
||||
(void)map;
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_read_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc, uint32_t upage)
|
||||
{
|
||||
check_expected_ptr(map);
|
||||
check_expected(upage);
|
||||
|
||||
memcpy(page_desc, mock_type(struct ftl_page_desc *), sizeof *page_desc);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_write_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc)
|
||||
{
|
||||
check_expected_ptr(map);
|
||||
check_expected_ptr(page_desc);
|
||||
|
||||
return mock_type(int);
|
||||
}
|
||||
|
||||
int __wrap_trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
|
||||
uint32_t *page, uint32_t va)
|
||||
{
|
||||
struct ftl_page_desc *ret_page_desc;
|
||||
uint32_t ret_page;
|
||||
|
||||
check_expected_ptr(map);
|
||||
check_expected_ptr(new_page_desc);
|
||||
check_expected_ptr(page);
|
||||
check_expected(va);
|
||||
|
||||
ret_page_desc = mock_type(struct ftl_page_desc *);
|
||||
|
||||
if (new_page_desc)
|
||||
memcpy(new_page_desc, ret_page_desc, sizeof *new_page_desc);
|
||||
|
||||
ret_page = mock_type(uint32_t);
|
||||
|
||||
if (page)
|
||||
*page = ret_page;
|
||||
|
||||
return mock_type(int);
|
||||
}
|
3
source/tests/ftl/mock.h
Normal file
3
source/tests/ftl/mock.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
int __wrap_prepare_head(struct ftl_map *map);
|
124
source/tests/ftl/next_upage.c
Normal file
124
source/tests/ftl/next_upage.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int next_upage(struct ftl_map *map, uint32_t p);
|
||||
|
||||
static void test_upage0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 0);
|
||||
|
||||
assert_int_equal(ret, 1);
|
||||
}
|
||||
|
||||
static void test_upage14(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 14);
|
||||
|
||||
assert_int_equal(ret, 16);
|
||||
}
|
||||
|
||||
static void test_upage15(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 15);
|
||||
|
||||
assert_int_equal(ret, 16);
|
||||
}
|
||||
|
||||
static void test_upage16(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 16);
|
||||
|
||||
assert_int_equal(ret, 17);
|
||||
}
|
||||
|
||||
static void test_upage62(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 62);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_upage63(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_groups_per_block = ilog2(1);
|
||||
map.nblocks = 4;
|
||||
|
||||
ret = next_upage(&map, 63);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
int test_next_upage(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "next_upage: upage=0", test_upage0, NULL, NULL, NULL },
|
||||
{ "next_upage: upage=14", test_upage14, NULL, NULL, NULL },
|
||||
{ "next_upage: upage=15", test_upage15, NULL, NULL, NULL },
|
||||
{ "next_upage: upage=16", test_upage16, NULL, NULL, NULL },
|
||||
{ "next_upage: upage=62 (wraparound)", test_upage62, NULL, NULL, NULL },
|
||||
{ "next_upage: upage=63 (wraparound)", test_upage63, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("next_upage", tests, NULL, NULL);
|
||||
}
|
182
source/tests/ftl/read_page_desc.c
Normal file
182
source/tests/ftl/read_page_desc.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int __real_read_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc, uint32_t upage);
|
||||
|
||||
static void test_upage0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&page_desc.magic, "page", 4);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_read, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, &page_desc);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 0);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_upage14(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&page_desc.magic, "page", 4);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group) + 14 * sizeof(struct ftl_page_desc));
|
||||
expect_value(__wrap_flash_read, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, &page_desc);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 14);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_upage15(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 15);
|
||||
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
static void test_upage16(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&page_desc.magic, "page", 4);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (32 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_read, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, &page_desc);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 16);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_upage30(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&page_desc.magic, "page", 4);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (32 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group) + 14 * sizeof(struct ftl_page_desc));
|
||||
expect_value(__wrap_flash_read, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, &page_desc);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 30);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_upage31(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 31);
|
||||
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
static void test_upage32(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&page_desc.magic, "page", 4);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (48 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_read, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, sizeof page_desc);
|
||||
will_return(__wrap_flash_read, &page_desc);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = __real_read_page_desc(&map, &ret_page_desc, 32);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
int test_read_page_desc(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "read_page_desc: upage=0", test_upage0, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=14", test_upage14, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=15 (invalid)", test_upage15, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=16", test_upage16, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=30", test_upage30, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=31 (invalid)", test_upage31, NULL, NULL, NULL },
|
||||
{ "read_page_desc: upage=32", test_upage32, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("read_page_desc", tests, NULL, NULL);
|
||||
}
|
95
source/tests/ftl/read_page_group.c
Normal file
95
source/tests/ftl/read_page_group.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int read_page_group(struct ftl_map *map,
|
||||
struct ftl_page_group *group, uint32_t upage);
|
||||
|
||||
static void test_magic(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&group.magic, "FtL", 3);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (16 - 1) * 4 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = read_page_group(&map, &ret_group, 0);
|
||||
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
static void test_group0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&group.magic, "FTL", 3);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (16 - 1) * 4 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = read_page_group(&map, &ret_group, 0);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_group1(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_group group, ret_group;
|
||||
size_t ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memcpy(&group.magic, "FTL", 3);
|
||||
|
||||
expect_value(__wrap_flash_read, addr, (2 * 16 - 1) * 4 * KIB);
|
||||
expect_value(__wrap_flash_read, len, sizeof group);
|
||||
will_return(__wrap_flash_read, sizeof group);
|
||||
will_return(__wrap_flash_read, &group);
|
||||
|
||||
map.log2_pages_per_group = ilog2(16);
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
|
||||
ret = read_page_group(&map, &ret_group, 1);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
int test_read_page_group(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "read_page_group: invalid magic", test_magic, NULL, NULL, NULL },
|
||||
{ "read_page_group: group=0", test_group0, NULL, NULL, NULL },
|
||||
{ "read_page_group: group=1", test_group1, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("read_page_group", tests, NULL, NULL);
|
||||
}
|
197
source/tests/ftl/trace_path.c
Normal file
197
source/tests/ftl/trace_path.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int __real_trace_path(struct ftl_map *map, struct ftl_page_desc *new_page_desc,
|
||||
uint32_t *page, uint32_t va);
|
||||
|
||||
static void test_empty_root(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
uint32_t page;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.root = UINT32_MAX;
|
||||
|
||||
ret = __real_trace_path(&map, NULL, &page, 0);
|
||||
|
||||
assert_int_equal(ret, -2);
|
||||
}
|
||||
|
||||
static void test_exact_match(void **state)
|
||||
{
|
||||
struct ftl_page_desc descs[] = {
|
||||
{
|
||||
.va = 0xdeadbeef,
|
||||
.subtrees = {
|
||||
[0] = 19,
|
||||
[1] = 21,
|
||||
[2] = 38,
|
||||
[3] = 81,
|
||||
[4] = 24,
|
||||
[5] = 64,
|
||||
[6] = 25,
|
||||
[7] = 15,
|
||||
[8] = 0,
|
||||
[9] = 73,
|
||||
[10] = 49,
|
||||
[11] = 22,
|
||||
[12] = 85,
|
||||
[13] = 45,
|
||||
[14] = 98,
|
||||
[15] = 7,
|
||||
[16] = 72,
|
||||
[17] = 26,
|
||||
[18] = 92,
|
||||
[19] = 16,
|
||||
[20] = 12,
|
||||
[21] = 57,
|
||||
[22] = 52,
|
||||
[23] = 39,
|
||||
[24] = 28,
|
||||
[25] = 42,
|
||||
[26] = 37,
|
||||
[27] = 87,
|
||||
[28] = 5,
|
||||
[29] = 27,
|
||||
[30] = 30,
|
||||
[31] = 47,
|
||||
},
|
||||
},
|
||||
};
|
||||
struct ftl_page_desc ret_page_desc;
|
||||
struct ftl_map map;
|
||||
uint32_t page;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.root = 75;
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 75);
|
||||
will_return(__wrap_read_page_desc, descs);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
ret = __real_trace_path(&map, &ret_page_desc, &page, 0xdeadbeef);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(page, 75);
|
||||
|
||||
assert_memory_equal(&ret_page_desc, descs, sizeof ret_page_desc);
|
||||
}
|
||||
|
||||
static void test_walk(void **state)
|
||||
{
|
||||
struct ftl_page_desc descs[] = {
|
||||
{
|
||||
.va = 0x7,
|
||||
.subtrees = {
|
||||
[0] = UINT32_MAX,
|
||||
[28] = 43,
|
||||
[29] = UINT32_MAX,
|
||||
},
|
||||
},
|
||||
{
|
||||
.va = 0xb,
|
||||
.subtrees = {
|
||||
[0] = UINT32_MAX,
|
||||
[28] = 42,
|
||||
[29] = 44,
|
||||
[30] = UINT32_MAX,
|
||||
},
|
||||
},
|
||||
{
|
||||
.va = 0xd,
|
||||
.subtrees = {
|
||||
[0] = UINT32_MAX,
|
||||
[29] = 43,
|
||||
[30] = 45,
|
||||
[31] = UINT32_MAX,
|
||||
},
|
||||
},
|
||||
{
|
||||
.va = 0xe,
|
||||
.subtrees = {
|
||||
[0] = UINT32_MAX,
|
||||
[30] = 44,
|
||||
[31] = 46,
|
||||
},
|
||||
},
|
||||
{
|
||||
.va = 0xf,
|
||||
.subtrees = {
|
||||
UINT32_MAX,
|
||||
},
|
||||
},
|
||||
};
|
||||
struct ftl_page_desc ret_page_desc;
|
||||
struct ftl_map map;
|
||||
uint32_t page;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.root = 42;
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 42);
|
||||
will_return(__wrap_read_page_desc, descs);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 43);
|
||||
will_return(__wrap_read_page_desc, descs + 1);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 44);
|
||||
will_return(__wrap_read_page_desc, descs + 2);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 45);
|
||||
will_return(__wrap_read_page_desc, descs + 3);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
expect_value(__wrap_read_page_desc, map, &map);
|
||||
expect_value(__wrap_read_page_desc, upage, 46);
|
||||
will_return(__wrap_read_page_desc, descs + 3);
|
||||
will_return(__wrap_read_page_desc, 0);
|
||||
|
||||
ret = __real_trace_path(&map, &ret_page_desc, &page, 0xf);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(page, 46);
|
||||
|
||||
assert_int_equal(ret_page_desc.va, 0xf);
|
||||
assert_int_equal(ret_page_desc.subtrees[28], 42);
|
||||
assert_int_equal(ret_page_desc.subtrees[29], 43);
|
||||
assert_int_equal(ret_page_desc.subtrees[30], 44);
|
||||
assert_int_equal(ret_page_desc.subtrees[31], 45);
|
||||
}
|
||||
|
||||
int test_trace_path(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "trace_path: empty root", test_empty_root, NULL, NULL, NULL },
|
||||
{ "trace_path: exact match", test_exact_match, NULL, NULL, NULL },
|
||||
{ "trace_path: page descriptor walk", test_walk, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("trace_path", tests, NULL, NULL);
|
||||
}
|
258
source/tests/ftl/write_page_desc.c
Normal file
258
source/tests/ftl/write_page_desc.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int __real_write_page_desc(struct ftl_map *map,
|
||||
struct ftl_page_desc *page_desc);
|
||||
|
||||
static int test_setup(void **state)
|
||||
{
|
||||
struct ftl_map *map;
|
||||
|
||||
if (!(map = test_malloc(sizeof(*map))))
|
||||
return -1;
|
||||
|
||||
map->log2_pages_per_group = ilog2(16);
|
||||
map->log2_groups_per_block = ilog2(1);
|
||||
map->log2_page_size = ilog2(4 * KIB);
|
||||
map->nblocks = 4;
|
||||
map->epoch = 0;
|
||||
|
||||
*state = map;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_teardown(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
|
||||
test_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_head0(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 0;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 0);
|
||||
assert_int_equal(map->head, 1);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_head14(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group) + 14 * sizeof(struct ftl_page_desc));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 14;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 14);
|
||||
assert_int_equal(map->head, 16);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_head16(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 2 * 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (2 * 16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 16;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 16);
|
||||
assert_int_equal(map->head, 17);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_head30(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 2 * 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (2 * 16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group) + 14 * sizeof(struct ftl_page_desc));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 30;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 30);
|
||||
assert_int_equal(map->head, 32);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_head32(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 3 * 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (3 * 16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 32;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 32);
|
||||
assert_int_equal(map->head, 33);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_epoch_wraparound(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 4 * 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (4 * 16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group) + 14 * sizeof(struct ftl_page_desc));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 62;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 62);
|
||||
assert_int_equal(map->head, 0);
|
||||
assert_int_equal(map->epoch, 1);
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
static void test_group_header(void **state)
|
||||
{
|
||||
struct ftl_map *map = *state;
|
||||
struct ftl_page_group ret_group;
|
||||
struct ftl_page_desc page_desc, ret_page_desc;
|
||||
size_t ret;
|
||||
|
||||
expect_value(__wrap_flash_is_erased, addr, 16 - 1);
|
||||
expect_value(__wrap_flash_is_erased, len, 1);
|
||||
will_return(__wrap_flash_is_erased, 1);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (16 - 1) * 4 * KIB);
|
||||
expect_value(__wrap_flash_write, len, sizeof ret_group);
|
||||
will_return(__wrap_flash_write, sizeof ret_group);
|
||||
will_return(__wrap_flash_write, &ret_group);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, (16 - 1) * 4 * KIB +
|
||||
sizeof(struct ftl_page_group));
|
||||
expect_value(__wrap_flash_write, len, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, sizeof page_desc);
|
||||
will_return(__wrap_flash_write, &ret_page_desc);
|
||||
|
||||
map->head = 0;
|
||||
map->epoch = 0;
|
||||
|
||||
ret = __real_write_page_desc(map, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_int_equal(map->root, 0);
|
||||
assert_int_equal(map->head, 1);
|
||||
assert_int_equal(map->epoch, 0);
|
||||
|
||||
assert_memory_equal(ret_group.magic, "FTL", 3);
|
||||
assert_int_equal(ret_group.epoch, map->epoch);
|
||||
|
||||
assert_memory_equal(ret_page_desc.magic, "page", 4);
|
||||
}
|
||||
|
||||
int test_write_page_desc(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "write_page_desc: head=0", test_head0, NULL, NULL, NULL },
|
||||
{ "write_page_desc: head=14", test_head14, NULL, NULL, NULL },
|
||||
{ "write_page_desc: head=16", test_head16, NULL, NULL, NULL },
|
||||
{ "write_page_desc: head=30", test_head30, NULL, NULL, NULL },
|
||||
{ "write_page_desc: head=32", test_head32, NULL, NULL, NULL },
|
||||
{ "write_page_desc: epoch wraparound", test_epoch_wraparound, NULL, NULL, NULL },
|
||||
{ "write_page_desc: group header", test_group_header, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("write_page_desc", tests, test_setup,
|
||||
test_teardown);
|
||||
}
|
131
source/tests/ftl/write_upage.c
Normal file
131
source/tests/ftl/write_upage.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int write_upage(struct ftl_map *map, const void *page,
|
||||
struct ftl_page_desc *page_desc);
|
||||
|
||||
static void test_prepare_head(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.head = 0;
|
||||
|
||||
will_return(__wrap_prepare_head, -1);
|
||||
|
||||
ret = write_upage(&map, NULL, &page_desc);
|
||||
|
||||
assert_int_equal(ret, -1);
|
||||
}
|
||||
|
||||
static void test_null_page(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.head = 0;
|
||||
|
||||
will_return(__wrap_prepare_head, 0);
|
||||
|
||||
expect_value(__wrap_write_page_desc, map, &map);
|
||||
expect_value(__wrap_write_page_desc, page_desc, &page_desc);
|
||||
will_return(__wrap_write_page_desc, 0);
|
||||
|
||||
ret = write_upage(&map, NULL, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void test_page0(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
char page[4 * KIB], ret_page[4 * KIB];
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memset(page, 0x5a, sizeof page);
|
||||
memset(ret_page, 0, sizeof ret_page);
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.head = 0;
|
||||
|
||||
will_return(__wrap_prepare_head, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, 0);
|
||||
expect_value(__wrap_flash_write, len, 4 * KIB);
|
||||
will_return(__wrap_flash_write, 4 * KIB);
|
||||
will_return(__wrap_flash_write, &ret_page);
|
||||
|
||||
expect_value(__wrap_write_page_desc, map, &map);
|
||||
expect_value(__wrap_write_page_desc, page_desc, &page_desc);
|
||||
will_return(__wrap_write_page_desc, 0);
|
||||
|
||||
ret = write_upage(&map, &page, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_memory_equal(page, ret_page, sizeof page);
|
||||
}
|
||||
|
||||
static void test_page42(void **state)
|
||||
{
|
||||
struct ftl_map map;
|
||||
char page[4 * KIB], ret_page[4 * KIB];
|
||||
struct ftl_page_desc page_desc;
|
||||
int ret;
|
||||
|
||||
(void)state;
|
||||
|
||||
memset(page, 0x5a, sizeof page);
|
||||
memset(ret_page, 0, sizeof ret_page);
|
||||
|
||||
map.log2_page_size = ilog2(4 * KIB);
|
||||
map.head = 42;
|
||||
|
||||
will_return(__wrap_prepare_head, 0);
|
||||
|
||||
expect_value(__wrap_flash_write, addr, 42 * 4 * KIB);
|
||||
expect_value(__wrap_flash_write, len, 4 * KIB);
|
||||
will_return(__wrap_flash_write, 4 * KIB);
|
||||
will_return(__wrap_flash_write, &ret_page);
|
||||
|
||||
expect_value(__wrap_write_page_desc, map, &map);
|
||||
expect_value(__wrap_write_page_desc, page_desc, &page_desc);
|
||||
will_return(__wrap_write_page_desc, 0);
|
||||
|
||||
ret = write_upage(&map, &page, &page_desc);
|
||||
|
||||
assert_int_equal(ret, 0);
|
||||
assert_memory_equal(page, ret_page, sizeof page);
|
||||
}
|
||||
|
||||
int test_write_upage(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
{ "write_upage: prepare_head() = -1", test_prepare_head, NULL, NULL, NULL },
|
||||
{ "write_upage: null page", test_null_page, NULL, NULL, NULL },
|
||||
{ "write_upage: head=0", test_page0, NULL, NULL, NULL },
|
||||
{ "write_upage: head=42", test_page42, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests_name("write_upage", tests, NULL, NULL);
|
||||
}
|
23
source/tests/main.c
Normal file
23
source/tests/main.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <bitops.h>
|
||||
#include <flash.h>
|
||||
#include <ftl.h>
|
||||
#include <macros.h>
|
||||
|
||||
int test_ftl(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += test_ftl();
|
||||
|
||||
return count;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue