From 99020ca016f5569a14ef7571384a0205f13522e8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 21 Mar 2017 13:57:51 +0100 Subject: state: Make pointing to the backend using a phandle the only supported method All other methods are broken for some time already: When starting the kernel the state code rewrites the state node in the device tree and replaced the "backend" property with a phandle - even when the target can't be described as a phandle. Since using phandles is the nicest way to point to the storage device anyway remove the other methods. Signed-off-by: Sascha Hauer --- .../devicetree/bindings/barebox/barebox,state.rst | 27 ++++++++++++++++------ common/state/state.c | 21 ++++++++--------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index 438cc434a2..e9daa65f1a 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -29,7 +29,8 @@ Required properties: * ``compatible``: should be ``barebox,state``; * ``magic``: A 32bit number used as a magic to identify the state -* ``backend``: describes where the data for this state is stored +* ``backend``: contains a phandle to the device/partition which holds the + actual state data. * ``backend-type``: should be ``raw`` or ``dtb``. Optional properties: @@ -77,19 +78,31 @@ Example:: magic = <0x27031977>; compatible = "barebox,state"; backend-type = "raw"; - backend = &eeprom, "partname:state"; + backend = &state_part; foo { - reg = <0x00 0x4>; - type = "uint32"; + reg = <0x00 0x4>; + type = "uint32"; default = <0x0>; }; bar { - reg = <0x10 0x4>; - type = "enum32"; + reg = <0x10 0x4>; + type = "enum32"; names = "baz", "qux"; - default = <1>; + default = <1>; + }; + }; + + &nand_flash { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + state_part: state@10000 { + label = "state"; + reg = <0x10000 0x10000>; + }; }; }; diff --git a/common/state/state.c b/common/state/state.c index 02bb1bb24a..6e6b3a6f08 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -452,19 +452,16 @@ struct state *state_new_from_node(struct device_node *node, char *path, } if (!path) { - /* guess if of_path is a path, not a phandle */ - if (of_path[0] == '/' && len > 1) { - ret = of_find_path(node, "backend", &path, 0); - } else { - struct device_node *partition_node; - - partition_node = of_parse_phandle(node, "backend", 0); - if (!partition_node) - goto out_release_state; - - of_path = partition_node->full_name; - ret = of_find_path_by_node(partition_node, &path, 0); + struct device_node *partition_node; + + partition_node = of_parse_phandle(node, "backend", 0); + if (!partition_node) { + dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n"); + goto out_release_state; } + + of_path = partition_node->full_name; + ret = of_find_path_by_node(partition_node, &path, 0); if (ret) { if (ret != -EPROBE_DEFER) dev_err(&state->dev, "state failed to parse path to backend: %s\n", -- cgit v1.2.3 From 38db53de7a9716e3fe2560c89afe2172b04e3d5e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 21 Mar 2017 15:45:23 +0100 Subject: state: Use positive logic bools with "non" in the names are rather confusing. Switch to positive logic. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 5dc8c50267..d7bd147441 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -249,7 +249,7 @@ const int desired_copies = 3; * @param storage Storage object * @param meminfo Info about the mtd device * @param path Path to the device - * @param non_circular Use non-circular mode to write data that is compatible with the old on-flash format + * @param circular If false, use non-circular mode to write data that is compatible with the old on-flash format * @param dev_offset Offset to start at in the device. * @param max_size Maximum size to use for data. May be 0 for infinite. * @return 0 on success, -errno otherwise @@ -262,7 +262,7 @@ const int desired_copies = 3; */ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, struct mtd_info_user *meminfo, - const char *path, bool non_circular, + const char *path, bool circular, off_t dev_offset, size_t max_size) { struct state_backend_storage_bucket *bucket; @@ -285,7 +285,7 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, unsigned int eraseblock = offset / meminfo->erasesize; bool lazy_init = true; - if (non_circular) + if (!circular) writesize = meminfo->erasesize; ret = state_backend_bucket_circular_create(storage->dev, path, @@ -483,16 +483,16 @@ int state_storage_init(struct state_backend_storage *storage, ret = mtd_get_meminfo(path, &meminfo); if (!ret && !(meminfo.flags & MTD_NO_ERASE)) { - bool non_circular = false; + bool circular = true; if (!storagetype) { - non_circular = true; + circular = false; } else if (strcmp(storagetype, "circular")) { dev_warn(storage->dev, "Unknown storagetype '%s', falling back to old format circular storage type.\n", storagetype); - non_circular = true; + circular = false; } return state_storage_mtd_buckets_init(storage, &meminfo, path, - non_circular, offset, + circular, offset, max_size); } else { return state_storage_file_buckets_init(storage, path, offset, -- cgit v1.2.3 From 33fa52317e6343183501a5b81907ca79081fee59 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 15:08:12 +0100 Subject: state: backend: remove .get_packed_len .get_packed_len isn't implemented by any backend, so remove the hook and its potential caller. Signed-off-by: Sascha Hauer --- common/state/backend.c | 3 --- common/state/state.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/common/state/backend.c b/common/state/backend.c index 5235bb0283..6b06c845f0 100644 --- a/common/state/backend.c +++ b/common/state/backend.c @@ -74,9 +74,6 @@ int state_load(struct state *state) int ret; struct state_backend *backend = &state->backend; - if (backend->format->get_packed_len) - len_hint = backend->format->get_packed_len(backend->format, - state); ret = state_storage_read(&backend->storage, backend->format, state->magic, &buf, &len, len_hint); if (ret) { diff --git a/common/state/state.h b/common/state/state.h index bc6917de61..0197cb839a 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -53,8 +53,6 @@ struct state_backend_format { uint8_t ** buf, ssize_t * len); int (*unpack) (struct state_backend_format * format, struct state * state, const uint8_t * buf, ssize_t len); - ssize_t(*get_packed_len) (struct state_backend_format * format, - struct state * state); void (*free) (struct state_backend_format * format); const char *name; }; -- cgit v1.2.3 From eeae145d9b06ff76ab72e804836b895eb0a01489 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 15:13:29 +0100 Subject: state: backend: remove len_hint argument from state_storage_read The argument is 0 in the only caller, so remove the argument. Signed-off-by: Sascha Hauer --- common/state/backend.c | 3 +-- common/state/backend_storage.c | 5 ++--- common/state/state.h | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/common/state/backend.c b/common/state/backend.c index 6b06c845f0..803390e2aa 100644 --- a/common/state/backend.c +++ b/common/state/backend.c @@ -70,12 +70,11 @@ int state_load(struct state *state) { uint8_t *buf; ssize_t len; - ssize_t len_hint = 0; int ret; struct state_backend *backend = &state->backend; ret = state_storage_read(&backend->storage, backend->format, - state->magic, &buf, &len, len_hint); + state->magic, &buf, &len); if (ret) { dev_err(&state->dev, "Failed to read state with format %s, %d\n", backend->format->name, ret); diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index d7bd147441..5481f27df9 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -129,14 +129,13 @@ int state_storage_restore_consistency(struct state_backend_storage *storage, */ int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, uint8_t ** buf, ssize_t * len, - ssize_t len_hint) + uint32_t magic, uint8_t ** buf, ssize_t * len) { struct state_backend_storage_bucket *bucket; int ret; list_for_each_entry(bucket, &storage->buckets, bucket_list) { - *len = len_hint; + *len = 0; ret = bucket_lazy_init(bucket); if (ret) { dev_warn(storage->dev, "Failed to init bucket/read state backend bucket, %d\n", diff --git a/common/state/state.h b/common/state/state.h index 0197cb839a..ddf45239eb 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -234,8 +234,7 @@ int state_storage_restore_consistency(struct state_backend_storage ssize_t len); int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, uint8_t **buf, ssize_t *len, - ssize_t len_hint); + uint32_t magic, uint8_t **buf, ssize_t *len); static inline struct state_uint32 *to_state_uint32(struct state_variable *s) { -- cgit v1.2.3 From 4b63113212a8f5e096f246a349b8f8b8a7c52825 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 12:14:26 +0100 Subject: state: Drop backend as extra struct type struct state_backend is embedded into struct state. This additional indirection does not have any real gain. Drop it. Signed-off-by: Sascha Hauer --- common/state/backend.c | 48 +++++++++++++++++++++++------------------------- common/state/state.c | 34 +++++++++++++++++----------------- common/state/state.h | 23 ++++++----------------- 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/common/state/backend.c b/common/state/backend.c index 803390e2aa..1773392e8d 100644 --- a/common/state/backend.c +++ b/common/state/backend.c @@ -31,19 +31,18 @@ int state_save(struct state *state) uint8_t *buf; ssize_t len; int ret; - struct state_backend *backend = &state->backend; if (!state->dirty) return 0; - ret = backend->format->pack(backend->format, state, &buf, &len); + ret = state->format->pack(state->format, state, &buf, &len); if (ret) { dev_err(&state->dev, "Failed to pack state with backend format %s, %d\n", - backend->format->name, ret); + state->format->name, ret); return ret; } - ret = state_storage_write(&backend->storage, buf, len); + ret = state_storage_write(&state->storage, buf, len); if (ret) { dev_err(&state->dev, "Failed to write packed state, %d\n", ret); goto out; @@ -71,20 +70,19 @@ int state_load(struct state *state) uint8_t *buf; ssize_t len; int ret; - struct state_backend *backend = &state->backend; - ret = state_storage_read(&backend->storage, backend->format, + ret = state_storage_read(&state->storage, state->format, state->magic, &buf, &len); if (ret) { dev_err(&state->dev, "Failed to read state with format %s, %d\n", - backend->format->name, ret); + state->format->name, ret); return ret; } - ret = backend->format->unpack(backend->format, state, buf, len); + ret = state->format->unpack(state->format, state, buf, len); if (ret) { dev_err(&state->dev, "Failed to unpack read data with format %s although verified, %d\n", - backend->format->name, ret); + state->format->name, ret); goto out; } @@ -95,17 +93,17 @@ out: return ret; } -static int state_format_init(struct state_backend *backend, +static int state_format_init(struct state *state, struct device_d *dev, const char *backend_format, struct device_node *node, const char *state_name) { int ret; if (!strcmp(backend_format, "raw")) { - ret = backend_format_raw_create(&backend->format, node, + ret = backend_format_raw_create(&state->format, node, state_name, dev); } else if (!strcmp(backend_format, "dtb")) { - ret = backend_format_dtb_create(&backend->format, dev); + ret = backend_format_dtb_create(&state->format, dev); } else { dev_err(dev, "Invalid backend format %s\n", backend_format); @@ -143,7 +141,7 @@ static void state_format_free(struct state_backend_format *format) * autoselect some backwardscompatible backend options * @return 0 on success, -errno otherwise */ -int state_backend_init(struct state_backend *backend, struct device_d *dev, +int state_backend_init(struct state *state, struct device_d *dev, struct device_node *node, const char *backend_format, const char *storage_path, const char *state_name, const char *of_path, off_t offset, size_t max_size, @@ -151,35 +149,35 @@ int state_backend_init(struct state_backend *backend, struct device_d *dev, { int ret; - ret = state_format_init(backend, dev, backend_format, node, state_name); + ret = state_format_init(state, dev, backend_format, node, state_name); if (ret) return ret; - ret = state_storage_init(&backend->storage, dev, storage_path, offset, + ret = state_storage_init(&state->storage, dev, storage_path, offset, max_size, stridesize, storagetype); if (ret) goto out_free_format; - backend->of_path = xstrdup(of_path); + state->of_backend_path = xstrdup(of_path); return 0; out_free_format: - state_format_free(backend->format); - backend->format = NULL; + state_format_free(state->format); + state->format = NULL; return ret; } -void state_backend_set_readonly(struct state_backend *backend) +void state_backend_set_readonly(struct state *state) { - state_storage_set_readonly(&backend->storage); + state_storage_set_readonly(&state->storage); } -void state_backend_free(struct state_backend *backend) +void state_backend_free(struct state *state) { - state_storage_free(&backend->storage); - if (backend->format) - state_format_free(backend->format); - free(backend->of_path); + state_storage_free(&state->storage); + if (state->format) + state_format_free(state->format); + free(state->of_path); } diff --git a/common/state/state.c b/common/state/state.c index 6e6b3a6f08..62357fb248 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -328,21 +328,21 @@ static int of_state_fixup(struct device_node *root, void *ctx) } /* backend-type */ - if (!state->backend.format) { + if (!state->format) { ret = -ENODEV; goto out; } p = of_new_property(new_node, "backend-type", - state->backend.format->name, - strlen(state->backend.format->name) + 1); + state->format->name, + strlen(state->format->name) + 1); if (!p) { ret = -ENOMEM; goto out; } /* backend phandle */ - backend_node = of_find_node_by_path_from(root, state->backend.of_path); + backend_node = of_find_node_by_path_from(root, state->of_backend_path); if (!backend_node) { ret = -ENODEV; goto out; @@ -353,9 +353,9 @@ static int of_state_fixup(struct device_node *root, void *ctx) if (ret) goto out; - if (!strcmp("raw", state->backend.format->name)) { + if (!strcmp("raw", state->format->name)) { struct digest *digest = - state_backend_format_raw_get_digest(state->backend.format); + state_backend_format_raw_get_digest(state->format); if (digest) { p = of_new_property(new_node, "algo", digest_name(digest), @@ -367,19 +367,19 @@ static int of_state_fixup(struct device_node *root, void *ctx) } } - if (state->backend.storage.name) { + if (state->storage.name) { p = of_new_property(new_node, "backend-storage-type", - state->backend.storage.name, - strlen(state->backend.storage.name) + 1); + state->storage.name, + strlen(state->storage.name) + 1); if (!p) { ret = -ENOMEM; goto out; } } - if (state->backend.storage.stridesize) { + if (state->storage.stridesize) { ret = of_property_write_u32(new_node, "backend-stridesize", - state->backend.storage.stridesize); + state->storage.stridesize); if (ret) goto out; } @@ -408,7 +408,7 @@ void state_release(struct state *state) of_unregister_fixup(of_state_fixup, state); list_del(&state->list); unregister_device(&state->dev); - state_backend_free(&state->backend); + state_backend_free(state); free(state->of_path); free(state); } @@ -487,14 +487,14 @@ struct state *state_new_from_node(struct device_node *node, char *path, dev_info(&state->dev, "No backend-storage-type found, using default.\n"); } - ret = state_backend_init(&state->backend, &state->dev, node, + ret = state_backend_init(state, &state->dev, node, backend_type, path, alias, of_path, offset, max_size, stridesize, storage_type); if (ret) goto out_release_state; if (readonly) - state_backend_set_readonly(&state->backend); + state_backend_set_readonly(state); ret = state_from_node(state, node, 1); if (ret) { @@ -569,10 +569,10 @@ void state_info(void) list_for_each_entry(state, &state_list, list) { printf("%-20s ", state->name); - if (state->backend.format) + if (state->format) printf("(backend: %s, path: %s)\n", - state->backend.format->name, - state->backend.of_path); + state->format->name, + state->of_backend_path); else printf("(no backend)\n"); } diff --git a/common/state/state.h b/common/state/state.h index ddf45239eb..cb248fc609 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -75,19 +75,6 @@ struct state_backend_storage { bool readonly; }; -/** - * state_backend - State Backend object - * - * @format Backend format object - * @storage Backend storage object - * @of_path Path to the DT node - */ -struct state_backend { - struct state_backend_format *format; - struct state_backend_storage storage; - char *of_path; -}; - struct state { struct list_head list; /* Entry to enqueue on list of states */ @@ -100,7 +87,9 @@ struct state { unsigned int dirty; unsigned int save_on_shutdown; - struct state_backend backend; + struct state_backend_format *format; + struct state_backend_storage storage; + char *of_backend_path; }; enum state_convert { @@ -216,13 +205,13 @@ int state_backend_bucket_cached_create(struct device_d *dev, struct state_variable *state_find_var(struct state *state, const char *name); struct digest *state_backend_format_raw_get_digest(struct state_backend_format *format); -int state_backend_init(struct state_backend *backend, struct device_d *dev, +int state_backend_init(struct state *state, struct device_d *dev, struct device_node *node, const char *backend_format, const char *storage_path, const char *state_name, const char *of_path, off_t offset, size_t max_size, uint32_t stridesize, const char *storagetype); -void state_backend_set_readonly(struct state_backend *backend); -void state_backend_free(struct state_backend *backend); +void state_backend_set_readonly(struct state *state); +void state_backend_free(struct state *state); void state_storage_free(struct state_backend_storage *storage); int state_backend_bucket_direct_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket **bucket, -- cgit v1.2.3 From 6fea1f90af44f3a1756bdcecaad7c2380590f4cc Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 12:16:55 +0100 Subject: state: merge backend.c into state.c The code in backend.c is too small to justify an extra file. Merge it into state.c. Signed-off-by: Sascha Hauer --- common/state/Makefile | 1 - common/state/backend.c | 183 ------------------------------------------------- common/state/state.c | 161 +++++++++++++++++++++++++++++++++++++++++++ common/state/state.h | 6 -- 4 files changed, 161 insertions(+), 190 deletions(-) delete mode 100644 common/state/backend.c diff --git a/common/state/Makefile b/common/state/Makefile index 3e0e2c6e55..d3518feab4 100644 --- a/common/state/Makefile +++ b/common/state/Makefile @@ -1,6 +1,5 @@ obj-y += state.o obj-y += state_variables.o -obj-y += backend.o obj-y += backend_format_dtb.o obj-y += backend_format_raw.o obj-y += backend_storage.o diff --git a/common/state/backend.c b/common/state/backend.c deleted file mode 100644 index 1773392e8d..0000000000 --- a/common/state/backend.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2016 Pengutronix, Markus Pargmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include - -#include "state.h" - - -/** - * Save the state - * @param state - * @return - */ -int state_save(struct state *state) -{ - uint8_t *buf; - ssize_t len; - int ret; - - if (!state->dirty) - return 0; - - ret = state->format->pack(state->format, state, &buf, &len); - if (ret) { - dev_err(&state->dev, "Failed to pack state with backend format %s, %d\n", - state->format->name, ret); - return ret; - } - - ret = state_storage_write(&state->storage, buf, len); - if (ret) { - dev_err(&state->dev, "Failed to write packed state, %d\n", ret); - goto out; - } - - state->dirty = 0; - -out: - free(buf); - return ret; -} - -/** - * state_load - Loads a state from the backend - * @param state The state that should be updated to contain the loaded data - * @return 0 on success, -errno on failure. If no state is loaded the previous - * values remain in the state. - * - * This function uses the registered storage backend to read data. All data that - * we read is checked for integrity by the formatter. After that we unpack the - * data into our state. - */ -int state_load(struct state *state) -{ - uint8_t *buf; - ssize_t len; - int ret; - - ret = state_storage_read(&state->storage, state->format, - state->magic, &buf, &len); - if (ret) { - dev_err(&state->dev, "Failed to read state with format %s, %d\n", - state->format->name, ret); - return ret; - } - - ret = state->format->unpack(state->format, state, buf, len); - if (ret) { - dev_err(&state->dev, "Failed to unpack read data with format %s although verified, %d\n", - state->format->name, ret); - goto out; - } - - state->dirty = 0; - -out: - free(buf); - return ret; -} - -static int state_format_init(struct state *state, - struct device_d *dev, const char *backend_format, - struct device_node *node, const char *state_name) -{ - int ret; - - if (!strcmp(backend_format, "raw")) { - ret = backend_format_raw_create(&state->format, node, - state_name, dev); - } else if (!strcmp(backend_format, "dtb")) { - ret = backend_format_dtb_create(&state->format, dev); - } else { - dev_err(dev, "Invalid backend format %s\n", - backend_format); - return -EINVAL; - } - - if (ret && ret != -EPROBE_DEFER) - dev_err(dev, "Failed to initialize format %s, %d\n", - backend_format, ret); - - return ret; -} - -static void state_format_free(struct state_backend_format *format) -{ - if (format->free) - format->free(format); -} - -/** - * state_backend_init - Initiates the backend storage and format using the - * passed arguments - * @param backend state backend - * @param dev Device pointer used for prints - * @param node the DT device node corresponding to the state - * @param backend_format a string describing the format. Valid values are 'raw' - * and 'dtb' currently - * @param storage_path Path to the backend storage file/device/partition/... - * @param state_name Name of the state - * @param of_path Path in the devicetree - * @param stridesize stridesize in case we have a medium without eraseblocks. - * stridesize describes how far apart copies of the same data should be stored. - * For blockdevices it makes sense to align them on blocksize. - * @param storagetype Type of the storage backend. This may be NULL where we - * autoselect some backwardscompatible backend options - * @return 0 on success, -errno otherwise - */ -int state_backend_init(struct state *state, struct device_d *dev, - struct device_node *node, const char *backend_format, - const char *storage_path, const char *state_name, const - char *of_path, off_t offset, size_t max_size, - uint32_t stridesize, const char *storagetype) -{ - int ret; - - ret = state_format_init(state, dev, backend_format, node, state_name); - if (ret) - return ret; - - ret = state_storage_init(&state->storage, dev, storage_path, offset, - max_size, stridesize, storagetype); - if (ret) - goto out_free_format; - - state->of_backend_path = xstrdup(of_path); - - return 0; - -out_free_format: - state_format_free(state->format); - state->format = NULL; - - return ret; -} - -void state_backend_set_readonly(struct state *state) -{ - state_storage_set_readonly(&state->storage); -} - -void state_backend_free(struct state *state) -{ - state_storage_free(&state->storage); - if (state->format) - state_format_free(state->format); - free(state->of_path); -} diff --git a/common/state/state.c b/common/state/state.c index 62357fb248..570fa498c5 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -34,6 +34,167 @@ /* list of all registered state instances */ static LIST_HEAD(state_list); +/** + * Save the state + * @param state + * @return + */ +int state_save(struct state *state) +{ + uint8_t *buf; + ssize_t len; + int ret; + + if (!state->dirty) + return 0; + + ret = state->format->pack(state->format, state, &buf, &len); + if (ret) { + dev_err(&state->dev, "Failed to pack state with backend format %s, %d\n", + state->format->name, ret); + return ret; + } + + ret = state_storage_write(&state->storage, buf, len); + if (ret) { + dev_err(&state->dev, "Failed to write packed state, %d\n", ret); + goto out; + } + + state->dirty = 0; + +out: + free(buf); + return ret; +} + +/** + * state_load - Loads a state from the backend + * @param state The state that should be updated to contain the loaded data + * @return 0 on success, -errno on failure. If no state is loaded the previous + * values remain in the state. + * + * This function uses the registered storage backend to read data. All data that + * we read is checked for integrity by the formatter. After that we unpack the + * data into our state. + */ +int state_load(struct state *state) +{ + uint8_t *buf; + ssize_t len; + int ret; + + ret = state_storage_read(&state->storage, state->format, + state->magic, &buf, &len); + if (ret) { + dev_err(&state->dev, "Failed to read state with format %s, %d\n", + state->format->name, ret); + return ret; + } + + ret = state->format->unpack(state->format, state, buf, len); + if (ret) { + dev_err(&state->dev, "Failed to unpack read data with format %s although verified, %d\n", + state->format->name, ret); + goto out; + } + + state->dirty = 0; + +out: + free(buf); + return ret; +} + +static int state_format_init(struct state *state, + struct device_d *dev, const char *backend_format, + struct device_node *node, const char *state_name) +{ + int ret; + + if (!backend_format || !strcmp(backend_format, "raw")) { + ret = backend_format_raw_create(&state->format, node, + state_name, dev); + } else if (!strcmp(backend_format, "dtb")) { + ret = backend_format_dtb_create(&state->format, dev); + } else { + dev_err(dev, "Invalid backend format %s\n", + backend_format); + return -EINVAL; + } + + if (ret && ret != -EPROBE_DEFER) + dev_err(dev, "Failed to initialize format %s, %d\n", + backend_format, ret); + + return ret; +} + +static void state_format_free(struct state_backend_format *format) +{ + if (format->free) + format->free(format); +} + +/** + * state_backend_init - Initiates the backend storage and format using the + * passed arguments + * @param backend state backend + * @param dev Device pointer used for prints + * @param node the DT device node corresponding to the state + * @param backend_format a string describing the format. Valid values are 'raw' + * and 'dtb' currently + * @param storage_path Path to the backend storage file/device/partition/... + * @param state_name Name of the state + * @param of_path Path in the devicetree + * @param stridesize stridesize in case we have a medium without eraseblocks. + * stridesize describes how far apart copies of the same data should be stored. + * For blockdevices it makes sense to align them on blocksize. + * @param storagetype Type of the storage backend. This may be NULL where we + * autoselect some backwardscompatible backend options + * @return 0 on success, -errno otherwise + */ +static int state_backend_init(struct state *state, struct device_d *dev, + struct device_node *node, const char *backend_format, + const char *storage_path, const char *state_name, const + char *of_path, off_t offset, size_t max_size, + uint32_t stridesize, const char *storagetype) +{ + int ret; + + ret = state_format_init(state, dev, backend_format, node, state_name); + if (ret) + return ret; + + ret = state_storage_init(&state->storage, dev, storage_path, offset, + max_size, stridesize, storagetype); + if (ret) + goto out_free_format; + + state->of_backend_path = xstrdup(of_path); + + return 0; + +out_free_format: + state_format_free(state->format); + state->format = NULL; + + return ret; +} + +void state_backend_set_readonly(struct state *state) +{ + state_storage_set_readonly(&state->storage); +} + +void state_backend_free(struct state *state) +{ + state_storage_free(&state->storage); + if (state->format) + state_format_free(state->format); + free(state->of_path); +} + static struct state *state_new(const char *name) { struct state *state; diff --git a/common/state/state.h b/common/state/state.h index cb248fc609..254ff31a06 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -205,13 +205,7 @@ int state_backend_bucket_cached_create(struct device_d *dev, struct state_variable *state_find_var(struct state *state, const char *name); struct digest *state_backend_format_raw_get_digest(struct state_backend_format *format); -int state_backend_init(struct state *state, struct device_d *dev, - struct device_node *node, const char *backend_format, - const char *storage_path, const char *state_name, const - char *of_path, off_t offset, size_t max_size, - uint32_t stridesize, const char *storagetype); void state_backend_set_readonly(struct state *state); -void state_backend_free(struct state *state); void state_storage_free(struct state_backend_storage *storage); int state_backend_bucket_direct_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket **bucket, -- cgit v1.2.3 From 04f51d6a8c28b43516366a9e8f56d1c464d153c0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 12:27:11 +0100 Subject: state: open code state_backend_init in caller Safes a lot of argument passing to a function that is used only once. Signed-off-by: Sascha Hauer --- common/state/state.c | 70 ++++++++++------------------------------------------ 1 file changed, 13 insertions(+), 57 deletions(-) diff --git a/common/state/state.c b/common/state/state.c index 570fa498c5..fce8fcc943 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -132,69 +132,18 @@ static int state_format_init(struct state *state, static void state_format_free(struct state_backend_format *format) { + if (!format) + return; + if (format->free) format->free(format); } -/** - * state_backend_init - Initiates the backend storage and format using the - * passed arguments - * @param backend state backend - * @param dev Device pointer used for prints - * @param node the DT device node corresponding to the state - * @param backend_format a string describing the format. Valid values are 'raw' - * and 'dtb' currently - * @param storage_path Path to the backend storage file/device/partition/... - * @param state_name Name of the state - * @param of_path Path in the devicetree - * @param stridesize stridesize in case we have a medium without eraseblocks. - * stridesize describes how far apart copies of the same data should be stored. - * For blockdevices it makes sense to align them on blocksize. - * @param storagetype Type of the storage backend. This may be NULL where we - * autoselect some backwardscompatible backend options - * @return 0 on success, -errno otherwise - */ -static int state_backend_init(struct state *state, struct device_d *dev, - struct device_node *node, const char *backend_format, - const char *storage_path, const char *state_name, const - char *of_path, off_t offset, size_t max_size, - uint32_t stridesize, const char *storagetype) -{ - int ret; - - ret = state_format_init(state, dev, backend_format, node, state_name); - if (ret) - return ret; - - ret = state_storage_init(&state->storage, dev, storage_path, offset, - max_size, stridesize, storagetype); - if (ret) - goto out_free_format; - - state->of_backend_path = xstrdup(of_path); - - return 0; - -out_free_format: - state_format_free(state->format); - state->format = NULL; - - return ret; -} - void state_backend_set_readonly(struct state *state) { state_storage_set_readonly(&state->storage); } -void state_backend_free(struct state *state) -{ - state_storage_free(&state->storage); - if (state->format) - state_format_free(state->format); - free(state->of_path); -} - static struct state *state_new(const char *name) { struct state *state; @@ -569,7 +518,9 @@ void state_release(struct state *state) of_unregister_fixup(of_state_fixup, state); list_del(&state->list); unregister_device(&state->dev); - state_backend_free(state); + state_storage_free(&state->storage); + state_format_free(state->format); + free(state->of_backend_path); free(state->of_path); free(state); } @@ -648,12 +599,17 @@ struct state *state_new_from_node(struct device_node *node, char *path, dev_info(&state->dev, "No backend-storage-type found, using default.\n"); } - ret = state_backend_init(state, &state->dev, node, - backend_type, path, alias, of_path, offset, + ret = state_format_init(state, &state->dev, backend_type, node, alias); + if (ret) + goto out_release_state; + + ret = state_storage_init(&state->storage, &state->dev, path, offset, max_size, stridesize, storage_type); if (ret) goto out_release_state; + state->of_backend_path = xstrdup(of_path); + if (readonly) state_backend_set_readonly(state); -- cgit v1.2.3 From 4b7957533e1d9d2bc690b87456ad803d52cef33b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 12:28:57 +0100 Subject: state: remove unnecessary argument from state_format_init The device pointer is already in struct state, no need to pass it around when a struct state * is already passed. Signed-off-by: Sascha Hauer --- common/state/state.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/common/state/state.c b/common/state/state.c index fce8fcc943..87b704feba 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -106,25 +106,24 @@ out: return ret; } -static int state_format_init(struct state *state, - struct device_d *dev, const char *backend_format, +static int state_format_init(struct state *state, const char *backend_format, struct device_node *node, const char *state_name) { int ret; if (!backend_format || !strcmp(backend_format, "raw")) { ret = backend_format_raw_create(&state->format, node, - state_name, dev); + state_name, &state->dev); } else if (!strcmp(backend_format, "dtb")) { - ret = backend_format_dtb_create(&state->format, dev); + ret = backend_format_dtb_create(&state->format, &state->dev); } else { - dev_err(dev, "Invalid backend format %s\n", + dev_err(&state->dev, "Invalid backend format %s\n", backend_format); return -EINVAL; } if (ret && ret != -EPROBE_DEFER) - dev_err(dev, "Failed to initialize format %s, %d\n", + dev_err(&state->dev, "Failed to initialize format %s, %d\n", backend_format, ret); return ret; @@ -599,7 +598,7 @@ struct state *state_new_from_node(struct device_node *node, char *path, dev_info(&state->dev, "No backend-storage-type found, using default.\n"); } - ret = state_format_init(state, &state->dev, backend_type, node, alias); + ret = state_format_init(state, backend_type, node, alias); if (ret) goto out_release_state; -- cgit v1.2.3 From 8b5b42537ab59b78d24dca35cb010f93ca71deb2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 12:36:40 +0100 Subject: state: pass struct state * to storage functions We can get a state_backend_storage * and the device * from struct state, so pass this to the storage functions rather than the two pointers. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 7 +++---- common/state/state.c | 2 +- common/state/state.h | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 5481f27df9..e1869830bd 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -454,7 +454,6 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage /** * state_storage_init - Init backend storage - * @param storage Storage object * @param path Path to the backend storage file * @param dev_offset Offset in the device to start writing at. * @param max_size Maximum size of the data. May be 0 for infinite. @@ -465,16 +464,16 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage * * Depending on the filetype, we create mtd buckets or normal file buckets. */ -int state_storage_init(struct state_backend_storage *storage, - struct device_d *dev, const char *path, +int state_storage_init(struct state *state, const char *path, off_t offset, size_t max_size, uint32_t stridesize, const char *storagetype) { + struct state_backend_storage *storage = &state->storage; int ret = -ENODEV; struct mtd_info_user meminfo; INIT_LIST_HEAD(&storage->buckets); - storage->dev = dev; + storage->dev = &state->dev; storage->name = storagetype; storage->stridesize = stridesize; diff --git a/common/state/state.c b/common/state/state.c index 87b704feba..8d2dca2523 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -602,7 +602,7 @@ struct state *state_new_from_node(struct device_node *node, char *path, if (ret) goto out_release_state; - ret = state_storage_init(&state->storage, &state->dev, path, offset, + ret = state_storage_init(state, path, offset, max_size, stridesize, storage_type); if (ret) goto out_release_state; diff --git a/common/state/state.h b/common/state/state.h index 254ff31a06..4ef46693c6 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -186,8 +186,7 @@ int backend_format_raw_create(struct state_backend_format **format, struct device_d *dev); int backend_format_dtb_create(struct state_backend_format **format, struct device_d *dev); -int state_storage_init(struct state_backend_storage *storage, - struct device_d *dev, const char *path, +int state_storage_init(struct state *state, const char *path, off_t offset, size_t max_size, uint32_t stridesize, const char *storagetype); void state_storage_set_readonly(struct state_backend_storage *storage); -- cgit v1.2.3 From cfea782fdd43943c92e7a911d57bcfbfc57a541a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 13:03:08 +0100 Subject: state: storage: initialize variable once outside loop writesize is initialized with the same value in each loop iteration, Instead, initialize it once outside the loop. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index e1869830bd..0808c5c0b4 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -268,6 +268,7 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, ssize_t end = dev_offset + max_size; int nr_copies = 0; off_t offset; + ssize_t writesize; if (!end || end > meminfo->size) end = meminfo->size; @@ -278,15 +279,16 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, return -EINVAL; } + if (circular) + writesize = meminfo->writesize; + else + writesize = meminfo->erasesize; + for (offset = dev_offset; offset < end; offset += meminfo->erasesize) { int ret; - ssize_t writesize = meminfo->writesize; unsigned int eraseblock = offset / meminfo->erasesize; bool lazy_init = true; - if (!circular) - writesize = meminfo->erasesize; - ret = state_backend_bucket_circular_create(storage->dev, path, &bucket, eraseblock, -- cgit v1.2.3 From 7599f6e56a2480df2831a47de4d62687b57c5249 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 16:11:17 +0100 Subject: state: backend_circular: Read whole PEB When the circular backend searches for the last page written in the eraseblock, it iterates backwards pagewise from the end of the block. This is ok for NAND flash, but on NOR flash, which does not have pages, the code ends up iterating bytewise backwards, calling into mtd each time. This is very time consuming, so optimize this by reading the whole eraseblock once and just iterate over the buffer in memory. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 0bce900d0d..53c2aae803 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -379,26 +379,24 @@ static int state_backend_bucket_circular_init( int sub_offset; uint32_t written_length = 0; uint8_t *buf; + int ret; - buf = xmalloc(circ->writesize); + buf = xmalloc(circ->max_size); if (!buf) return -ENOMEM; + ret = state_mtd_peb_read(circ, buf, 0, circ->max_size); + if (ret && ret != -EUCLEAN) + return ret; + for (sub_offset = circ->max_size - circ->writesize; sub_offset >= 0; sub_offset -= circ->writesize) { - int ret; - - ret = state_mtd_peb_read(circ, buf, sub_offset, - circ->writesize); - if (ret && ret != -EUCLEAN) - return ret; - - ret = mtd_buf_all_ff(buf, circ->writesize); + ret = mtd_buf_all_ff(buf + sub_offset, circ->writesize); if (!ret) { struct state_backend_storage_bucket_circular_meta *meta; meta = (struct state_backend_storage_bucket_circular_meta *) - (buf + circ->writesize - sizeof(*meta)); + (buf + sub_offset + circ->writesize - sizeof(*meta)); if (meta->magic != circular_magic) written_length = 0; -- cgit v1.2.3 From ad1d6953590fdcf350dd3c9eda4fd551a1f9dac3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 22 Mar 2017 16:16:26 +0100 Subject: state: drop lazy_init lazy_init is an optimization that makes it possible to read only up to the first valid bucket when starting. However, when restoring consistency, immediately afterwards we have we have to initialize all buckets anyway, so being lazy doesn't give us any gain. Remove it to simplify the code. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_cached.c | 14 -------------- common/state/backend_bucket_circular.c | 13 ++++--------- common/state/backend_storage.c | 34 +--------------------------------- common/state/state.h | 5 +---- 4 files changed, 6 insertions(+), 60 deletions(-) diff --git a/common/state/backend_bucket_cached.c b/common/state/backend_bucket_cached.c index ba0af7f373..5e7f44c8f8 100644 --- a/common/state/backend_bucket_cached.c +++ b/common/state/backend_bucket_cached.c @@ -110,19 +110,6 @@ static int state_backend_bucket_cache_write(struct state_backend_storage_bucket return 0; } -static int state_backend_bucket_cache_init( - struct state_backend_storage_bucket *bucket) -{ - struct state_backend_storage_bucket_cache *cache = - get_bucket_cache(bucket); - - if (cache->raw->init) { - return cache->raw->init(cache->raw); - } - - return 0; -} - static void state_backend_bucket_cache_free( struct state_backend_storage_bucket *bucket) { @@ -147,7 +134,6 @@ int state_backend_bucket_cached_create(struct device_d *dev, cache->bucket.free = state_backend_bucket_cache_free; cache->bucket.read = state_backend_bucket_cache_read; cache->bucket.write = state_backend_bucket_cache_write; - cache->bucket.init = state_backend_bucket_cache_init; *out = &cache->bucket; diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 53c2aae803..8eae86694a 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -456,8 +456,7 @@ int state_backend_bucket_circular_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket **bucket, unsigned int eraseblock, ssize_t writesize, - struct mtd_info_user *mtd_uinfo, - bool lazy_init) + struct mtd_info_user *mtd_uinfo) { struct state_backend_storage_bucket_circular *circ; int ret; @@ -493,13 +492,9 @@ int state_backend_bucket_circular_create(struct device_d *dev, const char *path, circ->bucket.free = state_backend_bucket_circular_free; *bucket = &circ->bucket; - if (!lazy_init) { - ret = state_backend_bucket_circular_init(*bucket); - if (ret) - goto out_free; - } else { - circ->bucket.init = state_backend_bucket_circular_init; - } + ret = state_backend_bucket_circular_init(*bucket); + if (ret) + goto out_free; return 0; diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 0808c5c0b4..04d9d8f0a7 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -27,23 +27,6 @@ const unsigned int min_copies_written = 1; -static int bucket_lazy_init(struct state_backend_storage_bucket *bucket) -{ - int ret; - - if (bucket->initialized) - return 0; - - if (bucket->init) { - ret = bucket->init(bucket); - if (ret) - return ret; - } - bucket->initialized = true; - - return 0; -} - /** * state_storage_write - Writes the given data to the storage * @param storage Storage object @@ -69,13 +52,6 @@ int state_storage_write(struct state_backend_storage *storage, return 0; list_for_each_entry(bucket, &storage->buckets, bucket_list) { - ret = bucket_lazy_init(bucket); - if (ret) { - dev_warn(storage->dev, "Failed to init bucket/write state backend bucket, %d\n", - ret); - continue; - } - ret = bucket->write(bucket, buf, len); if (ret) { dev_warn(storage->dev, "Failed to write state backend bucket, %d\n", @@ -136,12 +112,6 @@ int state_storage_read(struct state_backend_storage *storage, list_for_each_entry(bucket, &storage->buckets, bucket_list) { *len = 0; - ret = bucket_lazy_init(bucket); - if (ret) { - dev_warn(storage->dev, "Failed to init bucket/read state backend bucket, %d\n", - ret); - continue; - } ret = bucket->read(bucket, buf, len); if (ret) { @@ -287,14 +257,12 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, for (offset = dev_offset; offset < end; offset += meminfo->erasesize) { int ret; unsigned int eraseblock = offset / meminfo->erasesize; - bool lazy_init = true; ret = state_backend_bucket_circular_create(storage->dev, path, &bucket, eraseblock, writesize, - meminfo, - lazy_init); + meminfo); if (ret) { dev_warn(storage->dev, "Failed to create bucket at '%s' eraseblock %u\n", path, eraseblock); diff --git a/common/state/state.h b/common/state/state.h index 4ef46693c6..6f5de31dff 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -20,14 +20,12 @@ struct mtd_info_user; * @bucket_list A list element struct to attach this bucket to a list */ struct state_backend_storage_bucket { - int (*init) (struct state_backend_storage_bucket * bucket); int (*write) (struct state_backend_storage_bucket * bucket, const uint8_t * buf, ssize_t len); int (*read) (struct state_backend_storage_bucket * bucket, uint8_t ** buf, ssize_t * len_hint); void (*free) (struct state_backend_storage_bucket * bucket); - bool initialized; struct list_head bucket_list; }; @@ -196,8 +194,7 @@ int state_backend_bucket_circular_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket **bucket, unsigned int eraseblock, ssize_t writesize, - struct mtd_info_user *mtd_uinfo, - bool lazy_init); + struct mtd_info_user *mtd_uinfo); int state_backend_bucket_cached_create(struct device_d *dev, struct state_backend_storage_bucket *raw, struct state_backend_storage_bucket **out); -- cgit v1.2.3 From b7d9863dae31d7d4d3d4a9d671c4595287243b98 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 12:18:21 +0100 Subject: state: simplify direct backend - drop support for regular files. This, if at all, is only useful for debugging. For the debugging case still a file of sufficient size can be created manually. - make stridesize mandatory. Makes the code simpler. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 145 ++++------------------------------------- 1 file changed, 14 insertions(+), 131 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 04d9d8f0a7..52f4aedee7 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -156,60 +156,6 @@ static int mtd_get_meminfo(const char *path, struct mtd_info_user *meminfo) return ret; } -#ifdef __BAREBOX__ -#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode) || S_ISCHR(s.st_mode)) -#define BLKGET_GIVES_SIZE(s) 0 -#else -#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode)) -#define BLKGET_GIVES_SIZE(s) (S_ISBLK(s.st_mode)) -#endif -#ifndef BLKGETSIZE64 -#define BLKGETSIZE64 -1 -#endif - -static int state_backend_storage_get_size(const char *path, size_t * out_size) -{ - struct mtd_info_user meminfo; - struct stat s; - int ret; - - ret = stat(path, &s); - if (ret) - return -errno; - - /* - * under Linux, stat() gives the size only on regular files - * under barebox, it works on char dev, too - */ - if (STAT_GIVES_SIZE(s)) { - *out_size = s.st_size; - return 0; - } - - /* this works under Linux on block devs */ - if (BLKGET_GIVES_SIZE(s)) { - int fd; - - fd = open(path, O_RDONLY); - if (fd < 0) - return -errno; - - ret = ioctl(fd, BLKGETSIZE64, out_size); - close(fd); - if (!ret) - return 0; - } - - /* try mtd next */ - ret = mtd_get_meminfo(path, &meminfo); - if (!ret) { - *out_size = meminfo.size; - return 0; - } - - return ret; -} - /* Number of copies that should be allocated */ const int desired_copies = 3; @@ -292,41 +238,6 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, return 0; } -static int state_storage_file_create(struct device_d *dev, const char *path, - size_t fd_size) -{ - int fd; - uint8_t *buf; - int ret; - - fd = open(path, O_RDWR | O_CREAT, 0600); - if (fd < 0) { - dev_err(dev, "Failed to open/create file '%s', %d\n", path, - -errno); - return -errno; - } - - buf = xzalloc(fd_size); - if (!buf) { - ret = -ENOMEM; - goto out_close; - } - - ret = write_full(fd, buf, fd_size); - if (ret < 0) { - dev_err(dev, "Failed to initialize empty file '%s', %d\n", path, - ret); - goto out_free; - } - ret = 0; - -out_free: - free(buf); -out_close: - close(fd); - return ret; -} - /** * state_storage_file_buckets_init - Create buckets for a conventional file descriptor * @param storage Storage object @@ -345,53 +256,25 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage size_t max_size, uint32_t stridesize) { struct state_backend_storage_bucket *bucket; - size_t fd_size = 0; - int ret; + int ret, n; off_t offset; int nr_copies = 0; - ret = state_backend_storage_get_size(path, &fd_size); - if (ret) { - if (ret != -ENOENT) { - dev_err(storage->dev, "Failed to get the filesize of '%s', %d\n", - path, ret); - return ret; - } - if (!stridesize) { - dev_err(storage->dev, "File '%s' does not exist and no information about the needed size. Please specify stridesize\n", - path); - return ret; - } - - if (max_size) - fd_size = min(dev_offset + stridesize * desired_copies, - dev_offset + max_size); - else - fd_size = dev_offset + stridesize * desired_copies; - dev_info(storage->dev, "File '%s' does not exist, creating file of size %zd\n", - path, fd_size); - ret = state_storage_file_create(storage->dev, path, fd_size); - if (ret) { - dev_info(storage->dev, "Failed to create file '%s', %d\n", - path, ret); - return ret; - } - } else if (max_size) { - fd_size = min(fd_size, (size_t)dev_offset + max_size); - } - if (!stridesize) { - dev_warn(storage->dev, "WARNING, no stridesize given although we use a direct file write. Starting in degraded mode\n"); - stridesize = fd_size; + dev_err(storage->dev, "stridesize unspecified\n"); + return -EINVAL; } - for (offset = dev_offset; offset < fd_size; offset += stridesize) { - size_t maxsize = min((size_t)stridesize, - (size_t)(fd_size - offset)); + if (max_size && max_size < desired_copies * stridesize) { + dev_err(storage->dev, "device is too small to hold %d copies\n", desired_copies); + return -EINVAL; + } + for (n = 0; n < desired_copies; n++) { + offset = dev_offset + n * stridesize; ret = state_backend_bucket_direct_create(storage->dev, path, &bucket, offset, - maxsize); + stridesize); if (ret) { dev_warn(storage->dev, "Failed to create direct bucket at '%s' offset %ld\n", path, offset); @@ -407,16 +290,16 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage list_add_tail(&bucket->bucket_list, &storage->buckets); ++nr_copies; - if (nr_copies >= desired_copies) - return 0; } if (!nr_copies) { dev_err(storage->dev, "Failed to initialize any state direct storage bucket\n"); return -EIO; } - dev_warn(storage->dev, "Failed to initialize desired amount of direct buckets, only %d of %d succeeded\n", - nr_copies, desired_copies); + + if (nr_copies < desired_copies) + dev_warn(storage->dev, "Failed to initialize desired amount of direct buckets, only %d of %d succeeded\n", + nr_copies, desired_copies); return 0; } -- cgit v1.2.3 From 9948003da46c27b45d4479124407ed7805d84a02 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 09:16:14 +0100 Subject: state: replace len_hint logic The len_hint mechanism is rather hard to understand as it's not clear from where to where the hint is passed and also it's not clear what happens if the hint is empty or wrong. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 4 ++-- common/state/backend_bucket_direct.c | 11 +++-------- common/state/backend_format_dtb.c | 7 +++++-- common/state/backend_format_raw.c | 5 ++++- common/state/backend_storage.c | 9 ++++++--- common/state/state.h | 2 +- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 8eae86694a..0b8286f9cc 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -227,7 +227,7 @@ static int state_mtd_peb_erase(struct state_backend_storage_bucket_circular *cir static int state_backend_bucket_circular_read(struct state_backend_storage_bucket *bucket, uint8_t ** buf_out, - ssize_t * len_hint) + ssize_t * len_out) { struct state_backend_storage_bucket_circular *circ = get_bucket_circular(bucket); @@ -282,7 +282,7 @@ static int state_backend_bucket_circular_read(struct state_backend_storage_bucke } *buf_out = buf; - *len_hint = read_len - sizeof(struct state_backend_storage_bucket_circular_meta); + *len_out = read_len - sizeof(struct state_backend_storage_bucket_circular_meta); return ret; } diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 5225433ec5..06a5433c45 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -47,7 +47,7 @@ static inline struct state_backend_storage_bucket_direct static int state_backend_bucket_direct_read(struct state_backend_storage_bucket *bucket, uint8_t ** buf_out, - ssize_t * len_hint) + ssize_t * len_out) { struct state_backend_storage_bucket_direct *direct = get_bucket_direct(bucket); @@ -69,18 +69,13 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket if (meta.magic == direct_magic) { read_len = meta.written_length; } else { - if (*len_hint) - read_len = *len_hint; - else - read_len = direct->max_size; + read_len = direct->max_size; ret = lseek(direct->fd, direct->offset, SEEK_SET); if (ret < 0) { dev_err(direct->dev, "Failed to seek file, %d\n", ret); return ret; } } - if (direct->max_size) - read_len = min(read_len, direct->max_size); buf = xmalloc(read_len); if (!buf) @@ -94,7 +89,7 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket } *buf_out = buf; - *len_hint = read_len; + *len_out = read_len; return 0; } diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c index dc19c888e5..abf8921dc4 100644 --- a/common/state/backend_format_dtb.c +++ b/common/state/backend_format_dtb.c @@ -40,12 +40,13 @@ static inline struct state_backend_format_dtb *get_format_dtb(struct static int state_backend_format_dtb_verify(struct state_backend_format *format, uint32_t magic, const uint8_t * buf, - ssize_t len) + ssize_t *lenp) { struct state_backend_format_dtb *fdtb = get_format_dtb(format); struct device_node *root; struct fdt_header *fdt = (struct fdt_header *)buf; size_t dtb_len = fdt32_to_cpu(fdt->totalsize); + size_t len = *lenp; if (dtb_len > len) { dev_err(fdtb->dev, "Error, stored DTB length (%d) longer than read buffer (%d)\n", @@ -67,6 +68,8 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format, fdtb->root = root; + *lenp = be32_to_cpu(fdt->totalsize); + return 0; } @@ -78,7 +81,7 @@ static int state_backend_format_dtb_unpack(struct state_backend_format *format, int ret; if (!fdtb->root) { - state_backend_format_dtb_verify(format, 0, buf, len); + state_backend_format_dtb_verify(format, 0, buf, &len); } ret = state_from_node(state, fdtb->root, 0); diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index e028ea616c..3c8956f8ef 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -55,13 +55,14 @@ static inline struct state_backend_format_raw *get_format_raw( static int backend_format_raw_verify(struct state_backend_format *format, uint32_t magic, const uint8_t * buf, - ssize_t len) + ssize_t *lenp) { uint32_t crc; struct backend_raw_header *header; int d_len = 0; int ret; const uint8_t *data; + ssize_t len = *lenp; struct state_backend_format_raw *backend_raw = get_format_raw(format); ssize_t complete_len; @@ -105,6 +106,8 @@ static int backend_format_raw_verify(struct state_backend_format *format, return -EINVAL; } + *lenp = header->data_len + sizeof(*header); + if (backend_raw->digest) { struct digest *d = backend_raw->digest; const void *hmac = data + header->data_len; diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 52f4aedee7..f1b3f5a6b2 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -111,15 +111,18 @@ int state_storage_read(struct state_backend_storage *storage, int ret; list_for_each_entry(bucket, &storage->buckets, bucket_list) { - *len = 0; - ret = bucket->read(bucket, buf, len); if (ret) { dev_warn(storage->dev, "Failed to read from state backend bucket, trying next, %d\n", ret); continue; } - ret = format->verify(format, magic, *buf, *len); + + /* + * Verify the buffer crcs. The buffer length is passed in the len argument, + * .verify overwrites it with the length actually used. + */ + ret = format->verify(format, magic, *buf, len); if (!ret) { goto found; } diff --git a/common/state/state.h b/common/state/state.h index 6f5de31dff..0b1a7e5ec2 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -46,7 +46,7 @@ struct state_backend_storage_bucket { */ struct state_backend_format { int (*verify) (struct state_backend_format * format, uint32_t magic, - const uint8_t * buf, ssize_t len); + const uint8_t * buf, ssize_t *lenp); int (*pack) (struct state_backend_format * format, struct state * state, uint8_t ** buf, ssize_t * len); int (*unpack) (struct state_backend_format * format, -- cgit v1.2.3 From eaf17f417739d35082875b971148edb5771bafb7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 10:07:00 +0100 Subject: state: Convert all bufs to void * A void * is a much better type for a buffer than a u8 * as it can be casted to any other type implicitly. Convert all buffers used by the state framework to void *. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_cached.c | 6 +++--- common/state/backend_bucket_circular.c | 16 ++++++++-------- common/state/backend_bucket_direct.c | 6 +++--- common/state/backend_format_dtb.c | 6 +++--- common/state/backend_format_raw.c | 10 +++++----- common/state/backend_storage.c | 6 +++--- common/state/state.c | 4 ++-- common/state/state.h | 16 ++++++++-------- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/common/state/backend_bucket_cached.c b/common/state/backend_bucket_cached.c index 5e7f44c8f8..f8a7785387 100644 --- a/common/state/backend_bucket_cached.c +++ b/common/state/backend_bucket_cached.c @@ -20,7 +20,7 @@ struct state_backend_storage_bucket_cache { struct state_backend_storage_bucket *raw; - u8 *data; + void *data; ssize_t data_len; bool force_write; @@ -61,7 +61,7 @@ static int state_backend_bucket_cache_fill( } static int state_backend_bucket_cache_read(struct state_backend_storage_bucket *bucket, - uint8_t ** buf_out, + void ** buf_out, ssize_t * len_hint) { struct state_backend_storage_bucket_cache *cache = @@ -85,7 +85,7 @@ static int state_backend_bucket_cache_read(struct state_backend_storage_bucket * } static int state_backend_bucket_cache_write(struct state_backend_storage_bucket *bucket, - const uint8_t * buf, ssize_t len) + const void * buf, ssize_t len) { struct state_backend_storage_bucket_cache *cache = get_bucket_cache(bucket); diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 0b8286f9cc..53ee0c3f57 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -65,7 +65,7 @@ static inline struct state_backend_storage_bucket_circular #ifdef __BAREBOX__ static int state_mtd_peb_read(struct state_backend_storage_bucket_circular *circ, - char *buf, int offset, int len) + void *buf, int offset, int len) { int ret; @@ -102,7 +102,7 @@ static int state_mtd_peb_read(struct state_backend_storage_bucket_circular *circ } static int state_mtd_peb_write(struct state_backend_storage_bucket_circular *circ, - const char *buf, int offset, int len) + const void *buf, int offset, int len) { int ret; @@ -133,7 +133,7 @@ static int state_mtd_peb_erase(struct state_backend_storage_bucket_circular *cir } #else static int state_mtd_peb_read(struct state_backend_storage_bucket_circular *circ, - char *buf, int suboffset, int len) + void *buf, int suboffset, int len) { int ret; off_t offset = suboffset; @@ -185,7 +185,7 @@ static int state_mtd_peb_read(struct state_backend_storage_bucket_circular *circ } static int state_mtd_peb_write(struct state_backend_storage_bucket_circular *circ, - const char *buf, int suboffset, int len) + const void *buf, int suboffset, int len) { int ret; off_t offset = suboffset; @@ -226,14 +226,14 @@ static int state_mtd_peb_erase(struct state_backend_storage_bucket_circular *cir #endif static int state_backend_bucket_circular_read(struct state_backend_storage_bucket *bucket, - uint8_t ** buf_out, + void ** buf_out, ssize_t * len_out) { struct state_backend_storage_bucket_circular *circ = get_bucket_circular(bucket); ssize_t read_len; off_t offset; - uint8_t *buf; + void *buf; int ret; /* Storage is empty */ @@ -288,7 +288,7 @@ static int state_backend_bucket_circular_read(struct state_backend_storage_bucke } static int state_backend_bucket_circular_write(struct state_backend_storage_bucket *bucket, - const uint8_t * buf, + const void * buf, ssize_t len) { struct state_backend_storage_bucket_circular *circ = @@ -297,7 +297,7 @@ static int state_backend_bucket_circular_write(struct state_backend_storage_buck struct state_backend_storage_bucket_circular_meta *meta; uint32_t written_length = ALIGN(len + sizeof(*meta), circ->writesize); int ret; - uint8_t *write_buf; + void *write_buf; if (written_length > circ->max_size) { dev_err(circ->dev, "Error, state data too big to be written, to write: %zd, writesize: %zd, length: %zd, available: %zd\n", diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 06a5433c45..246cb499c4 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -46,14 +46,14 @@ static inline struct state_backend_storage_bucket_direct } static int state_backend_bucket_direct_read(struct state_backend_storage_bucket - *bucket, uint8_t ** buf_out, + *bucket, void ** buf_out, ssize_t * len_out) { struct state_backend_storage_bucket_direct *direct = get_bucket_direct(bucket); struct state_backend_storage_bucket_direct_meta meta; ssize_t read_len; - uint8_t *buf; + void *buf; int ret; ret = lseek(direct->fd, direct->offset, SEEK_SET); @@ -95,7 +95,7 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket } static int state_backend_bucket_direct_write(struct state_backend_storage_bucket - *bucket, const uint8_t * buf, + *bucket, const void * buf, ssize_t len) { struct state_backend_storage_bucket_direct *direct = diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c index abf8921dc4..d7b01729bc 100644 --- a/common/state/backend_format_dtb.c +++ b/common/state/backend_format_dtb.c @@ -39,7 +39,7 @@ static inline struct state_backend_format_dtb *get_format_dtb(struct } static int state_backend_format_dtb_verify(struct state_backend_format *format, - uint32_t magic, const uint8_t * buf, + uint32_t magic, const void * buf, ssize_t *lenp) { struct state_backend_format_dtb *fdtb = get_format_dtb(format); @@ -75,7 +75,7 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format, static int state_backend_format_dtb_unpack(struct state_backend_format *format, struct state *state, - const uint8_t * buf, ssize_t len) + const void * buf, ssize_t len) { struct state_backend_format_dtb *fdtb = get_format_dtb(format); int ret; @@ -92,7 +92,7 @@ static int state_backend_format_dtb_unpack(struct state_backend_format *format, } static int state_backend_format_dtb_pack(struct state_backend_format *format, - struct state *state, uint8_t ** buf, + struct state *state, void ** buf, ssize_t * len) { struct state_backend_format_dtb *fdtb = get_format_dtb(format); diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index 3c8956f8ef..a425b636d0 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -54,14 +54,14 @@ static inline struct state_backend_format_raw *get_format_raw( } static int backend_format_raw_verify(struct state_backend_format *format, - uint32_t magic, const uint8_t * buf, + uint32_t magic, const void * buf, ssize_t *lenp) { uint32_t crc; struct backend_raw_header *header; int d_len = 0; int ret; - const uint8_t *data; + const void *data; ssize_t len = *lenp; struct state_backend_format_raw *backend_raw = get_format_raw(format); ssize_t complete_len; @@ -139,12 +139,12 @@ static int backend_format_raw_verify(struct state_backend_format *format, } static int backend_format_raw_unpack(struct state_backend_format *format, - struct state *state, const uint8_t * buf, + struct state *state, const void * buf, ssize_t len) { struct state_variable *sv; const struct backend_raw_header *header; - const uint8_t *data; + const void *data; struct state_backend_format_raw *backend_raw = get_format_raw(format); header = (const struct backend_raw_header *)buf; @@ -163,7 +163,7 @@ static int backend_format_raw_unpack(struct state_backend_format *format, } static int backend_format_raw_pack(struct state_backend_format *format, - struct state *state, uint8_t ** buf_out, + struct state *state, void ** buf_out, ssize_t * len_out) { struct state_backend_format_raw *backend_raw = get_format_raw(format); diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index f1b3f5a6b2..6ec58a0c97 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -42,7 +42,7 @@ const unsigned int min_copies_written = 1; * error. */ int state_storage_write(struct state_backend_storage *storage, - const uint8_t * buf, ssize_t len) + const void * buf, ssize_t len) { struct state_backend_storage_bucket *bucket; int ret; @@ -82,7 +82,7 @@ int state_storage_write(struct state_backend_storage *storage, * low, can read their own copy first and compare it. */ int state_storage_restore_consistency(struct state_backend_storage *storage, - const uint8_t * buf, ssize_t len) + const void * buf, ssize_t len) { return state_storage_write(storage, buf, len); } @@ -105,7 +105,7 @@ int state_storage_restore_consistency(struct state_backend_storage *storage, */ int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, uint8_t ** buf, ssize_t * len) + uint32_t magic, void **buf, ssize_t *len) { struct state_backend_storage_bucket *bucket; int ret; diff --git a/common/state/state.c b/common/state/state.c index 8d2dca2523..476e3ee08e 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -41,7 +41,7 @@ static LIST_HEAD(state_list); */ int state_save(struct state *state) { - uint8_t *buf; + void *buf; ssize_t len; int ret; @@ -80,7 +80,7 @@ out: */ int state_load(struct state *state) { - uint8_t *buf; + void *buf; ssize_t len; int ret; diff --git a/common/state/state.h b/common/state/state.h index 0b1a7e5ec2..52d332e27d 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -21,9 +21,9 @@ struct mtd_info_user; */ struct state_backend_storage_bucket { int (*write) (struct state_backend_storage_bucket * bucket, - const uint8_t * buf, ssize_t len); + const void * buf, ssize_t len); int (*read) (struct state_backend_storage_bucket * bucket, - uint8_t ** buf, ssize_t * len_hint); + void ** buf, ssize_t * len_hint); void (*free) (struct state_backend_storage_bucket * bucket); struct list_head bucket_list; @@ -46,11 +46,11 @@ struct state_backend_storage_bucket { */ struct state_backend_format { int (*verify) (struct state_backend_format * format, uint32_t magic, - const uint8_t * buf, ssize_t *lenp); + const void * buf, ssize_t *lenp); int (*pack) (struct state_backend_format * format, struct state * state, - uint8_t ** buf, ssize_t * len); + void ** buf, ssize_t * len); int (*unpack) (struct state_backend_format * format, - struct state * state, const uint8_t * buf, ssize_t len); + struct state * state, const void * buf, ssize_t len); void (*free) (struct state_backend_format * format); const char *name; }; @@ -207,13 +207,13 @@ int state_backend_bucket_direct_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket **bucket, off_t offset, ssize_t max_size); int state_storage_write(struct state_backend_storage *storage, - const uint8_t * buf, ssize_t len); + const void * buf, ssize_t len); int state_storage_restore_consistency(struct state_backend_storage - *storage, const uint8_t * buf, + *storage, const void * buf, ssize_t len); int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, uint8_t **buf, ssize_t *len); + uint32_t magic, void **buf, ssize_t *len); static inline struct state_uint32 *to_state_uint32(struct state_variable *s) { -- cgit v1.2.3 From 238008b4bd8f263762c654c42e6176e3629977c1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 08:47:55 +0100 Subject: state: Drop cache bucket The cache bucket sits between the storage functions and the backend storage. We only read from the storage once, so there is no need to cache anything. The real purpose of the cache bucket is to keep the -EUCLEAN information when a NAND block needs to be rewritten and to keep the read buffers as long as the backend iterates over all buckets trying to find the one we want to use. This can be coded easier and more obvious in the backend code, so drop the cache bucket. Signed-off-by: Sascha Hauer --- common/state/Makefile | 1 - common/state/backend_bucket_cached.c | 141 ----------------------------------- common/state/backend_storage.c | 112 +++++++++++++++++----------- common/state/state.h | 7 +- 4 files changed, 71 insertions(+), 190 deletions(-) delete mode 100644 common/state/backend_bucket_cached.c diff --git a/common/state/Makefile b/common/state/Makefile index d3518feab4..fcf9add52c 100644 --- a/common/state/Makefile +++ b/common/state/Makefile @@ -5,4 +5,3 @@ obj-y += backend_format_raw.o obj-y += backend_storage.o obj-y += backend_bucket_direct.o obj-$(CONFIG_MTD) += backend_bucket_circular.o -obj-y += backend_bucket_cached.o diff --git a/common/state/backend_bucket_cached.c b/common/state/backend_bucket_cached.c deleted file mode 100644 index f8a7785387..0000000000 --- a/common/state/backend_bucket_cached.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2016 Pengutronix, Markus Pargmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include "state.h" - -struct state_backend_storage_bucket_cache { - struct state_backend_storage_bucket bucket; - - struct state_backend_storage_bucket *raw; - - void *data; - ssize_t data_len; - bool force_write; - - /* For outputs */ - struct device_d *dev; -}; - -static inline struct state_backend_storage_bucket_cache - *get_bucket_cache(struct state_backend_storage_bucket *bucket) -{ - return container_of(bucket, - struct state_backend_storage_bucket_cache, - bucket); -} - -static inline void state_backend_bucket_cache_drop( - struct state_backend_storage_bucket_cache *cache) -{ - if (cache->data) { - free(cache->data); - cache->data = NULL; - cache->data_len = 0; - } -} - -static int state_backend_bucket_cache_fill( - struct state_backend_storage_bucket_cache *cache) -{ - int ret; - - ret = cache->raw->read(cache->raw, &cache->data, &cache->data_len); - if (ret == -EUCLEAN) { - cache->force_write = true; - ret = 0; - } - - return ret; -} - -static int state_backend_bucket_cache_read(struct state_backend_storage_bucket *bucket, - void ** buf_out, - ssize_t * len_hint) -{ - struct state_backend_storage_bucket_cache *cache = - get_bucket_cache(bucket); - int ret; - - if (!cache->data) { - ret = state_backend_bucket_cache_fill(cache); - if (ret) - return ret; - } - - if (cache->data) { - *buf_out = xmemdup(cache->data, cache->data_len); - if (!*buf_out) - return -ENOMEM; - *len_hint = cache->data_len; - } - - return 0; -} - -static int state_backend_bucket_cache_write(struct state_backend_storage_bucket *bucket, - const void * buf, ssize_t len) -{ - struct state_backend_storage_bucket_cache *cache = - get_bucket_cache(bucket); - int ret; - - if (!cache->force_write) { - if (!cache->data) - ret = state_backend_bucket_cache_fill(cache); - - if (cache->data_len == len && !memcmp(cache->data, buf, len)) - return 0; - } - - state_backend_bucket_cache_drop(cache); - - ret = cache->raw->write(cache->raw, buf, len); - if (ret) - return ret; - - cache->data = xmemdup(buf, len); - cache->data_len = len; - return 0; -} - -static void state_backend_bucket_cache_free( - struct state_backend_storage_bucket *bucket) -{ - struct state_backend_storage_bucket_cache *cache = - get_bucket_cache(bucket); - - state_backend_bucket_cache_drop(cache); - cache->raw->free(cache->raw); - free(cache); -} - -int state_backend_bucket_cached_create(struct device_d *dev, - struct state_backend_storage_bucket *raw, - struct state_backend_storage_bucket **out) -{ - struct state_backend_storage_bucket_cache *cache; - - cache = xzalloc(sizeof(*cache)); - cache->raw = raw; - cache->dev = dev; - - cache->bucket.free = state_backend_bucket_cache_free; - cache->bucket.read = state_backend_bucket_cache_read; - cache->bucket.write = state_backend_bucket_cache_write; - - *out = &cache->bucket; - - return 0; -} diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 6ec58a0c97..218c67f2d7 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -69,22 +69,29 @@ int state_storage_write(struct state_backend_storage *storage, return -EIO; } -/** - * state_storage_restore_consistency - Restore consistency on all storage backends - * @param storage Storage object - * @param buf Buffer with valid data that should be on all buckets after this operation - * @param len Length of the buffer - * @return 0 on success, -errno otherwise - * - * This function brings valid data onto all buckets we have to ensure that all - * data copies are in sync. In the current implementation we just write the data - * to all buckets. Bucket implementations that need to keep the number of writes - * low, can read their own copy first and compare it. - */ -int state_storage_restore_consistency(struct state_backend_storage *storage, - const void * buf, ssize_t len) +static int bucket_refresh(struct state_backend_storage *storage, + struct state_backend_storage_bucket *bucket, void *buf, ssize_t len) { - return state_storage_write(storage, buf, len); + int ret; + + if (bucket->needs_refresh) + goto refresh; + + if (bucket->len != len) + goto refresh; + + if (memcmp(bucket->buf, buf, len)) + goto refresh; + + return 0; + +refresh: + ret = bucket->write(bucket, buf, len); + + if (ret) + dev_warn(storage->dev, "Failed to restore bucket\n"); + + return ret; } /** @@ -94,7 +101,6 @@ int state_storage_restore_consistency(struct state_backend_storage *storage, * @param magic state magic value * @param buf The newly allocated data area will be stored in this pointer * @param len The resulting length of the buffer - * @param len_hint Hint of how big the data may be. * @return 0 on success, -errno otherwise. buf and len will be set to valid * values on success. * @@ -107,12 +113,18 @@ int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, uint32_t magic, void **buf, ssize_t *len) { - struct state_backend_storage_bucket *bucket; + struct state_backend_storage_bucket *bucket, *bucket_used = NULL; int ret; + /* + * Iterate over all buckets. The first valid one we find is the + * one we want to use. + */ list_for_each_entry(bucket, &storage->buckets, bucket_list) { - ret = bucket->read(bucket, buf, len); - if (ret) { + ret = bucket->read(bucket, &bucket->buf, &bucket->len); + if (ret == -EUCLEAN) { + bucket->needs_refresh = 1; + } else if (ret) { dev_warn(storage->dev, "Failed to read from state backend bucket, trying next, %d\n", ret); continue; @@ -122,22 +134,46 @@ int state_storage_read(struct state_backend_storage *storage, * Verify the buffer crcs. The buffer length is passed in the len argument, * .verify overwrites it with the length actually used. */ - ret = format->verify(format, magic, *buf, len); - if (!ret) { - goto found; - } - free(*buf); - dev_warn(storage->dev, "Failed to verify read copy, trying next bucket, %d\n", - ret); + ret = format->verify(format, magic, bucket->buf, &bucket->len); + if (!ret && !bucket_used) + bucket_used = bucket; + + if (ret) + dev_warn(storage->dev, "Failed to verify read copy, trying next bucket, %d\n", + ret); + } + + if (!bucket_used) { + dev_err(storage->dev, "Failed to find any valid state copy in any bucket\n"); + + return -ENOENT; } - dev_err(storage->dev, "Failed to find any valid state copy in any bucket\n"); + /* + * Restore/refresh all buckets except the one we currently use (in case + * it's the only usable bucket at the moment) + */ + list_for_each_entry(bucket, &storage->buckets, bucket_list) { + if (bucket == bucket_used) + continue; + + ret = bucket_refresh(storage, bucket, bucket_used->buf, bucket_used->len); + + /* Free buffer from the unused buckets */ + free(bucket->buf); + bucket->buf = NULL; + } - return -ENOENT; + /* + * Restore/refresh the bucket we currently use + */ + ret = bucket_refresh(storage, bucket_used, bucket_used->buf, bucket_used->len); -found: - /* A failed restore consistency is not a failure of reading the state */ - state_storage_restore_consistency(storage, *buf, *len); + *buf = bucket_used->buf; + *len = bucket_used->len; + + /* buffer from the used bucket is passed to the caller, do not free */ + bucket_used->buf = NULL; return 0; } @@ -218,13 +254,6 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, continue; } - ret = state_backend_bucket_cached_create(storage->dev, bucket, - &bucket); - if (ret) { - dev_warn(storage->dev, "Failed to setup cache bucket, continuing without cache, %d\n", - ret); - } - list_add_tail(&bucket->bucket_list, &storage->buckets); ++nr_copies; if (nr_copies >= desired_copies) @@ -284,13 +313,6 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage continue; } - ret = state_backend_bucket_cached_create(storage->dev, bucket, - &bucket); - if (ret) { - dev_warn(storage->dev, "Failed to setup cache bucket, continuing without cache, %d\n", - ret); - } - list_add_tail(&bucket->bucket_list, &storage->buckets); ++nr_copies; } diff --git a/common/state/state.h b/common/state/state.h index 52d332e27d..62544a207c 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -27,6 +27,10 @@ struct state_backend_storage_bucket { void (*free) (struct state_backend_storage_bucket * bucket); struct list_head bucket_list; + + void *buf; + ssize_t len; + bool needs_refresh; }; /** @@ -208,9 +212,6 @@ int state_backend_bucket_direct_create(struct device_d *dev, const char *path, off_t offset, ssize_t max_size); int state_storage_write(struct state_backend_storage *storage, const void * buf, ssize_t len); -int state_storage_restore_consistency(struct state_backend_storage - *storage, const void * buf, - ssize_t len); int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, uint32_t magic, void **buf, ssize_t *len); -- cgit v1.2.3 From 5207445cfd1f5fcb592cf4337691ec4b85170c65 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 11:29:50 +0100 Subject: state: backend-direct: Fix max_size The max_size in the direct backend includes the meta data, so substract its size when determing the max data size we can store. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_direct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 246cb499c4..9996ac2919 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -103,7 +103,7 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket int ret; struct state_backend_storage_bucket_direct_meta meta; - if (direct->max_size && len > direct->max_size) + if (direct->max_size && len > direct->max_size - sizeof(meta)) return -E2BIG; ret = lseek(direct->fd, direct->offset, SEEK_SET); -- cgit v1.2.3 From a5986ff8177e0f44b7d521a3cd824a8aa328d46f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 11:41:53 +0100 Subject: state: bucket: Make output more informative Print offset and number of the bucket along with the bucket specific messages to give a hint which bucket a message is for. Also it's pretty much expected that buckets sometimes have no data or need cleanup, so instead of complaining loudly, only write which bucket is used and which buckets are cleaned up. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 25 +++++++++++++++---------- common/state/state.h | 3 +++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 218c67f2d7..4e0548af85 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -89,7 +89,11 @@ refresh: ret = bucket->write(bucket, buf, len); if (ret) - dev_warn(storage->dev, "Failed to restore bucket\n"); + dev_warn(storage->dev, "Failed to restore bucket %d@0x%08lx\n", + bucket->num, bucket->offset); + else + dev_info(storage->dev, "restored bucket %d@0x%08lx\n", + bucket->num, bucket->offset); return ret; } @@ -122,13 +126,10 @@ int state_storage_read(struct state_backend_storage *storage, */ list_for_each_entry(bucket, &storage->buckets, bucket_list) { ret = bucket->read(bucket, &bucket->buf, &bucket->len); - if (ret == -EUCLEAN) { + if (ret == -EUCLEAN) bucket->needs_refresh = 1; - } else if (ret) { - dev_warn(storage->dev, "Failed to read from state backend bucket, trying next, %d\n", - ret); + else if (ret) continue; - } /* * Verify the buffer crcs. The buffer length is passed in the len argument, @@ -137,10 +138,6 @@ int state_storage_read(struct state_backend_storage *storage, ret = format->verify(format, magic, bucket->buf, &bucket->len); if (!ret && !bucket_used) bucket_used = bucket; - - if (ret) - dev_warn(storage->dev, "Failed to verify read copy, trying next bucket, %d\n", - ret); } if (!bucket_used) { @@ -149,6 +146,8 @@ int state_storage_read(struct state_backend_storage *storage, return -ENOENT; } + dev_info(storage->dev, "Using bucket %d@0x%08lx\n", bucket_used->num, bucket_used->offset); + /* * Restore/refresh all buckets except the one we currently use (in case * it's the only usable bucket at the moment) @@ -254,6 +253,9 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, continue; } + bucket->offset = offset; + bucket->num = nr_copies; + list_add_tail(&bucket->bucket_list, &storage->buckets); ++nr_copies; if (nr_copies >= desired_copies) @@ -313,6 +315,9 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage continue; } + bucket->offset = offset; + bucket->num = nr_copies; + list_add_tail(&bucket->bucket_list, &storage->buckets); ++nr_copies; } diff --git a/common/state/state.h b/common/state/state.h index 62544a207c..f6ab2009cc 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -26,6 +26,9 @@ struct state_backend_storage_bucket { void ** buf, ssize_t * len_hint); void (*free) (struct state_backend_storage_bucket * bucket); + int num; + off_t offset; + struct list_head bucket_list; void *buf; -- cgit v1.2.3 From 0e0a13b243621f06cf1f2da257ff7b2fd81a16b1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 12:59:48 +0100 Subject: state: backend_bucket_direct: max_size is always given max_size is always != 0, so if(direct->max_size) can be skipped. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_direct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 9996ac2919..b72e8adb96 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -103,7 +103,7 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket int ret; struct state_backend_storage_bucket_direct_meta meta; - if (direct->max_size && len > direct->max_size - sizeof(meta)) + if (len > direct->max_size - sizeof(meta)) return -E2BIG; ret = lseek(direct->fd, direct->offset, SEEK_SET); -- cgit v1.2.3 From 3c482d418761a52dbd10cab1bb5d140a34d927ef Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 13:51:10 +0100 Subject: state: backend: Add more fields to struct state_backend_storage To save a few function arguments. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 48 ++++++++++++++++++------------------------ common/state/state.h | 6 ++++++ 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 4e0548af85..17013855b4 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -201,10 +201,7 @@ const int desired_copies = 3; * state_storage_mtd_buckets_init - Creates storage buckets for mtd devices * @param storage Storage object * @param meminfo Info about the mtd device - * @param path Path to the device * @param circular If false, use non-circular mode to write data that is compatible with the old on-flash format - * @param dev_offset Offset to start at in the device. - * @param max_size Maximum size to use for data. May be 0 for infinite. * @return 0 on success, -errno otherwise * * Starting from offset 0 this function tries to create circular buckets on @@ -214,12 +211,10 @@ const int desired_copies = 3; * Circular buckets write new data always in the next free space. */ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, - struct mtd_info_user *meminfo, - const char *path, bool circular, - off_t dev_offset, size_t max_size) + struct mtd_info_user *meminfo, bool circular) { struct state_backend_storage_bucket *bucket; - ssize_t end = dev_offset + max_size; + ssize_t end = storage->offset + storage->max_size; int nr_copies = 0; off_t offset; ssize_t writesize; @@ -227,9 +222,9 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, if (!end || end > meminfo->size) end = meminfo->size; - if (!IS_ALIGNED(dev_offset, meminfo->erasesize)) { + if (!IS_ALIGNED(storage->offset, meminfo->erasesize)) { dev_err(storage->dev, "Offset within the device is not aligned to eraseblocks. Offset is %ld, erasesize %zu\n", - dev_offset, meminfo->erasesize); + storage->offset, meminfo->erasesize); return -EINVAL; } @@ -238,18 +233,18 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, else writesize = meminfo->erasesize; - for (offset = dev_offset; offset < end; offset += meminfo->erasesize) { + for (offset = storage->offset; offset < end; offset += meminfo->erasesize) { int ret; unsigned int eraseblock = offset / meminfo->erasesize; - ret = state_backend_bucket_circular_create(storage->dev, path, + ret = state_backend_bucket_circular_create(storage->dev, storage->path, &bucket, eraseblock, writesize, meminfo); if (ret) { dev_warn(storage->dev, "Failed to create bucket at '%s' eraseblock %u\n", - path, eraseblock); + storage->path, eraseblock); continue; } @@ -275,24 +270,19 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, /** * state_storage_file_buckets_init - Create buckets for a conventional file descriptor * @param storage Storage object - * @param path Path to file/device - * @param dev_offset Offset in the device to start writing at. - * @param max_size Maximum size of the data. May be 0 for infinite. - * @param stridesize How far apart the different data copies are placed. If - * stridesize is 0, only one copy can be created. * @return 0 on success, -errno otherwise * * For blockdevices and other regular files we create direct buckets beginning * at offset 0. Direct buckets are simple and write data always to offset 0. */ -static int state_storage_file_buckets_init(struct state_backend_storage *storage, - const char *path, off_t dev_offset, - size_t max_size, uint32_t stridesize) +static int state_storage_file_buckets_init(struct state_backend_storage *storage) { struct state_backend_storage_bucket *bucket; int ret, n; off_t offset; int nr_copies = 0; + uint32_t stridesize = storage->stridesize; + size_t max_size = storage->max_size; if (!stridesize) { dev_err(storage->dev, "stridesize unspecified\n"); @@ -305,13 +295,13 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage } for (n = 0; n < desired_copies; n++) { - offset = dev_offset + n * stridesize; - ret = state_backend_bucket_direct_create(storage->dev, path, + offset = storage->offset + n * stridesize; + ret = state_backend_bucket_direct_create(storage->dev, storage->path, &bucket, offset, stridesize); if (ret) { dev_warn(storage->dev, "Failed to create direct bucket at '%s' offset %ld\n", - path, offset); + storage->path, offset); continue; } @@ -359,6 +349,9 @@ int state_storage_init(struct state *state, const char *path, storage->dev = &state->dev; storage->name = storagetype; storage->stridesize = stridesize; + storage->offset = offset; + storage->max_size = max_size; + storage->path = xstrdup(path); if (IS_ENABLED(CONFIG_MTD)) ret = mtd_get_meminfo(path, &meminfo); @@ -372,12 +365,9 @@ int state_storage_init(struct state *state, const char *path, storagetype); circular = false; } - return state_storage_mtd_buckets_init(storage, &meminfo, path, - circular, offset, - max_size); + return state_storage_mtd_buckets_init(storage, &meminfo, circular); } else { - return state_storage_file_buckets_init(storage, path, offset, - max_size, stridesize); + return state_storage_file_buckets_init(storage); } dev_err(storage->dev, "storage init done\n"); @@ -405,4 +395,6 @@ void state_storage_free(struct state_backend_storage *storage) list_del(&bucket->bucket_list); bucket->free(bucket); } + + free(storage->path); } diff --git a/common/state/state.h b/common/state/state.h index f6ab2009cc..a2737abeb6 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -66,6 +66,9 @@ struct state_backend_format { * state_backend_storage - Storage backend of the state. * * @buckets List of storage buckets that are available + * @stridesize The distance between copies + * @offset Offset in the backend device where the data starts + * @max_size The maximum size of the data we can use */ struct state_backend_storage { struct list_head buckets; @@ -76,6 +79,9 @@ struct state_backend_storage { const char *name; uint32_t stridesize; + off_t offset; + size_t max_size; + char *path; bool readonly; }; -- cgit v1.2.3 From 95dfbdcf9db252cc63db04d43cd76ad73467fa08 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 15:57:31 +0100 Subject: state: backend_circular: remove unnecessary warning It's expected that NAND flashes contain bad blocks, do not warn about them. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 17013855b4..deae9c325b 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -242,11 +242,8 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, eraseblock, writesize, meminfo); - if (ret) { - dev_warn(storage->dev, "Failed to create bucket at '%s' eraseblock %u\n", - storage->path, eraseblock); + if (ret) continue; - } bucket->offset = offset; bucket->num = nr_copies; -- cgit v1.2.3 From 6f6604c918f95fccce2e94966f7c9512b80fb27c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 16:18:48 +0100 Subject: state: storage: direct: do not close file that is not opened When open failed to not try to close the invalid fd afterwards. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_direct.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index b72e8adb96..4465ed0e41 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -156,7 +156,6 @@ int state_backend_bucket_direct_create(struct device_d *dev, const char *path, fd = open(path, O_RDWR); if (fd < 0) { dev_err(dev, "Failed to open file '%s', %d\n", path, -errno); - close(fd); return -errno; } -- cgit v1.2.3 From b5eeaea7c9591a5e7406bbdf5578d29d62149f38 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 23 Mar 2017 16:30:28 +0100 Subject: state: backend: Add some documentation Write some sentences to make the concepts clearer. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 16 +++++++++++++++- common/state/backend_storage.c | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 53ee0c3f57..58fffd18e3 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -25,7 +25,21 @@ #include "state.h" - +/* + * The circular backend bucket code. The circular backend bucket is intended + * for mtd devices which need an erase operation. + * + * Erasing blocks is an operation that should be avoided. On NOR flashes erasing + * blocks is very time consuming and on NAND flashes each block only has a limited + * number of erase cycles allowed. For this reason we continuously write more data + * into each eraseblock and only erase it when no more free space is available. + * Don't confuse these multiple writes into a single eraseblock with buckets. A bucket + * is the whole eraseblock, we just happen to reuse the same bucket for storing + * new data. + * + * If your device is a mtd device, but does not have eraseblocks, like MRAMs, then + * the direct bucket is used instead. + */ struct state_backend_storage_bucket_circular { struct state_backend_storage_bucket bucket; diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index deae9c325b..f9e8151670 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -25,6 +25,28 @@ #include "state.h" +/* + * The state framework stores data in so called buckets. A bucket is + * exactly one copy of the state we want to store. On flash type media + * a bucket corresponds to a single eraseblock. On media which do not + * need an erase operation a bucket corresponds to a storage area of + * @stridesize bytes. + * + * For redundancy and to make sure that we have valid data on the storage + * device at any time the state framework stores multiple buckets. The strategy + * is as follows: + * + * When loading the state from the storage we iterate over the buckets. We + * take the first one we find which has valid crcs. The next step is to + * restore consistency between the different buckets. This means rewriting + * a bucket when it signalled it needs refresh (i.e. returned -EUCLEAN) + * or when contains data different from the bucket we use. + * + * When the state backend initialized successfully we already restored + * consistency which means all buckets contain the same data. This means + * when storing a new state we can just write all buckets in order. + */ + const unsigned int min_copies_written = 1; /** -- cgit v1.2.3 From 1f386378a7b8173220648afeab41605ac7742364 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 08:15:52 +0100 Subject: state: backend_circular: default to circular storage Default to the new circular storage format which saves erase cycles. The old format can still be selected with backend-storage-type = "noncircular". Signed-off-by: Sascha Hauer --- .../devicetree/bindings/barebox/barebox,state.rst | 6 +++--- common/state/backend_storage.c | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index e9daa65f1a..00fb592614 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -40,9 +40,9 @@ Optional properties: e.g. ``hmac(sha256)``. Only used for ``raw``. * ``backend-stridesize``: Maximum size per copy of the data. Only important for non-MTD devices -* ``backend-storage-type``: Type of the storage. This has two options at the - moment. For MTD with erasing the correct type is ``circular``. For all other - devices and files, ``direct`` is the needed type. +* ``backend-storage-type``: Normally the correct storage type is detected auto- + matically. The circular backend supports the option ``noncircular`` to fall + back to an old storage format. Variable nodes -------------- diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index f9e8151670..036204c188 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -376,13 +376,15 @@ int state_storage_init(struct state *state, const char *path, ret = mtd_get_meminfo(path, &meminfo); if (!ret && !(meminfo.flags & MTD_NO_ERASE)) { - bool circular = true; - if (!storagetype) { - circular = false; - } else if (strcmp(storagetype, "circular")) { - dev_warn(storage->dev, "Unknown storagetype '%s', falling back to old format circular storage type.\n", - storagetype); + bool circular; + if (!storagetype || !strcmp(storagetype, "circular")) { + circular = true; + } else if (!strcmp(storagetype, "noncircular")) { + dev_warn(storage->dev, "using old format circular storage type.\n"); circular = false; + } else { + dev_warn(storage->dev, "unknown storage type '%s'\n", storagetype); + return -EINVAL; } return state_storage_mtd_buckets_init(storage, &meminfo, circular); } else { -- cgit v1.2.3 From fcdda4abc4b11263d81773389949d80e4b3df930 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 08:56:48 +0100 Subject: state: backend_circular: rewrite function doc The commment talks about copies where buckets are meant and also claims we start at offset 0, which may not be true. Rewrite comment. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 036204c188..d29db36cca 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -226,11 +226,9 @@ const int desired_copies = 3; * @param circular If false, use non-circular mode to write data that is compatible with the old on-flash format * @return 0 on success, -errno otherwise * - * Starting from offset 0 this function tries to create circular buckets on - * different offsets in the device. Different copies of the data are located in - * different eraseblocks. - * For MTD devices we use circular buckets to minimize the number of erases. - * Circular buckets write new data always in the next free space. + * This function iterates over the eraseblocks and creates one bucket on + * each eraseblock until we have the number of desired buckets. Bad blocks + * will be skipped and the next block will be used. */ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, struct mtd_info_user *meminfo, bool circular) -- cgit v1.2.3 From a97f875fecfee91d73f4bba89ca16ad34495f82f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 08:58:39 +0100 Subject: state: backend_storage: Rename variable nr_copies to n_buckets We defined what a bucket is, so use n_buckets when counting buckets, and not nr_copies. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index d29db36cca..c29004071b 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -235,7 +235,7 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, { struct state_backend_storage_bucket *bucket; ssize_t end = storage->offset + storage->max_size; - int nr_copies = 0; + int n_buckets = 0; off_t offset; ssize_t writesize; @@ -266,21 +266,21 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, continue; bucket->offset = offset; - bucket->num = nr_copies; + bucket->num = n_buckets; list_add_tail(&bucket->bucket_list, &storage->buckets); - ++nr_copies; - if (nr_copies >= desired_copies) + ++n_buckets; + if (n_buckets >= desired_copies) return 0; } - if (!nr_copies) { + if (!n_buckets) { dev_err(storage->dev, "Failed to initialize any state storage bucket\n"); return -EIO; } dev_warn(storage->dev, "Failed to initialize desired amount of buckets, only %d of %d succeeded\n", - nr_copies, desired_copies); + n_buckets, desired_copies); return 0; } @@ -297,7 +297,7 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage struct state_backend_storage_bucket *bucket; int ret, n; off_t offset; - int nr_copies = 0; + int n_buckets = 0; uint32_t stridesize = storage->stridesize; size_t max_size = storage->max_size; @@ -323,20 +323,20 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage } bucket->offset = offset; - bucket->num = nr_copies; + bucket->num = n_buckets; list_add_tail(&bucket->bucket_list, &storage->buckets); - ++nr_copies; + ++n_buckets; } - if (!nr_copies) { + if (!n_buckets) { dev_err(storage->dev, "Failed to initialize any state direct storage bucket\n"); return -EIO; } - if (nr_copies < desired_copies) + if (n_buckets < desired_copies) dev_warn(storage->dev, "Failed to initialize desired amount of direct buckets, only %d of %d succeeded\n", - nr_copies, desired_copies); + n_buckets, desired_copies); return 0; } -- cgit v1.2.3 From 13a3c584b49e1a91d825fee3771ce655bf67f1b5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 09:02:01 +0100 Subject: state: backend_storage: Rename variable desired_copies to desired_buckets We defined what a bucket is, so rename the variable that holds the number of desired buckets from desired_copies to desired_buckets. While at it, make locally used variable static. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index c29004071b..1310531dd1 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -216,8 +216,8 @@ static int mtd_get_meminfo(const char *path, struct mtd_info_user *meminfo) return ret; } -/* Number of copies that should be allocated */ -const int desired_copies = 3; +/* Number of buckets that should be used */ +static const int desired_buckets = 3; /** * state_storage_mtd_buckets_init - Creates storage buckets for mtd devices @@ -270,7 +270,7 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, list_add_tail(&bucket->bucket_list, &storage->buckets); ++n_buckets; - if (n_buckets >= desired_copies) + if (n_buckets >= desired_buckets) return 0; } @@ -280,7 +280,7 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, } dev_warn(storage->dev, "Failed to initialize desired amount of buckets, only %d of %d succeeded\n", - n_buckets, desired_copies); + n_buckets, desired_buckets); return 0; } @@ -306,12 +306,12 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage return -EINVAL; } - if (max_size && max_size < desired_copies * stridesize) { - dev_err(storage->dev, "device is too small to hold %d copies\n", desired_copies); + if (max_size && max_size < desired_buckets * stridesize) { + dev_err(storage->dev, "device is too small to hold %d copies\n", desired_buckets); return -EINVAL; } - for (n = 0; n < desired_copies; n++) { + for (n = 0; n < desired_buckets; n++) { offset = storage->offset + n * stridesize; ret = state_backend_bucket_direct_create(storage->dev, storage->path, &bucket, offset, @@ -334,9 +334,9 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage return -EIO; } - if (n_buckets < desired_copies) + if (n_buckets < desired_buckets) dev_warn(storage->dev, "Failed to initialize desired amount of direct buckets, only %d of %d succeeded\n", - n_buckets, desired_copies); + n_buckets, desired_buckets); return 0; } -- cgit v1.2.3 From ec5f8eb29331de692d3ffdb26bbf3b5f47b61e5c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 09:07:19 +0100 Subject: state: backend_storage: rewrite function doc The function documentation for state_storage_file_buckets_init() is not very accurate. Rewrite it. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 1310531dd1..bc531ef991 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -289,8 +289,8 @@ static int state_storage_mtd_buckets_init(struct state_backend_storage *storage, * @param storage Storage object * @return 0 on success, -errno otherwise * - * For blockdevices and other regular files we create direct buckets beginning - * at offset 0. Direct buckets are simple and write data always to offset 0. + * direct buckets are simpler than circular buckets and can be used on blockdevices + * and mtd devices that don't need erase (MRAM). Also used for EEPROMs. */ static int state_storage_file_buckets_init(struct state_backend_storage *storage) { -- cgit v1.2.3 From 75e8aac036d9abefac7d0e1d3d4c1456f1cba134 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 09:09:43 +0100 Subject: state: backend_storage: make locally used variable static Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index bc531ef991..8d0f285f77 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -47,7 +47,7 @@ * when storing a new state we can just write all buckets in order. */ -const unsigned int min_copies_written = 1; +static const unsigned int min_copies_written = 1; /** * state_storage_write - Writes the given data to the storage -- cgit v1.2.3 From 73f3dae29a761034459a41f6300dcf4665f78af5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 10:30:25 +0100 Subject: state: backend_storage: rename more variables Use "buckets" rather than "copies" in variable names. Signed-off-by: Sascha Hauer --- common/state/backend_storage.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 8d0f285f77..a5688aa424 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -47,7 +47,7 @@ * when storing a new state we can just write all buckets in order. */ -static const unsigned int min_copies_written = 1; +static const unsigned int min_buckets_written = 1; /** * state_storage_write - Writes the given data to the storage @@ -60,7 +60,7 @@ static const unsigned int min_copies_written = 1; * operation on all of them. Writes are always in the same sequence. This * ensures, that reading in the same sequence will always return the latest * written valid data first. - * We try to at least write min_copies_written. If this fails we return with an + * We try to at least write min_buckets_written. If this fails we return with an * error. */ int state_storage_write(struct state_backend_storage *storage, @@ -68,7 +68,7 @@ int state_storage_write(struct state_backend_storage *storage, { struct state_backend_storage_bucket *bucket; int ret; - int copies_written = 0; + int buckets_written = 0; if (storage->readonly) return 0; @@ -79,15 +79,15 @@ int state_storage_write(struct state_backend_storage *storage, dev_warn(storage->dev, "Failed to write state backend bucket, %d\n", ret); } else { - ++copies_written; + ++buckets_written; } } - if (copies_written >= min_copies_written) + if (buckets_written >= min_buckets_written) return 0; dev_err(storage->dev, "Failed to write state to at least %d buckets. Successfully written to %d buckets\n", - min_copies_written, copies_written); + min_buckets_written, buckets_written); return -EIO; } -- cgit v1.2.3 From 8f329292316dd38297bb0b95d9f10d7f3935a07b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 15:44:30 +0100 Subject: keystore: implement forgetting secrets To be able to change secrets add a function to forget secrets. Signed-off-by: Sascha Hauer --- crypto/keystore.c | 53 +++++++++++++++++++++++++++++++++-------------- include/crypto/keystore.h | 4 ++++ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/crypto/keystore.c b/crypto/keystore.c index 90b470fe67..f2b25ca6c9 100644 --- a/crypto/keystore.c +++ b/crypto/keystore.c @@ -16,8 +16,8 @@ static LIST_HEAD(keystore_list); struct keystore_key { struct list_head list; - const char *name; - const u8 *secret; + char *name; + u8 *secret; int secret_len; }; @@ -29,6 +29,17 @@ static int keystore_compare(struct list_head *a, struct list_head *b) return strcmp(na, nb); } +static struct keystore_key *get_key(const char *name) +{ + struct keystore_key *key; + + for_each_key(key) + if (!strcmp(name, key->name)) + return key; + + return NULL; +}; + /** * @param[in] name Name of the secret to get * @param[out] secret Double pointer to memory representing the secret, do _not_ free() after use @@ -38,19 +49,17 @@ int keystore_get_secret(const char *name, const u8 **secret, int *secret_len) { struct keystore_key *key; - for_each_key(key) { - if (!strcmp(name, key->name)) { - if (!secret || !secret_len) - return 0; + if (!secret || !secret_len) + return 0; - *secret = key->secret; - *secret_len = key->secret_len; + key = get_key(name); + if (!key) + return -ENOENT; - return 0; - } - } + *secret = key->secret; + *secret_len = key->secret_len; - return -ENOENT; + return 0; } /** @@ -61,11 +70,10 @@ int keystore_get_secret(const char *name, const u8 **secret, int *secret_len) int keystore_set_secret(const char *name, const u8 *secret, int secret_len) { struct keystore_key *key; - int ret; /* check if key is already in store */ - ret = keystore_get_secret(name, NULL, NULL); - if (!ret) + key = get_key(name); + if (key) return -EBUSY; key = xzalloc(sizeof(*key)); @@ -78,3 +86,18 @@ int keystore_set_secret(const char *name, const u8 *secret, int secret_len) return 0; } + +void keystore_forget_secret(const char *name) +{ + struct keystore_key *key; + + key = get_key(name); + if (!key) + return; + + list_del(&key->list); + + free(key->name); + free(key->secret); + free(key); +} diff --git a/include/crypto/keystore.h b/include/crypto/keystore.h index 29915854b8..89d962628b 100644 --- a/include/crypto/keystore.h +++ b/include/crypto/keystore.h @@ -12,6 +12,7 @@ #ifdef CONFIG_CRYPTO_KEYSTORE int keystore_get_secret(const char *name, const u8 **secret, int *secret_len); int keystore_set_secret(const char *name, const u8 *secret, int secret_len); +void keystore_forget_secret(const char *name); #else static inline int keystore_get_secret(const char *name, const u8 **secret, int *secret_len) { @@ -21,6 +22,9 @@ static inline int keystore_set_secret(const char *name, const u8 *secret, int se { return 0; } +static inline void keystore_forget_secret(const char *name) +{ +} #endif #endif -- cgit v1.2.3 From e18b4ad84db80e6a0442fd521f84dd113314e29e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 15:45:52 +0100 Subject: commands: implement keystore command The keystore command provides access to the barebox keystore. Signed-off-by: Sascha Hauer --- commands/Kconfig | 6 ++++ commands/Makefile | 1 + commands/keystore.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 commands/keystore.c diff --git a/commands/Kconfig b/commands/Kconfig index bc0885c69d..6bb47d6363 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1967,6 +1967,12 @@ config CMD_FIRMWARELOAD Provides the "firmwareload" command which deals with devices which need firmware to work. It is also used to upload firmware to FPGA devices. +config CMD_KEYSTORE + depends on CRYPTO_KEYSTORE + bool + prompt "keystore" + help + keystore provides access to the barebox keystore. config CMD_LINUX_EXEC bool "linux exec" diff --git a/commands/Makefile b/commands/Makefile index 601f15fc38..a20c675929 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_CMD_READLINK) += readlink.o obj-$(CONFIG_CMD_LET) += let.o obj-$(CONFIG_CMD_LN) += ln.o obj-$(CONFIG_CMD_CLK) += clk.o +obj-$(CONFIG_CMD_KEYSTORE) += keystore.o obj-$(CONFIG_CMD_TFTP) += tftp.o obj-$(CONFIG_CMD_FILETYPE) += filetype.o obj-$(CONFIG_CMD_BAREBOX_UPDATE)+= barebox-update.o diff --git a/commands/keystore.c b/commands/keystore.c new file mode 100644 index 0000000000..52c4be2639 --- /dev/null +++ b/commands/keystore.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include + +static int do_keystore(int argc, char *argv[]) +{ + int opt; + int ret; + int do_remove = 0; + const char *name; + const char *file = NULL; + char *secret_str = NULL; + void *secret; + int s_len; + + while ((opt = getopt(argc, argv, "rs:f:")) > 0) { + switch (opt) { + case 'r': + do_remove = 1; + break; + case 's': + secret_str = optarg; + break; + case 'f': + file = optarg; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (argc == optind) + return COMMAND_ERROR_USAGE; + + if (!do_remove && !file && !secret_str) + return COMMAND_ERROR_USAGE; + + if (file && secret_str) + return COMMAND_ERROR_USAGE; + + name = argv[optind]; + + if (do_remove) { + keystore_forget_secret(name); + printf("forgotten secret for key %s\n", name); + return 0; + } + + if (file) { + ret = read_file_2(file, &s_len, (void *)&secret_str, FILESIZE_MAX); + if (ret) { + printf("Cannot open %s: %s\n", file, strerror(-ret)); + return 1; + } + } else if (secret_str) { + s_len = strlen(secret_str); + } + + if (s_len & 1) { + printf("invalid secret len. Must be whole bytes\n"); + return 1; + } + + secret = xzalloc(s_len / 2); + ret = hex2bin(secret, secret_str, s_len / 2); + if (ret) { + printf("Cannot convert %s to binary: %s\n", secret_str, strerror(-ret)); + return 1; + } + + ret = keystore_set_secret(name, secret, s_len / 2); + if (ret) + printf("cannot set secret for key %s: %s\n", name, strerror(-ret)); + else + printf("Added secret for key %s\n", name); + + free(secret); + + return ret ? 1 : 0; +} + +BAREBOX_CMD_HELP_START(keystore) +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-r", "remove a key from the keystore") +BAREBOX_CMD_HELP_OPT("-s ", "set a key in the keystore") +BAREBOX_CMD_HELP_OPT("-f ", "set a key in the keystore, read secret from file") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(keystore) + .cmd = do_keystore, + BAREBOX_CMD_DESC("manage keys") + BAREBOX_CMD_OPTS("[-rsf] ") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_keystore_help) +BAREBOX_CMD_END -- cgit v1.2.3 From 3a5ddf3d0db006e9256c8e256e7dc7b4a3f89a14 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 15:46:32 +0100 Subject: commands: state: allow loading state with -l At least for testing purposes it's useful to be able to manually load a state. Add -l option for this. Signed-off-by: Sascha Hauer --- commands/state.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/commands/state.c b/commands/state.c index 4b51759e3e..aded6e71e2 100644 --- a/commands/state.c +++ b/commands/state.c @@ -21,20 +21,23 @@ static int do_state(int argc, char *argv[]) { int opt, ret = 0; struct state *state = NULL; - int do_save = 0; + int do_save = 0, do_load = 0; const char *statename = "state"; - while ((opt = getopt(argc, argv, "s")) > 0) { + while ((opt = getopt(argc, argv, "sl")) > 0) { switch (opt) { case 's': do_save = 1; break; + case 'l': + do_load = 1; + break; default: return COMMAND_ERROR_USAGE; } } - if (!do_save) { + if (!do_save && !do_load) { state_info(); return 0; } @@ -48,7 +51,9 @@ static int do_state(int argc, char *argv[]) return -ENOENT; } - if (do_save) + if (do_load) + ret = state_load(state); + else if (do_save) ret = state_save(state); return ret; -- cgit v1.2.3 From d44fcbf43b4f815cab948d475961710967684663 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 17:40:35 +0100 Subject: crypto: digest: initialize earlier Digests have dependencies and are needed for state which initializes at device_initcall level. To make sure the digests are available for state register them earlier, at coredevice_initcall level. Signed-off-by: Sascha Hauer --- crypto/hmac.c | 2 +- crypto/sha1.c | 2 +- crypto/sha2.c | 2 +- crypto/sha4.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto/hmac.c b/crypto/hmac.c index 05b9b50f12..37b270df7a 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -196,4 +196,4 @@ static int digest_hmac_initcall(void) return 0; } -crypto_initcall(digest_hmac_initcall); +coredevice_initcall(digest_hmac_initcall); diff --git a/crypto/sha1.c b/crypto/sha1.c index cbde4d28e4..f4b2ded0b0 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -303,4 +303,4 @@ static int sha1_digest_register(void) { return digest_algo_register(&m); } -device_initcall(sha1_digest_register); +coredevice_initcall(sha1_digest_register); diff --git a/crypto/sha2.c b/crypto/sha2.c index cb0f11c77e..c62ddb8d25 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -372,4 +372,4 @@ static int sha256_digest_register(void) return digest_algo_register(&m256); } -device_initcall(sha256_digest_register); +coredevice_initcall(sha256_digest_register); diff --git a/crypto/sha4.c b/crypto/sha4.c index 4ce37b73e4..aad8081fa5 100644 --- a/crypto/sha4.c +++ b/crypto/sha4.c @@ -292,4 +292,4 @@ static int sha512_digest_register(void) return digest_algo_register(&m512); } -device_initcall(sha512_digest_register); +coredevice_initcall(sha512_digest_register); -- cgit v1.2.3 From a3764c0b45765a5e7392a3b9a388aa9d9a424b1f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 15:47:12 +0100 Subject: state: backend_raw: alloc digest only when needed Instead of deferring probe just allocate the digest when it's needed. This way the credentials can be added later, possibly on the commandline. Signed-off-by: Sascha Hauer --- common/state/backend_format_raw.c | 112 ++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index a425b636d0..43a5523152 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -35,6 +35,10 @@ struct state_backend_format_raw { /* For outputs */ struct device_d *dev; + + char *secret_name; + int needs_secret; + char *algo; }; struct __attribute__((__packed__)) backend_raw_header { @@ -53,6 +57,43 @@ static inline struct state_backend_format_raw *get_format_raw( return container_of(format, struct state_backend_format_raw, format); } +static int backend_raw_digest_init(struct state_backend_format_raw *raw) +{ + const unsigned char *key; + int key_len; + int ret; + + if (!raw->digest) { + raw->digest = digest_alloc(raw->algo); + if (!raw->digest) { + dev_err(raw->dev, "algo %s not found\n", + raw->algo); + return -ENODEV; + } + raw->digest_length = digest_length(raw->digest); + } + + ret = keystore_get_secret(raw->secret_name, &key, &key_len); + if (ret) { + dev_err(raw->dev, "Could not get secret '%s'\n", + raw->secret_name); + return ret; + } + + ret = digest_set_key(raw->digest, key, key_len); + if (ret) + return ret; + + ret = digest_init(raw->digest); + if (ret) { + dev_err(raw->dev, "Failed to initialize digest: %s\n", + strerror(-ret)); + return ret; + } + + return 0; +} + static int backend_format_raw_verify(struct state_backend_format *format, uint32_t magic, const void * buf, ssize_t *lenp) @@ -86,7 +127,11 @@ static int backend_format_raw_verify(struct state_backend_format *format, return -EINVAL; } - if (backend_raw->digest) { + if (backend_raw->algo) { + ret = backend_raw_digest_init(backend_raw); + if (ret) + return ret; + d_len = digest_length(backend_raw->digest); } @@ -108,26 +153,18 @@ static int backend_format_raw_verify(struct state_backend_format *format, *lenp = header->data_len + sizeof(*header); - if (backend_raw->digest) { - struct digest *d = backend_raw->digest; + if (backend_raw->algo) { const void *hmac = data + header->data_len; - ret = digest_init(d); - if (ret) { - dev_err(backend_raw->dev, "Failed to initialize digest, %d\n", - ret); - return ret; - } - /* hmac over header and data */ - ret = digest_update(d, buf, sizeof(*header) + header->data_len); + ret = digest_update(backend_raw->digest, buf, sizeof(*header) + header->data_len); if (ret) { dev_err(backend_raw->dev, "Failed to update digest, %d\n", ret); return ret; } - ret = digest_verify(d, hmac); + ret = digest_verify(backend_raw->digest, hmac); if (ret < 0) { dev_err(backend_raw->dev, "Failed to verify data, hmac, %d\n", ret); @@ -195,25 +232,20 @@ static int backend_format_raw_pack(struct state_backend_format *format, header->header_crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t)); - if (backend_raw->digest) { - struct digest *d = backend_raw->digest; - - ret = digest_init(d); - if (ret) { - dev_err(backend_raw->dev, "Failed to initialize digest for packing, %d\n", - ret); - goto out_free; - } + if (backend_raw->algo) { + ret = backend_raw_digest_init(backend_raw); + if (ret) + return ret; /* hmac over header and data */ - ret = digest_update(d, buf, sizeof(*header) + size_data); + ret = digest_update(backend_raw->digest, buf, sizeof(*header) + size_data); if (ret) { dev_err(backend_raw->dev, "Failed to update digest for packing, %d\n", ret); goto out_free; } - ret = digest_final(d, hmac); + ret = digest_final(backend_raw->digest, hmac); if (ret < 0) { dev_err(backend_raw->dev, "Failed to finish digest for packing, %d\n", ret); @@ -243,11 +275,9 @@ static int backend_format_raw_init_digest(struct state_backend_format_raw *raw, struct device_node *root, const char *secret_name) { - struct digest *digest; struct property *p; const char *algo; - const unsigned char *key; - int key_len, ret; + int ret; p = of_find_property(root, "algo", NULL); if (!p) /* does not exist */ @@ -263,30 +293,7 @@ static int backend_format_raw_init_digest(struct state_backend_format_raw *raw, return -EINVAL; } - ret = keystore_get_secret(secret_name, &key, &key_len); - if (ret == -ENOENT) { /* -ENOENT == does not exist */ - dev_info(raw->dev, "Could not get secret '%s' - probe deferred\n", - secret_name); - return -EPROBE_DEFER; - } else if (ret) { - return ret; - } - - digest = digest_alloc(algo); - if (!digest) { - dev_info(raw->dev, "algo %s not found - probe deferred\n", - algo); - return -EPROBE_DEFER; - } - - ret = digest_set_key(digest, key, key_len); - if (ret) { - digest_free(digest); - return ret; - } - - raw->digest = digest; - raw->digest_length = digest_length(digest); + raw->algo = xstrdup(algo); return 0; } @@ -304,15 +311,14 @@ int backend_format_raw_create(struct state_backend_format **format, raw->dev = dev; ret = backend_format_raw_init_digest(raw, node, secret_name); - if (ret == -EPROBE_DEFER) { - return ret; - } else if (ret) { + if (ret) { dev_err(raw->dev, "Failed initializing digest for raw format, %d\n", ret); free(raw); return ret; } + raw->secret_name = xstrdup(secret_name); raw->format.pack = backend_format_raw_pack; raw->format.unpack = backend_format_raw_unpack; raw->format.verify = backend_format_raw_verify; -- cgit v1.2.3 From 95e2e0e487a083a4c9bf13a1918120fbc2a9cd2b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 15:48:26 +0100 Subject: state: backend_circular: Set minumum writesize to 8 NOR flashes have a write size of 1. With this the metadata may end up on non-4-byte-aligned offsets. Force the minimum writesize to 8 so that the metadata is always at aligned offsets. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 58fffd18e3..5a525f68e1 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -475,6 +475,9 @@ int state_backend_bucket_circular_create(struct device_d *dev, const char *path, struct state_backend_storage_bucket_circular *circ; int ret; + if (writesize < 8) + writesize = 8; + circ = xzalloc(sizeof(*circ)); circ->eraseblock = eraseblock; circ->writesize = writesize; -- cgit v1.2.3 From a081eb840ed12eff6256a5497771a8c3168fc95b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Mar 2017 17:52:48 +0100 Subject: state: backend bucket circular: Explain metadata Explain why we have metadata and where it is used. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 5a525f68e1..d99ba39126 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -61,6 +61,11 @@ struct state_backend_storage_bucket_circular { struct device_d *dev; }; +/* + * The metadata will be written directly before writesize aligned offsets. + * When searching backwards through the pages it allows us to find the + * beginning of the data. + */ struct __attribute__((__packed__)) state_backend_storage_bucket_circular_meta { uint32_t magic; uint32_t written_length; -- cgit v1.2.3 From 0c7436753c73e71ee512e5ed8029e7ccceedcd89 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 27 Mar 2017 10:14:38 +0200 Subject: state: Allow to load without authentification Sometimes it's useful to be able to load a state even when it can't be authentificated. Add an option for this. Signed-off-by: Sascha Hauer --- commands/state.c | 16 ++++++++++++---- common/state/backend_format_dtb.c | 4 ++-- common/state/backend_format_raw.c | 6 +++--- common/state/backend_storage.c | 6 ++++-- common/state/state.c | 14 ++++++++++++-- common/state/state.h | 9 +++++++-- include/state.h | 1 + 7 files changed, 41 insertions(+), 15 deletions(-) diff --git a/commands/state.c b/commands/state.c index aded6e71e2..c57a906ff0 100644 --- a/commands/state.c +++ b/commands/state.c @@ -23,8 +23,9 @@ static int do_state(int argc, char *argv[]) struct state *state = NULL; int do_save = 0, do_load = 0; const char *statename = "state"; + int no_auth = 0; - while ((opt = getopt(argc, argv, "sl")) > 0) { + while ((opt = getopt(argc, argv, "sln")) > 0) { switch (opt) { case 's': do_save = 1; @@ -32,6 +33,9 @@ static int do_state(int argc, char *argv[]) case 'l': do_load = 1; break; + case 'n': + no_auth = 1; + break; default: return COMMAND_ERROR_USAGE; } @@ -51,10 +55,14 @@ static int do_state(int argc, char *argv[]) return -ENOENT; } - if (do_load) - ret = state_load(state); - else if (do_save) + if (do_load) { + if (no_auth) + ret = state_load_no_auth(state); + else + ret = state_load(state); + } else if (do_save) { ret = state_save(state); + } return ret; } diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c index d7b01729bc..55fa1fc597 100644 --- a/common/state/backend_format_dtb.c +++ b/common/state/backend_format_dtb.c @@ -40,7 +40,7 @@ static inline struct state_backend_format_dtb *get_format_dtb(struct static int state_backend_format_dtb_verify(struct state_backend_format *format, uint32_t magic, const void * buf, - ssize_t *lenp) + ssize_t *lenp, enum state_flags flags) { struct state_backend_format_dtb *fdtb = get_format_dtb(format); struct device_node *root; @@ -81,7 +81,7 @@ static int state_backend_format_dtb_unpack(struct state_backend_format *format, int ret; if (!fdtb->root) { - state_backend_format_dtb_verify(format, 0, buf, &len); + state_backend_format_dtb_verify(format, 0, buf, &len, 0); } ret = state_from_node(state, fdtb->root, 0); diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index 43a5523152..232856a209 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -96,7 +96,7 @@ static int backend_raw_digest_init(struct state_backend_format_raw *raw) static int backend_format_raw_verify(struct state_backend_format *format, uint32_t magic, const void * buf, - ssize_t *lenp) + ssize_t *lenp, enum state_flags flags) { uint32_t crc; struct backend_raw_header *header; @@ -127,7 +127,7 @@ static int backend_format_raw_verify(struct state_backend_format *format, return -EINVAL; } - if (backend_raw->algo) { + if (backend_raw->algo && !(flags & STATE_FLAG_NO_AUTHENTIFICATION)) { ret = backend_raw_digest_init(backend_raw); if (ret) return ret; @@ -153,7 +153,7 @@ static int backend_format_raw_verify(struct state_backend_format *format, *lenp = header->data_len + sizeof(*header); - if (backend_raw->algo) { + if (backend_raw->algo && !(flags & STATE_FLAG_NO_AUTHENTIFICATION)) { const void *hmac = data + header->data_len; /* hmac over header and data */ diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index a5688aa424..9ed6ad79ac 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -127,6 +127,7 @@ refresh: * @param magic state magic value * @param buf The newly allocated data area will be stored in this pointer * @param len The resulting length of the buffer + * @param flags flags controlling how to load state * @return 0 on success, -errno otherwise. buf and len will be set to valid * values on success. * @@ -137,7 +138,8 @@ refresh: */ int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, void **buf, ssize_t *len) + uint32_t magic, void **buf, ssize_t *len, + enum state_flags flags) { struct state_backend_storage_bucket *bucket, *bucket_used = NULL; int ret; @@ -157,7 +159,7 @@ int state_storage_read(struct state_backend_storage *storage, * Verify the buffer crcs. The buffer length is passed in the len argument, * .verify overwrites it with the length actually used. */ - ret = format->verify(format, magic, bucket->buf, &bucket->len); + ret = format->verify(format, magic, bucket->buf, &bucket->len, flags); if (!ret && !bucket_used) bucket_used = bucket; } diff --git a/common/state/state.c b/common/state/state.c index 476e3ee08e..1232ff3207 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -78,14 +78,14 @@ out: * we read is checked for integrity by the formatter. After that we unpack the * data into our state. */ -int state_load(struct state *state) +static int state_do_load(struct state *state, enum state_flags flags) { void *buf; ssize_t len; int ret; ret = state_storage_read(&state->storage, state->format, - state->magic, &buf, &len); + state->magic, &buf, &len, flags); if (ret) { dev_err(&state->dev, "Failed to read state with format %s, %d\n", state->format->name, ret); @@ -106,6 +106,16 @@ out: return ret; } +int state_load(struct state *state) +{ + return state_do_load(state, 0); +} + +int state_load_no_auth(struct state *state) +{ + return state_do_load(state, STATE_FLAG_NO_AUTHENTIFICATION); +} + static int state_format_init(struct state *state, const char *backend_format, struct device_node *node, const char *state_name) { diff --git a/common/state/state.h b/common/state/state.h index a2737abeb6..5e240c4773 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -5,6 +5,10 @@ struct state; struct mtd_info_user; +enum state_flags { + STATE_FLAG_NO_AUTHENTIFICATION = (1 << 0), +}; + /** * state_backend_storage_bucket - This class describes a single backend storage * object copy @@ -53,7 +57,7 @@ struct state_backend_storage_bucket { */ struct state_backend_format { int (*verify) (struct state_backend_format * format, uint32_t magic, - const void * buf, ssize_t *lenp); + const void * buf, ssize_t *lenp, enum state_flags flags); int (*pack) (struct state_backend_format * format, struct state * state, void ** buf, ssize_t * len); int (*unpack) (struct state_backend_format * format, @@ -223,7 +227,8 @@ int state_storage_write(struct state_backend_storage *storage, const void * buf, ssize_t len); int state_storage_read(struct state_backend_storage *storage, struct state_backend_format *format, - uint32_t magic, void **buf, ssize_t *len); + uint32_t magic, void **buf, ssize_t *len, + enum state_flags flags); static inline struct state_uint32 *to_state_uint32(struct state_variable *s) { diff --git a/include/state.h b/include/state.h index bc9a574093..63164f92e5 100644 --- a/include/state.h +++ b/include/state.h @@ -18,6 +18,7 @@ struct state *state_by_name(const char *name); struct state *state_by_node(const struct device_node *node); int state_get_name(const struct state *state, char const **name); +int state_load_no_auth(struct state *state); int state_load(struct state *state); int state_save(struct state *state); void state_info(void); -- cgit v1.2.3 From 13d85dfe2a47bed91724ce73f9929a09ff739090 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 29 Mar 2017 11:08:32 +0200 Subject: state: Update documentation - explain what buckets are - rework text about storage backends - explain redundancy concept Signed-off-by: Sascha Hauer --- Documentation/user/state.rst | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Documentation/user/state.rst b/Documentation/user/state.rst index 5dd5c486e2..73c4be8159 100644 --- a/Documentation/user/state.rst +++ b/Documentation/user/state.rst @@ -23,16 +23,35 @@ available, ``raw`` and ``dtb``. Both format the state data differently. Basically these are serializers. The raw serializer additionally supports a HMAC algorithm to detect manipulations. +The data is always stored in a logical unit called ``bucket``. A ``bucket`` has +its own size depending on some external contraints. These contraints are listed +in more detail below depending on the used memory type and storage backend. A +``bucket`` stores exactly one state. A default number of three buckets is used +to store data redundantely. + +Redundancy +---------- + +The state framework is safe against powerfailures during write operations. To +archieve that multiple buckets are stored to disk. When writing all buckets are +written in order. When reading, the buckets are read in order and the first +one found that passes CRC tests is used. When all data is read the buckets +containing invalid or outdated data are written with the data just read. Also +NAND blocks need cleanup due to excessive bitflips are rewritten in this step. +With this it is made sure that after successful initialization of a state the +data on the storage device is consistent and redundant. + Storage Backends ---------------- -The serialized data can be stored to different backends which are automatically -selected depending on the defined backend in the devicetree. Currently two -implementations exist, ``circular`` and ``direct``. ``circular`` writes the -data sequentially on the backend storage device. Each save is appended until -the storage area is full. It then erases the block and starts from offset 0. -``circular`` is used for MTD devices with erase functionality. ``direct`` -writes the data directly to the file without erasing. +The serialized data can be stored to different backends. Currently two +implementations exist, ``circular`` and ``direct``. The state framework automatically +selects the correct backend depending on the storage medium. Media requiring +erase operations (NAND, NOR flash) use the ``circular`` backend, others use the ``direct`` +backend. The purpose of the ``circular`` backend is to save erase cycles which may +wear out the flash blocks. It continuously fills eraseblocks with updated data +and only when an eraseblock if fully written erases it and starts over writing +new data to the same eraseblock again. For all backends multiple copies are written to handle read errors. -- cgit v1.2.3 From ccb5b80125a0b95e8954260eddd7f40a61c8e65e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 29 Mar 2017 14:29:12 +0200 Subject: state: Do not load state during state_new_from_node The caller of state_new_from_node() may have it's own ideas what to do when loading the state fails, so do not load it in the initialization function, but instead let the caller do it. Signed-off-by: Sascha Hauer --- common/state/state.c | 5 ----- drivers/misc/state.c | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/common/state/state.c b/common/state/state.c index 1232ff3207..bdeda2e5a1 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -632,11 +632,6 @@ struct state *state_new_from_node(struct device_node *node, char *path, goto out_release_state; } - ret = state_load(state); - if (ret) { - dev_warn(&state->dev, "Failed to load persistent state, continuing with defaults, %d\n", ret); - } - dev_info(&state->dev, "New state registered '%s'\n", alias); return state; diff --git a/drivers/misc/state.c b/drivers/misc/state.c index b43aee60fe..98ed42e757 100644 --- a/drivers/misc/state.c +++ b/drivers/misc/state.c @@ -26,6 +26,7 @@ static int state_probe(struct device_d *dev) struct device_node *np = dev->device_node; struct state *state; bool readonly = false; + int ret; state = state_new_from_node(np, NULL, 0, 0, readonly); if (IS_ERR(state)) { @@ -35,6 +36,11 @@ static int state_probe(struct device_d *dev) return ret; } + ret = state_load(state); + if (ret) + dev_warn(dev, "Failed to load persistent state, continuing with defaults, %d\n", + ret); + return 0; } -- cgit v1.2.3 From 9d6d91931afb8f038a58d18471dccd65bdd95cfd Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 29 Mar 2017 16:27:01 +0200 Subject: state: Remove -EUCLEAN check from userspace tool The state code is used for the userspace tool aswell, kept in sync manually. This patch only introduces a change for the userspace tool, not for barebox. In Linux userspace there is no direct possibility to check for -EUCLEAN. To indirectly check for -EUCLEAN the state tool reads the number of corrected bits before and after reading a block. Unfortunately it does not take the number of acceptable bitflips into account, but instead returns -EUCLEAN even when only a single bitflip occurred on a whole page. To be correct the algorithm must be more complicated: We would have to read the bitflip_threshold from sysfs. This value is per ECC step (often 512 byte), not per page. We would have to read the page in ECC step size chunks, testing for bitflips lower than the threshold for each chunk. Even if we would do that, there's still another issue. The eccstats ioctl delivers the eccstats for the whole device, so a concurrent reader would falsify the result. Let's decide that this is not worth the hassle and assume that no device has enough uptime that a cleanup in barebox is not sufficient. Signed-off-by: Sascha Hauer --- common/state/backend_bucket_circular.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index d99ba39126..5279ec9ce2 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -171,33 +171,12 @@ static int state_mtd_peb_read(struct state_backend_storage_bucket_circular *circ dev_dbg(circ->dev, "Read state from %ld length %zd\n", offset, len); - ret = ioctl(circ->fd, ECCGETSTATS, &stat1); - if (ret) - nostats = true; ret = read_full(circ->fd, buf, len); if (ret < 0) { dev_err(circ->dev, "Failed to read circular storage len %zd, %d\n", len, ret); free(buf); - return ret; - } - - if (nostats) - return 0; - - ret = ioctl(circ->fd, ECCGETSTATS, &stat2); - if (ret) - return 0; - - if (stat2.failed - stat1.failed > 0) { - ret = -EUCLEAN; - dev_dbg(circ->dev, "PEB %u has ECC error, forcing rewrite\n", - circ->eraseblock); - } else if (stat2.corrected - stat1.corrected > 0) { - ret = -EUCLEAN; - dev_dbg(circ->dev, "PEB %u is unclean, forcing rewrite\n", - circ->eraseblock); } return ret; -- cgit v1.2.3 From e627903d59b7f7d085e53a0dc9ed942bcc63dff9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 30 Mar 2017 16:33:26 +0200 Subject: state: find device node from device path, not from device node path The device node path may change from the internal device tree to the one Linux is started with, so using this path to fixup the tree is not very robust. Instead, use of_find_node_by_devpath() which has been created for exactly this purpose. Signed-off-by: Sascha Hauer --- common/state/state.c | 10 +++++----- common/state/state.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/state/state.c b/common/state/state.c index bdeda2e5a1..94a423b825 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -461,7 +461,7 @@ static int of_state_fixup(struct device_node *root, void *ctx) } /* backend phandle */ - backend_node = of_find_node_by_path_from(root, state->of_backend_path); + backend_node = of_find_node_by_devpath(root, state->backend_path); if (!backend_node) { ret = -ENODEV; goto out; @@ -529,7 +529,7 @@ void state_release(struct state *state) unregister_device(&state->dev); state_storage_free(&state->storage); state_format_free(state->format); - free(state->of_backend_path); + free(state->backend_path); free(state->of_path); free(state); } @@ -591,6 +591,8 @@ struct state *state_new_from_node(struct device_node *node, char *path, } } + state->backend_path = xstrdup(path); + ret = of_property_read_string(node, "backend-type", &backend_type); if (ret) { goto out_release_state; @@ -617,8 +619,6 @@ struct state *state_new_from_node(struct device_node *node, char *path, if (ret) goto out_release_state; - state->of_backend_path = xstrdup(of_path); - if (readonly) state_backend_set_readonly(state); @@ -693,7 +693,7 @@ void state_info(void) if (state->format) printf("(backend: %s, path: %s)\n", state->format->name, - state->of_backend_path); + state->backend_path); else printf("(no backend)\n"); } diff --git a/common/state/state.h b/common/state/state.h index 5e240c4773..ead8cc88c1 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -104,7 +104,7 @@ struct state { struct state_backend_format *format; struct state_backend_storage storage; - char *of_backend_path; + char *backend_path; }; enum state_convert { -- cgit v1.2.3 From 7b3d284f4bad78d61e9f5d32ec5aa1efc19ce733 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 3 Apr 2017 22:51:58 +0200 Subject: state: remove unused variable type enum state_variable_type is never used. Remove it. Signed-off-by: Sascha Hauer --- common/state/state.c | 1 - common/state/state.h | 11 ----------- common/state/state_variables.c | 5 ----- 3 files changed, 17 deletions(-) diff --git a/common/state/state.c b/common/state/state.c index 94a423b825..8369aedac6 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -271,7 +271,6 @@ static int state_convert_node_variable(struct state *state, sv->name = name; sv->start = start_size[0]; - sv->type = vtype->type; state_add_var(state, sv); } else { sv = state_find_var(state, name); diff --git a/common/state/state.h b/common/state/state.h index ead8cc88c1..81aaec23b6 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -114,20 +114,10 @@ enum state_convert { STATE_CONVERT_FIXUP, }; -enum state_variable_type { - STATE_TYPE_INVALID = 0, - STATE_TYPE_ENUM, - STATE_TYPE_U8, - STATE_TYPE_U32, - STATE_TYPE_MAC, - STATE_TYPE_STRING, -}; - struct state_variable; /* A variable type (uint32, enum32) */ struct variable_type { - enum state_variable_type type; const char *type_name; struct list_head list; int (*export) (struct state_variable *, struct device_node *, @@ -141,7 +131,6 @@ struct variable_type { /* instance of a single variable */ struct state_variable { struct state *state; - enum state_variable_type type; struct list_head list; const char *name; unsigned int start; diff --git a/common/state/state_variables.c b/common/state/state_variables.c index fd072a0c27..5b8e6284d9 100644 --- a/common/state/state_variables.c +++ b/common/state/state_variables.c @@ -439,31 +439,26 @@ static struct state_variable *state_string_create(struct state *state, static struct variable_type types[] = { { - .type = STATE_TYPE_U8, .type_name = "uint8", .export = state_uint32_export, .import = state_uint32_import, .create = state_uint8_create, }, { - .type = STATE_TYPE_U32, .type_name = "uint32", .export = state_uint32_export, .import = state_uint32_import, .create = state_uint32_create, }, { - .type = STATE_TYPE_ENUM, .type_name = "enum32", .export = state_enum32_export, .import = state_enum32_import, .create = state_enum32_create, }, { - .type = STATE_TYPE_MAC, .type_name = "mac", .export = state_mac_export, .import = state_mac_import, .create = state_mac_create, }, { - .type = STATE_TYPE_STRING, .type_name = "string", .export = state_string_export, .import = state_string_import, -- cgit v1.2.3