diff --git a/common/bootchooser.c b/common/bootchooser.c index 83b15e0..c47c734 100644 --- a/common/bootchooser.c +++ b/common/bootchooser.c @@ -52,12 +52,12 @@ static int last_boot_successful; struct bootchooser { - struct bootentry entry; struct list_head targets; struct bootchooser_target *last_chosen; struct state *state; char *state_prefix; + int refs; int verbose; int dryrun; @@ -345,11 +345,15 @@ bootchooser_target_set_priority(target, -1); } +static struct bootchooser *bootchooser; + /** - * bootchooser_get - get a bootchooser instance + * bootchooser_get - get a reference to the bootchooser * - * This evaluates the different globalvars and eventually state variables, - * creates a bootchooser instance from it and returns it. + * When no bootchooser is initialized this function allocates the bootchooser + * and initializes it with the different globalvars and state variables. The + * bootchooser is returned. Subsequent calls will return a reference to the same + * bootchooser. */ struct bootchooser *bootchooser_get(void) { @@ -360,6 +364,11 @@ uint32_t last_chosen; static int attempts_resetted; + if (bootchooser) { + bootchooser->refs++; + return bootchooser; + } + bc = xzalloc(sizeof(*bc)); if (*state_prefix) { @@ -474,6 +483,10 @@ } + bootchooser = bc; + + bootchooser->refs = 1; + return bc; err: @@ -529,16 +542,26 @@ } /** - * bootchooser_put - release a bootchooser instance + * bootchooser_put - return a bootchooser reference * @bc: The bootchooser instance * - * This releases a bootchooser instance and the memory associated with it. + * This returns a reference to the bootchooser. If it is the last reference the + * bootchooser is saved and the associated memory is freed. + * + * Return: 0 for success or a negative error code. An error can occur when + * bootchooser_save fails to write to the storage, nevertheless the + * bootchooser reference is still released. */ int bootchooser_put(struct bootchooser *bc) { struct bootchooser_target *target, *tmp; int ret; + bc->refs--; + + if (bc->refs) + return 0; + ret = bootchooser_save(bc); if (ret) pr_err("Failed to save bootchooser state: %s\n", strerror(-ret)); @@ -553,6 +576,8 @@ free(bc); + bootchooser = NULL; + return ret; } @@ -841,20 +866,26 @@ static int bootchooser_entry_boot(struct bootentry *entry, int verbose, int dryrun) { - struct bootchooser *bc = container_of(entry, struct bootchooser, - entry); + struct bootchooser *bc; + int ret; + + bc = bootchooser_get(); + if (IS_ERR(bc)) + return PTR_ERR(bc); + bc->verbose = verbose; bc->dryrun = dryrun; - return bootchooser_boot(bc); + ret = bootchooser_boot(bc); + + bootchooser_put(bc); + + return ret; } static void bootchooser_release(struct bootentry *entry) { - struct bootchooser *bc = container_of(entry, struct bootchooser, - entry); - - bootchooser_put(bc); + free(entry); } /** @@ -869,6 +900,7 @@ static int bootchooser_add_entry(struct bootentries *entries, const char *name) { struct bootchooser *bc; + struct bootentry *entry; if (strcmp(name, "bootchooser")) return 0; @@ -877,12 +909,16 @@ if (IS_ERR(bc)) return PTR_ERR(bc); - bc->entry.boot = bootchooser_entry_boot; - bc->entry.release = bootchooser_release; - bc->entry.title = xstrdup("bootchooser"); - bc->entry.description = xstrdup("bootchooser"); + entry = xzalloc(sizeof(*entry)); - bootentries_add_entry(entries, &bc->entry); + entry->boot = bootchooser_entry_boot; + entry->release = bootchooser_release; + entry->title = xstrdup("bootchooser"); + entry->description = xstrdup("bootchooser"); + + bootentries_add_entry(entries, entry); + + bootchooser_put(bc); return 1; } diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 0529421..4b71d87 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -155,8 +155,6 @@ { int ret; off_t offset = suboffset; - struct mtd_ecc_stats stat1, stat2; - bool nostats = false; offset += (off_t)circ->eraseblock * circ->mtd->erasesize; @@ -480,7 +478,8 @@ circ->fd = open(path, O_RDWR); if (circ->fd < 0) { pr_err("Failed to open circular bucket '%s'\n", path); - return -errno; + ret = -errno; + goto out_free; } #endif @@ -489,7 +488,7 @@ dev_info(dev, "Not using eraseblock %u, it is marked as bad (%d)\n", circ->eraseblock, ret); ret = -EIO; - goto out_free; + goto out_close; } circ->bucket.read = state_backend_bucket_circular_read; @@ -499,13 +498,15 @@ ret = state_backend_bucket_circular_init(*bucket); if (ret) - goto out_free; + goto out_close; return 0; -out_free: +out_close: #ifndef __BAREBOX__ close(circ->fd); +out_free: + free(circ->mtd); #endif free(circ); diff --git a/common/state/state.c b/common/state/state.c index 1597197..54c5723 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -83,7 +83,7 @@ } /** - * state_load - Loads a state from the backend + * state_do_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. diff --git a/drivers/of/base.c b/drivers/of/base.c index 0d8289d..b082f0c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2274,6 +2274,18 @@ return basprintf("[0x%llx]", addr); } + /* + * Special workaround for the of partition binding. In the old binding + * the partitions are directly under the hardware devicenode whereas in + * the new binding the partitions are in an extra subnode with + * "fixed-partitions" compatible. We skip this extra subnode from the + * reproducible name to get the same name for both bindings. + */ + if (node->parent && + of_device_is_compatible(node->parent, "fixed-partitions")) { + node = node->parent; + } + na = of_n_addr_cells(node); offset = of_read_number(reg, na);