[PATCH] log: make global data relocatable
Thomas Weißschuh
thomas.weissschuh at linutronix.de
Mon Feb 12 10:32:56 CET 2024
When `gd` is relocated during `spl_relocate_stack_gd()` the
doubly-linked circular list in the `log_head` member is broken.
The last element of the list should point back to the initial
`list_head`, but as the initial `list_head` is moved the pointer becomes
stale. As a result the loop in `log_dispatch` would never finish.
Migrate the list to a singly-linked non-circular one which is
easily relocatable.
This should also remove the special handling introduced in
commit e7595aa350ae ("x86: Allow logging to be used in SPL reliably").
Signed-off-by: Thomas Weißschuh <thomas.weissschuh at linutronix.de>
---
common/log.c | 15 +++++++++------
include/asm-generic/global_data.h | 2 +-
include/log.h | 2 +-
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/common/log.c b/common/log.c
index b2de57fcb3b8..098d40c86d81 100644
--- a/common/log.c
+++ b/common/log.c
@@ -109,7 +109,7 @@ struct log_device *log_device_find_by_name(const char *drv_name)
{
struct log_device *ldev;
- list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ for (ldev = gd->log_head; ldev; ldev = ldev->sibling_node) {
if (!strcmp(drv_name, ldev->drv->name))
return ldev;
}
@@ -218,7 +218,7 @@ static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args)
/* Emit message */
gd->processing_msg = true;
- list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ for (ldev = gd->log_head; ldev; ldev = ldev->sibling_node) {
if ((ldev->flags & LOGDF_ENABLE) &&
log_passes_filters(ldev, rec)) {
if (!rec->msg) {
@@ -400,7 +400,7 @@ static struct log_device *log_find_device_by_drv(struct log_driver *drv)
{
struct log_device *ldev;
- list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ for (ldev = gd->log_head; ldev; ldev = ldev->sibling_node) {
if (ldev->drv == drv)
return ldev;
}
@@ -433,13 +433,16 @@ int log_init(void)
struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
const int count = ll_entry_count(struct log_driver, log_driver);
struct log_driver *end = drv + count;
+ struct log_device **log_head;
+
+ gd->log_head = NULL;
+ log_head = (struct log_device **)&gd->log_head;
/*
* We cannot add runtime data to the driver since it is likely stored
* in rodata. Instead, set up a 'device' corresponding to each driver.
* We only support having a single device for each driver.
*/
- INIT_LIST_HEAD((struct list_head *)&gd->log_head);
while (drv < end) {
struct log_device *ldev;
@@ -451,8 +454,8 @@ int log_init(void)
INIT_LIST_HEAD(&ldev->filter_head);
ldev->drv = drv;
ldev->flags = drv->flags;
- list_add_tail(&ldev->sibling_node,
- (struct list_head *)&gd->log_head);
+ *log_head = ldev;
+ log_head = &ldev->sibling_node;
drv++;
}
gd->flags |= GD_FLG_LOG_READY;
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index fcc3c6e14ca3..a9a407b801c2 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -404,7 +404,7 @@ struct global_data {
/**
* @log_head: list of logging devices
*/
- struct list_head log_head;
+ struct log_device *log_head;
/**
* @log_fmt: bit mask for logging format
*
diff --git a/include/log.h b/include/log.h
index 6e84f080ef3d..961233684d2a 100644
--- a/include/log.h
+++ b/include/log.h
@@ -455,7 +455,7 @@ struct log_device {
unsigned short flags;
struct log_driver *drv;
struct list_head filter_head;
- struct list_head sibling_node;
+ struct log_device *sibling_node;
};
enum {
---
base-commit: e8f2404e093daf6cc3ac2b3233e3c6770d13e371
change-id: 20240208-spl-logging-14a1257c3147
Best regards,
--
Thomas Weißschuh <thomas.weissschuh at linutronix.de>
More information about the U-Boot
mailing list