diff options
Diffstat (limited to 'common/state')
-rw-r--r-- | common/state/Makefile | 2 | ||||
-rw-r--r-- | common/state/backend_bucket_circular.c | 4 | ||||
-rw-r--r-- | common/state/backend_bucket_direct.c | 28 | ||||
-rw-r--r-- | common/state/backend_format_dtb.c | 6 | ||||
-rw-r--r-- | common/state/backend_format_raw.c | 17 | ||||
-rw-r--r-- | common/state/backend_storage.c | 28 | ||||
-rw-r--r-- | common/state/state.c | 96 | ||||
-rw-r--r-- | common/state/state.h | 32 | ||||
-rw-r--r-- | common/state/state_variables.c | 13 |
9 files changed, 159 insertions, 67 deletions
diff --git a/common/state/Makefile b/common/state/Makefile index fcf9add52c..93215dd069 100644 --- a/common/state/Makefile +++ b/common/state/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += state.o obj-y += state_variables.o obj-y += backend_format_dtb.o diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 735510e0d3..2ac5bf6a82 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -62,7 +62,7 @@ struct state_backend_storage_bucket_circular { #endif /* For outputs */ - struct device_d *dev; + struct device *dev; }; /* @@ -456,7 +456,7 @@ static int bucket_circular_is_block_bad(struct state_backend_storage_bucket_circ } #endif -int state_backend_bucket_circular_create(struct device_d *dev, const char *path, +int state_backend_bucket_circular_create(struct device *dev, const char *path, struct state_backend_storage_bucket **bucket, unsigned int eraseblock, ssize_t writesize, diff --git a/common/state/backend_bucket_direct.c b/common/state/backend_bucket_direct.c index 4522f0170f..03c752d6fe 100644 --- a/common/state/backend_bucket_direct.c +++ b/common/state/backend_bucket_direct.c @@ -17,7 +17,7 @@ #include <libfile.h> #include <linux/kernel.h> #include <malloc.h> -#include <printk.h> +#include <linux/printk.h> #include "state.h" @@ -29,7 +29,7 @@ struct state_backend_storage_bucket_direct { int fd; - struct device_d *dev; + struct device *dev; }; struct __attribute__((__packed__)) state_backend_storage_bucket_direct_meta { @@ -52,7 +52,7 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket struct state_backend_storage_bucket_direct *direct = get_bucket_direct(bucket); struct state_backend_storage_bucket_direct_meta meta; - uint32_t read_len; + uint32_t read_len, header_len = 0; void *buf; int ret; @@ -72,13 +72,15 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket return -EINVAL; } + + header_len = sizeof(meta); } else { if (meta.magic != ~0 && !!meta.magic) bucket->wrong_magic = 1; if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) { - dev_err(direct->dev, "No meta data header found\n"); dev_dbg(direct->dev, "Enable backward compatibility or increase stride size\n"); - return -EINVAL; + return dev_err_state_init(direct->dev, meta.magic ? -EINVAL : -ENOMEDIUM, + "No meta data header found\n"); } read_len = direct->max_size; if (lseek(direct->fd, direct->offset, SEEK_SET) != @@ -87,12 +89,16 @@ static int state_backend_bucket_direct_read(struct state_backend_storage_bucket -errno); return -errno; } + } buf = xmalloc(read_len); if (!buf) return -ENOMEM; + dev_dbg(direct->dev, "Read state from %lld length %d\n", (long long) direct->offset, + header_len + read_len); + ret = read_full(direct->fd, buf, read_len); if (ret < 0) { dev_err(direct->dev, "Failed to read from file, %d\n", ret); @@ -112,6 +118,7 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket { struct state_backend_storage_bucket_direct *direct = get_bucket_direct(bucket); + size_t header_len = 0; int ret; struct state_backend_storage_bucket_direct_meta meta; @@ -129,6 +136,8 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket dev_err(direct->dev, "Failed to write metadata to file, %d\n", ret); return ret; } + + header_len = sizeof(meta); } else { if (!IS_ENABLED(CONFIG_STATE_BACKWARD_COMPATIBLE)) { dev_dbg(direct->dev, "Too small stride size: must skip metadata! Increase stride size\n"); @@ -148,6 +157,9 @@ static int state_backend_bucket_direct_write(struct state_backend_storage_bucket return ret; } + dev_dbg(direct->dev, "Written state to offset %lld length %zu data length %zu\n", + (long long)direct->offset, len + header_len, len); + return 0; } @@ -162,14 +174,14 @@ static void state_backend_bucket_direct_free(struct free(direct); } -int state_backend_bucket_direct_create(struct device_d *dev, const char *path, +int state_backend_bucket_direct_create(struct device *dev, const char *path, struct state_backend_storage_bucket **bucket, - off_t offset, ssize_t max_size) + off_t offset, ssize_t max_size, bool readonly) { int fd; struct state_backend_storage_bucket_direct *direct; - fd = open(path, O_RDWR); + fd = open(path, readonly ? O_RDONLY : O_RDWR); if (fd < 0) { dev_err(dev, "Failed to open file '%s', %d\n", path, -errno); return -errno; diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c index 48f30db1f5..b41b896aac 100644 --- a/common/state/backend_format_dtb.c +++ b/common/state/backend_format_dtb.c @@ -28,7 +28,7 @@ struct state_backend_format_dtb { struct device_node *root; /* For outputs */ - struct device_d *dev; + struct device *dev; }; static inline struct state_backend_format_dtb *get_format_dtb(struct @@ -59,7 +59,7 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format, fdtb->root = NULL; } - root = of_unflatten_dtb(buf); + root = of_unflatten_dtb(buf, dtb_len); if (IS_ERR(root)) { dev_err(fdtb->dev, "Failed to unflatten dtb from buffer with length %zd, %ld\n", len, PTR_ERR(root)); @@ -131,7 +131,7 @@ static void state_backend_format_dtb_free(struct state_backend_format *format) } int backend_format_dtb_create(struct state_backend_format **format, - struct device_d *dev) + struct device *dev) { struct state_backend_format_dtb *dtb; diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index 5a71149d34..105f7dd444 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -16,14 +16,12 @@ */ #include <common.h> -#include <common.h> #include <crypto/keystore.h> #include <digest.h> #include <linux/kernel.h> #include <malloc.h> #include <crc.h> #include <of.h> -#include <crc.h> #include "state.h" @@ -34,7 +32,7 @@ struct state_backend_format_raw { unsigned int digest_length; /* For outputs */ - struct device_d *dev; + struct device *dev; char *secret_name; int needs_secret; @@ -115,11 +113,10 @@ static int backend_format_raw_verify(struct state_backend_format *format, header = (struct backend_raw_header *)buf; crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t)); - if (crc != header->header_crc) { - dev_err(backend_raw->dev, "Error, invalid header crc in raw format, calculated 0x%08x, found 0x%08x\n", + if (crc != header->header_crc) + return dev_err_state_init(backend_raw->dev, header->header_crc ? -EINVAL : -ENOMEDIUM, + "header crc in raw format, calculated 0x%08x, found 0x%08x\n", crc, header->header_crc); - return -EINVAL; - } if (magic && magic != header->magic) { dev_err(backend_raw->dev, "Error, invalid magic in raw format 0x%08x, should be 0x%08x\n", @@ -183,6 +180,7 @@ static int backend_format_raw_unpack(struct state_backend_format *format, const struct backend_raw_header *header; const void *data; struct state_backend_format_raw *backend_raw = get_format_raw(format); + int ret = 0; header = (const struct backend_raw_header *)buf; data = buf + sizeof(*header); @@ -191,12 +189,13 @@ static int backend_format_raw_unpack(struct state_backend_format *format, if (sv->start + sv->size > header->data_len) { dev_err(backend_raw->dev, "State variable ends behind valid data, %s\n", sv->name); + ret = -ENOSPC; continue; } memcpy(sv->raw, data + sv->start, sv->size); } - return 0; + return ret; } static int backend_format_raw_pack(struct state_backend_format *format, @@ -300,7 +299,7 @@ static int backend_format_raw_init_digest(struct state_backend_format_raw *raw, int backend_format_raw_create(struct state_backend_format **format, struct device_node *node, const char *secret_name, - struct device_d *dev) + struct device *dev) { struct state_backend_format_raw *raw; int ret; diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index fe7e89e8fb..df81902bf7 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -21,7 +21,7 @@ #include <linux/mtd/mtd-abi.h> #include <sys/stat.h> #include <malloc.h> -#include <printk.h> +#include <linux/printk.h> #include "state.h" @@ -144,6 +144,7 @@ int state_storage_read(struct state_backend_storage *storage, enum state_flags flags) { struct state_backend_storage_bucket *bucket, *bucket_used = NULL; + int zerobuckets = 0, totalbuckets = 0; int ret; dev_dbg(storage->dev, "Checking redundant buckets...\n"); @@ -152,30 +153,35 @@ int state_storage_read(struct state_backend_storage *storage, * one we want to use. */ list_for_each_entry(bucket, &storage->buckets, bucket_list) { + totalbuckets++; + ret = bucket->read(bucket, &bucket->buf, &bucket->len); - if (ret == -EUCLEAN) + if (ret == -EUCLEAN) { bucket->needs_refresh = 1; - else if (ret) + } else if (ret) { + if (ret == -ENOMEDIUM) + zerobuckets++; continue; + } /* * 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, flags); - if (!ret && !bucket_used) + if (ret == -ENOMEDIUM) + zerobuckets++; + else if (!ret && !bucket_used) bucket_used = bucket; - if (ret) + else if (ret) dev_info(storage->dev, "Ignoring broken bucket %d@0x%08llx...\n", bucket->num, (long long) bucket->offset); } dev_dbg(storage->dev, "Checking redundant buckets finished.\n"); - if (!bucket_used) { - dev_err(storage->dev, "Failed to find any valid state copy in any bucket\n"); - - return -ENOENT; - } + if (!bucket_used) + return dev_err_state_init(storage->dev, zerobuckets == totalbuckets ? -ENOMEDIUM : -ENOENT, + "no valid state copy in any bucket\n"); dev_info(storage->dev, "Using bucket %d@0x%08llx\n", bucket_used->num, (long long) bucket_used->offset); @@ -326,7 +332,7 @@ static int state_storage_file_buckets_init(struct state_backend_storage *storage offset = storage->offset + n * stridesize; ret = state_backend_bucket_direct_create(storage->dev, storage->path, &bucket, offset, - stridesize); + stridesize, storage->readonly); if (ret) { dev_warn(storage->dev, "Failed to create direct bucket at '%s' offset %lld\n", storage->path, (long long) offset); diff --git a/common/state/state.c b/common/state/state.c index d42920985d..219309d715 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -21,8 +21,10 @@ #include <fs.h> #include <crc.h> #include <init.h> +#include <block.h> #include <linux/err.h> #include <linux/list.h> +#include <linux/uuid.h> #include <linux/mtd/mtd-abi.h> #include <malloc.h> @@ -101,8 +103,8 @@ static int state_do_load(struct state *state, enum state_flags flags) 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); + dev_err_state_init(&state->dev, ret, "format %s read failed\n", + state->format->name); goto out; } @@ -271,9 +273,8 @@ static int state_convert_node_variable(struct state *state, if (conv == STATE_CONVERT_FROM_NODE_CREATE) { sv = vtype->create(state, name, node, vtype); if (IS_ERR(sv)) { + dev_err(&state->dev, "failed to create %s: %pe\n", name, sv); ret = PTR_ERR(sv); - dev_err(&state->dev, "failed to create %s: %s\n", name, - strerror(-ret)); goto out_free; } @@ -334,8 +335,10 @@ static int state_convert_node_variable(struct state *state, goto out; return 0; - out_free:free(name); - out: return ret; +out_free: + free(name); +out: + return ret; } struct device_node *state_to_node(struct state *state, @@ -362,7 +365,8 @@ struct device_node *state_to_node(struct state *state, } return root; - out: of_delete_node(root); +out: + of_delete_node(root); return ERR_PTR(ret); } @@ -557,12 +561,12 @@ static int of_state_fixup(struct device_node *root, void *ctx) goto out; /* delete existing node */ - if (node) - of_delete_node(node); + of_delete_node(node); return 0; - out: of_delete_node(new_node); +out: + of_delete_node(new_node); return ret; } @@ -579,6 +583,22 @@ void state_release(struct state *state) free(state); } +#ifdef __BAREBOX__ +static char *cdev_to_devpath(struct cdev *cdev, off_t *offset, size_t *size) +{ + /* + * We only accept partitions exactly mapping the barebox-state, + * but dt-utils may need to set non-zero values here + */ + *offset = 0; + *size = 0; + + return basprintf("/dev/%s", cdev->name); +} +#endif + +static guid_t barebox_state_partition_guid = BAREBOX_STATE_PARTITION_GUID; + /* * state_new_from_node - create a new state instance from a device_node * @@ -595,12 +615,13 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) const char *alias; uint32_t stridesize; struct device_node *partition_node; - off_t offset = 0; - size_t size = 0; + struct cdev *cdev; + off_t offset; + size_t size; alias = of_alias_get(node); if (!alias) { - pr_err("State node %s does not have an alias in the /aliases/ node\n", node->full_name); + pr_err("State node %pOF does not have an alias in the /aliases/ node\n", node); return ERR_PTR(-EINVAL); } @@ -615,11 +636,8 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) goto out_release_state; } -#ifdef __BAREBOX__ - ret = of_find_path_by_node(partition_node, &state->backend_path, 0); -#else - ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size); -#endif + cdev = of_cdev_find(partition_node); + ret = PTR_ERR_OR_ZERO(cdev); if (ret) { if (ret != -EPROBE_DEFER) dev_err(&state->dev, "state failed to parse path to backend: %s\n", @@ -627,6 +645,22 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) goto out_release_state; } + /* Is the backend referencing an on-disk partitionable block device? */ + if (cdev_is_block_disk(cdev)) { + cdev = cdev_find_child_by_gpt_typeuuid(cdev, &barebox_state_partition_guid); + if (IS_ERR(cdev)) { + ret = -EINVAL; + goto out_release_state; + } + + pr_debug("%pOF: backend GPT partition looked up via PartitionTypeGUID\n", + node); + } + + state->backend_path = cdev_to_devpath(cdev, &offset, &size); + + pr_debug("%pOF: backend resolved to %s\n", node, state->backend_path); + state->backend_reproducible_name = of_get_reproducible_name(partition_node); ret = of_property_read_string(node, "backend-type", &backend_type); @@ -650,14 +684,14 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) if (ret) goto out_release_state; + if (readonly) + state_backend_set_readonly(state); + ret = state_storage_init(state, state->backend_path, offset, size, stridesize, storage_type); if (ret) goto out_release_state; - if (readonly) - state_backend_set_readonly(state); - ret = state_from_node(state, node, 1); if (ret) { goto out_release_state; @@ -701,10 +735,12 @@ struct state *state_by_name(const char *name) * * @node The of node of the state instance */ -struct state *state_by_node(const struct device_node *node) +struct state *state_by_node(struct device_node *node) { struct state *state; + of_device_ensure_probed(node); + list_for_each_entry(state, &state_list, list) { if (!strcmp(state->of_path, node->full_name)) return state; @@ -713,6 +749,22 @@ struct state *state_by_node(const struct device_node *node) return NULL; } +/* + * state_by_alias - find a state instance by alias + * + * @name The DT alias of the state instance + */ +struct state *state_by_alias(const char *alias) +{ + struct device_node *node; + + node = of_find_node_by_alias(NULL, alias); + if (!node) + return NULL; + + return state_by_node(node); +} + int state_read_mac(struct state *state, const char *name, u8 *buf) { struct state_variable *svar; diff --git a/common/state/state.h b/common/state/state.h index 1881d92ea7..f0c5b1de41 100644 --- a/common/state/state.h +++ b/common/state/state.h @@ -1,5 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <linux/types.h> #include <linux/list.h> +#include <linux/err.h> #include <driver.h> struct state; @@ -87,7 +90,7 @@ struct state_backend_storage { struct list_head buckets; /* For outputs */ - struct device_d *dev; + struct device *dev; const char *name; @@ -102,7 +105,7 @@ struct state_backend_storage { struct state { struct list_head list; /* Entry to enqueue on list of states */ - struct device_d dev; + struct device dev; char *of_path; const char *name; uint32_t magic; @@ -199,21 +202,21 @@ struct device_node *state_to_node(struct state *state, enum state_convert conv); int backend_format_raw_create(struct state_backend_format **format, struct device_node *node, const char *secret_name, - struct device_d *dev); + struct device *dev); int backend_format_dtb_create(struct state_backend_format **format, - struct device_d *dev); + struct device *dev); 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); void state_add_var(struct state *state, struct state_variable *var); struct variable_type *state_find_type_by_name(const char *name); -int state_backend_bucket_circular_create(struct device_d *dev, const char *path, +int state_backend_bucket_circular_create(struct device *dev, const char *path, struct state_backend_storage_bucket **bucket, unsigned int eraseblock, ssize_t writesize, struct mtd_info_user *mtd_uinfo); -int state_backend_bucket_cached_create(struct device_d *dev, +int state_backend_bucket_cached_create(struct device *dev, struct state_backend_storage_bucket *raw, struct state_backend_storage_bucket **out); struct state_variable *state_find_var(struct state *state, const char *name); @@ -221,9 +224,9 @@ struct digest *state_backend_format_raw_get_digest(struct state_backend_format *format); void state_backend_set_readonly(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, +int state_backend_bucket_direct_create(struct device *dev, const char *path, struct state_backend_storage_bucket **bucket, - off_t offset, ssize_t max_size); + off_t offset, ssize_t max_size, bool readonly); int state_storage_write(struct state_backend_storage *storage, const void * buf, ssize_t len); int state_storage_read(struct state_backend_storage *storage, @@ -266,3 +269,16 @@ static inline int state_string_copy_to_raw(struct state_string *string, return 0; } + +#ifdef DEBUG +#define MSG_STATE_ZERO_INIT MSG_INFO +#else +#define MSG_STATE_ZERO_INIT MSG_DEBUG +#endif + +#define dev_err_state_init(dev, ret, fmt, ...) ({ \ + int __ret = (ret); \ + __dev_printf(__ret == -ENOMEDIUM ? MSG_STATE_ZERO_INIT : MSG_ERR, \ + (dev), "init error: %pe: " fmt, ERR_PTR(__ret), ##__VA_ARGS__); \ + __ret; \ +}) diff --git a/common/state/state_variables.c b/common/state/state_variables.c index 66c66f38bd..77946206cd 100644 --- a/common/state/state_variables.c +++ b/common/state/state_variables.c @@ -21,7 +21,7 @@ #include <linux/types.h> #include <malloc.h> #include <net.h> -#include <printk.h> +#include <linux/printk.h> #include <of.h> #include <stdio.h> @@ -180,6 +180,8 @@ static int state_enum32_export(struct state_variable *var, str += sprintf(str, "%s", enum32->names[i]) + 1; ret = of_set_property(node, "names", prop, len, 1); + if (ret) + return ret; free(prop); @@ -261,7 +263,8 @@ static struct state_variable *state_enum32_create(struct state *state, } return &enum32->var; - out: for (i--; i >= 0; i--) +out: + for (i--; i >= 0; i--) free((char *)enum32->names[i]); free(enum32->names); free(enum32); @@ -327,7 +330,8 @@ static struct state_variable *state_mac_create(struct state *state, } return &mac->var; - out: free(mac); +out: + free(mac); return ERR_PTR(ret); } @@ -442,7 +446,8 @@ static struct state_variable *state_string_create(struct state *state, } return &string->var; - out: free(string); +out: + free(string); return ERR_PTR(ret); } |