storage/stream: Add persistent write progress to stream_flash
Add additional API to stream_flash that can be used to make stream write progress persistent using the settings subsystem. This functionality makes it possible to resume a write operation after it was interrupted, e.g. by power loss. Signed-off-by: Jonathan Nilsen <Jonathan.Nilsen@nordicsemi.no>
This commit is contained in:
parent
be226ca55a
commit
0e6ac008a0
6 changed files with 376 additions and 1 deletions
|
@ -17,6 +17,15 @@ config STREAM_FLASH_ERASE
|
|||
If disabled an external actor must erase the flash area being written
|
||||
to.
|
||||
|
||||
config STREAM_FLASH_PROGRESS
|
||||
bool "Persistent stream write progress"
|
||||
depends on SETTINGS
|
||||
depends on !SETTINGS_NONE
|
||||
help
|
||||
Enable API for loading and storing the current write progress to flash
|
||||
using the settings subsystem. In case of power failure or device
|
||||
reset, the API can be used to resume writing from the latest state.
|
||||
|
||||
module = STREAM_FLASH
|
||||
module-str = stream flash
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
|
|
@ -16,6 +16,62 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_STREAM_FLASH_LOG_LEVEL);
|
|||
|
||||
#include <storage/stream_flash.h>
|
||||
|
||||
#ifdef CONFIG_STREAM_FLASH_PROGRESS
|
||||
#include <settings/settings.h>
|
||||
|
||||
static int settings_direct_loader(const char *key, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg,
|
||||
void *param)
|
||||
{
|
||||
struct stream_flash_ctx *ctx = (struct stream_flash_ctx *) param;
|
||||
|
||||
/* Handle the subtree if it is an exact key match. */
|
||||
if (settings_name_next(key, NULL) == 0) {
|
||||
size_t bytes_written = 0;
|
||||
ssize_t len = read_cb(cb_arg, &bytes_written,
|
||||
sizeof(bytes_written));
|
||||
|
||||
if (len != sizeof(ctx->bytes_written)) {
|
||||
LOG_ERR("Unable to read bytes_written from storage");
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Check that loaded progress is not outdated. */
|
||||
if (bytes_written >= ctx->bytes_written) {
|
||||
ctx->bytes_written = bytes_written;
|
||||
} else {
|
||||
LOG_WRN("Loaded outdated bytes_written %zu < %zu",
|
||||
bytes_written, ctx->bytes_written);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STREAM_FLASH_ERASE
|
||||
int rc;
|
||||
struct flash_pages_info page;
|
||||
off_t offset = (off_t) (ctx->offset + ctx->bytes_written) - 1;
|
||||
|
||||
/* Update the last erased page to avoid deleting already
|
||||
* written data.
|
||||
*/
|
||||
if (ctx->bytes_written > 0) {
|
||||
rc = flash_get_page_info_by_offs(ctx->fdev, offset,
|
||||
&page);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Error %d while getting page info", rc);
|
||||
return rc;
|
||||
}
|
||||
ctx->last_erased_page_start_offset = page.start_offset;
|
||||
} else {
|
||||
ctx->last_erased_page_start_offset = -1;
|
||||
}
|
||||
#endif /* CONFIG_STREAM_FLASH_ERASE */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STREAM_FLASH_PROGRESS */
|
||||
|
||||
#ifdef CONFIG_STREAM_FLASH_ERASE
|
||||
|
||||
int stream_flash_erase_page(struct stream_flash_ctx *ctx, off_t off)
|
||||
|
@ -201,6 +257,15 @@ int stream_flash_init(struct stream_flash_ctx *ctx, const struct device *fdev,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STREAM_FLASH_PROGRESS
|
||||
int rc = settings_subsys_init();
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Error %d initializing settings subsystem", rc);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct _inspect_flash inspect_flash_ctx = {
|
||||
.buf_len = buf_len,
|
||||
.total_size = 0
|
||||
|
@ -241,3 +306,62 @@ int stream_flash_init(struct stream_flash_ctx *ctx, const struct device *fdev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STREAM_FLASH_PROGRESS
|
||||
|
||||
int stream_flash_progress_load(struct stream_flash_ctx *ctx,
|
||||
const char *settings_key)
|
||||
{
|
||||
if (!ctx || !settings_key) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int rc = settings_load_subtree_direct(settings_key,
|
||||
settings_direct_loader,
|
||||
(void *) ctx);
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Error %d while loading progress for \"%s\"",
|
||||
rc, settings_key);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int stream_flash_progress_save(struct stream_flash_ctx *ctx,
|
||||
const char *settings_key)
|
||||
{
|
||||
if (!ctx || !settings_key) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int rc = settings_save_one(settings_key,
|
||||
&ctx->bytes_written,
|
||||
sizeof(ctx->bytes_written));
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Error %d while storing progress for \"%s\"",
|
||||
rc, settings_key);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int stream_flash_progress_clear(struct stream_flash_ctx *ctx,
|
||||
const char *settings_key)
|
||||
{
|
||||
if (!ctx || !settings_key) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int rc = settings_delete(settings_key);
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Error %d while deleting progress for \"%s\"",
|
||||
rc, settings_key);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STREAM_FLASH_PROGRESS */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue