diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2017-04-07 09:59:38 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2017-04-07 09:59:38 +0200 |
commit | 5d834decbe062273393acfcf172fdd29ead6a166 (patch) | |
tree | 1eeea5cf915f7779aaa77421327caaa7525e91e0 /common/state/state.c | |
parent | 53adf0648c330357103e4a7103c3d7f05c0c4bcf (diff) | |
parent | 7b3d284f4bad78d61e9f5d32ec5aa1efc19ce733 (diff) | |
download | barebox-5d834decbe062273393acfcf172fdd29ead6a166.tar.gz barebox-5d834decbe062273393acfcf172fdd29ead6a166.tar.xz |
Merge branch 'for-next/state'
Diffstat (limited to 'common/state/state.c')
-rw-r--r-- | common/state/state.c | 189 |
1 files changed, 153 insertions, 36 deletions
diff --git a/common/state/state.c b/common/state/state.c index 02bb1bb24a..8369aedac6 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -34,6 +34,125 @@ /* list of all registered state instances */ static LIST_HEAD(state_list); +/** + * Save the state + * @param state + * @return + */ +int state_save(struct state *state) +{ + void *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. + */ +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, flags); + 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; +} + +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) +{ + int ret; + + if (!backend_format || !strcmp(backend_format, "raw")) { + ret = backend_format_raw_create(&state->format, node, + state_name, &state->dev); + } else if (!strcmp(backend_format, "dtb")) { + ret = backend_format_dtb_create(&state->format, &state->dev); + } else { + dev_err(&state->dev, "Invalid backend format %s\n", + backend_format); + return -EINVAL; + } + + if (ret && ret != -EPROBE_DEFER) + dev_err(&state->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) + return; + + if (format->free) + format->free(format); +} + +void state_backend_set_readonly(struct state *state) +{ + state_storage_set_readonly(&state->storage); +} + static struct state *state_new(const char *name) { struct state *state; @@ -152,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); @@ -328,21 +446,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_devpath(root, state->backend_path); if (!backend_node) { ret = -ENODEV; goto out; @@ -353,9 +471,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 +485,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 +526,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->backend); + state_storage_free(&state->storage); + state_format_free(state->format); + free(state->backend_path); free(state->of_path); free(state); } @@ -452,19 +572,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", @@ -473,6 +590,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; @@ -490,14 +609,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->backend, &state->dev, node, - backend_type, path, alias, of_path, offset, + ret = state_format_init(state, backend_type, node, alias); + if (ret) + goto out_release_state; + + ret = state_storage_init(state, 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) { @@ -509,11 +631,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; @@ -572,10 +689,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->backend_path); else printf("(no backend)\n"); } |