-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
llext: flush logging before unloading extensions #77289
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can happen with any extension using logging, not just ones that happen to use memory mapping. @nordic-krch any thoughts?
One option would be for format string in these cases should be copied along with the varargs used. Any pointers in the varargs should likely also be copied over. (E.g. using "%s" with a string parameter in the loaded extensions rodata section)
Alternatively the logging needs to be flushed while unloading an extension perhaps.
So perhaps in llext_unload...
- Lock everything to prevent preemption on all cores
- Flush all logging
- Unmap/release extension memory
I support @teburd's suggestion to flush logging. For logging to NOT copy the format strings and parameters into the buffer, there are specific conditions that need to be met first. Maybe avoid those conditions so you don't have to flush? |
@dcpleung @teburd yes, I was also thinking about this as a potentially more universal solution. But AFAICS there's currently no API to do that, right? Would this be enough?
|
hmm, just tested, this doesn't quite work unfortunately. The |
This seems to be used in a few places... while (log_process()) {} You'd also need to perhaps disable interrupts while flushing though to avoid issues key = irq_lock();
while (log_process()) {}
irq_unlock(key); |
no, didn't help either, unfortunately |
@teburd btw, where do you see such examples? I only see this when panicking and in a user-space logging test |
Ok maybe a new, possibly pointless idea... Temporarily boost the priority of the logging thread and tell it to run, locking all the interrupts and junk while unloading the extension. #include <zephyr/logging/log_ctrl.h>
extern k_thread logging_thread;
void llext_log_flush(void)
{
int cur_prio;
/* boost logging thread prio */
cur_prio = k_thread_priority_get(&logging_thread);
k_thread_priority_set(&logging_thread, K_HIGHEST_THREAD_PRIO);
log_thread_trigger();
k_thread_priority_set(&logging_thread, cur_prio);
}
void llext_unload(...)
{
int key, cur_prio;
key = irq_lock();
/* boost current thread priority */
cur_prio = k_thread_get_priority(&k_current_get());
k_thread_set_priority(&k_current_get(), K_HIGHEST_THREAD_PRIO+1);
llext_log_flush();
/* unload work done here */
k_thread_set_priority(&k_current_get(), cur_prio);
irq_unlock(key);
} |
Re-assigned as this now no longer modifies logging code, but I'd still appreciate feedback from @nordic-krch on the approach |
6efcab3
to
ad630d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
I would also be in favor of moving it to a log_flush
function so that it would be universally available, if the approach is acceptable to the logging subsystem.
https://github.com/zephyrproject-rtos/zephyr/actions/runs/10597173924/job/29368081193?pr=77289 looks like a regression, possibly from #76820 |
subsys/llext/llext.c
Outdated
|
||
static void llext_log_flush(void) | ||
{ | ||
#if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_MINIMAL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should only be done when CONFIG_LOG_MODE_DEFERRED
is enabled. Both minimal and immediate modes do not have log processing thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dcpleung you're right!
dec0986
to
a44d375
Compare
Extensions could have used logging, when log processing is deferred, the logging thread can run after the extension has been unloaded and thereby access invalid memory addresses. Make sure to flush all logs before unloading extensions. Signed-off-by: Tom Burdick <thomas.burdick@intel.com> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
When logging is deferred it can happen that the logger thread attempts to emit a log entry when the memory, containing log data has been unmapped. This can happen e.g. when an LLEXT object was running from dynamically mapped memory, used logging and was unloaded and unmapped before the logger thread had a chance to emit the entry. To avoid this problem, check that the memory, where the format string is residing, hasn't been unmapped. If that does happen, ignore the error and drop the log entry.
This is required to fix thesofproject/sof#9371 . The fix isn't particularly elegant, it's mixing two hardly related APIs: logging and memory mapping. The key problem is that when logging is deferred, memory that it's trying to access might be gone by then. Ideas for a more generic solution are welcome, but - as usually - if properly fixing this requires significant API extensions or changes, maybe we can apply this or something similar as a temporary fix, while working out a generic solution.