Import of kernel-5.14.0-611.38.1.el9_7

This commit is contained in:
almalinux-bot-kernel 2026-03-12 04:35:32 +00:00
parent 39d42eb2b3
commit fd14d7a12e
16 changed files with 468 additions and 216 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 7
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 611.36.1
RHEL_RELEASE = 611.38.1
#
# ZSTREAM

View File

@ -440,7 +440,9 @@ int mlxsw_sp_mr_route_add(struct mlxsw_sp_mr_table *mr_table,
rhashtable_remove_fast(&mr_table->route_ht,
&mr_orig_route->ht_node,
mlxsw_sp_mr_route_ht_params);
mutex_lock(&mr_table->route_list_lock);
list_del(&mr_orig_route->node);
mutex_unlock(&mr_table->route_list_lock);
mlxsw_sp_mr_route_destroy(mr_table, mr_orig_route);
}

View File

@ -58,7 +58,7 @@ struct macvlan_port {
struct macvlan_source_entry {
struct hlist_node hlist;
struct macvlan_dev *vlan;
struct macvlan_dev __rcu *vlan;
unsigned char addr[6+2] __aligned(sizeof(u16));
struct rcu_head rcu;
};
@ -145,7 +145,7 @@ static struct macvlan_source_entry *macvlan_hash_lookup_source(
hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (ether_addr_equal_64bits(entry->addr, addr) &&
entry->vlan == vlan)
rcu_access_pointer(entry->vlan) == vlan)
return entry;
}
return NULL;
@ -167,7 +167,7 @@ static int macvlan_hash_add_source(struct macvlan_dev *vlan,
return -ENOMEM;
ether_addr_copy(entry->addr, addr);
entry->vlan = vlan;
RCU_INIT_POINTER(entry->vlan, vlan);
h = &port->vlan_source_hash[macvlan_eth_hash(addr)];
hlist_add_head_rcu(&entry->hlist, h);
vlan->macaddr_count++;
@ -186,6 +186,7 @@ static void macvlan_hash_add(struct macvlan_dev *vlan)
static void macvlan_hash_del_source(struct macvlan_source_entry *entry)
{
RCU_INIT_POINTER(entry->vlan, NULL);
hlist_del_rcu(&entry->hlist);
kfree_rcu(entry, rcu);
}
@ -389,7 +390,7 @@ static void macvlan_flush_sources(struct macvlan_port *port,
int i;
hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist)
if (entry->vlan == vlan)
if (rcu_access_pointer(entry->vlan) == vlan)
macvlan_hash_del_source(entry);
vlan->macaddr_count = 0;
@ -432,9 +433,14 @@ static bool macvlan_forward_source(struct sk_buff *skb,
hlist_for_each_entry_rcu(entry, h, hlist) {
if (ether_addr_equal_64bits(entry->addr, addr)) {
if (entry->vlan->flags & MACVLAN_FLAG_NODST)
struct macvlan_dev *vlan = rcu_dereference(entry->vlan);
if (!vlan)
continue;
if (vlan->flags & MACVLAN_FLAG_NODST)
consume = true;
macvlan_forward_source_one(skb, entry->vlan);
macvlan_forward_source_one(skb, vlan);
}
}
@ -1675,7 +1681,7 @@ static int macvlan_fill_info_macaddr(struct sk_buff *skb,
struct macvlan_source_entry *entry;
hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (entry->vlan != vlan)
if (rcu_access_pointer(entry->vlan) != vlan)
continue;
if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr))
return 1;

View File

@ -148,18 +148,26 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *file)
if (has_lock && (ctx->flags & IORING_SETUP_SQPOLL)) {
struct io_sq_data *sq = ctx->sq_data;
struct task_struct *tsk;
rcu_read_lock();
tsk = rcu_dereference(sq->thread);
/*
* sq->thread might be NULL if we raced with the sqpoll
* thread termination.
*/
if (sq->thread) {
if (tsk) {
get_task_struct(tsk);
rcu_read_unlock();
getrusage(tsk, RUSAGE_SELF, &sq_usage);
put_task_struct(tsk);
sq_pid = sq->task_pid;
sq_cpu = sq->sq_cpu;
getrusage(sq->thread, RUSAGE_SELF, &sq_usage);
sq_total_time = (sq_usage.ru_stime.tv_sec * 1000000
+ sq_usage.ru_stime.tv_usec);
sq_work_time = sq->work_time;
} else {
rcu_read_unlock();
}
}

View File

@ -2856,7 +2856,7 @@ static __cold void io_ring_exit_work(struct work_struct *work)
struct task_struct *tsk;
io_sq_thread_park(sqd);
tsk = sqd->thread;
tsk = sqpoll_task_locked(sqd);
if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
io_wq_cancel_cb(tsk->io_uring->io_wq,
io_cancel_ctx_cb, ctx, true);
@ -3093,7 +3093,7 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
s64 inflight;
DEFINE_WAIT(wait);
WARN_ON_ONCE(sqd && sqd->thread != current);
WARN_ON_ONCE(sqd && sqpoll_task_locked(sqd) != current);
if (!current->io_uring)
return;

View File

@ -323,6 +323,8 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
if (ctx->flags & IORING_SETUP_SQPOLL) {
sqd = ctx->sq_data;
if (sqd) {
struct task_struct *tsk;
/*
* Observe the correct sqd->lock -> ctx->uring_lock
* ordering. Fine to drop uring_lock here, we hold
@ -332,8 +334,9 @@ static __cold int io_register_iowq_max_workers(struct io_ring_ctx *ctx,
mutex_unlock(&ctx->uring_lock);
mutex_lock(&sqd->lock);
mutex_lock(&ctx->uring_lock);
if (sqd->thread)
tctx = sqd->thread->io_uring;
tsk = sqpoll_task_locked(sqd);
if (tsk)
tctx = tsk->io_uring;
}
} else {
tctx = current->io_uring;

View File

@ -30,7 +30,7 @@ enum {
void io_sq_thread_unpark(struct io_sq_data *sqd)
__releases(&sqd->lock)
{
WARN_ON_ONCE(sqd->thread == current);
WARN_ON_ONCE(sqpoll_task_locked(sqd) == current);
/*
* Do the dance but not conditional clear_bit() because it'd race with
@ -45,24 +45,32 @@ void io_sq_thread_unpark(struct io_sq_data *sqd)
void io_sq_thread_park(struct io_sq_data *sqd)
__acquires(&sqd->lock)
{
WARN_ON_ONCE(sqd->thread == current);
struct task_struct *tsk;
atomic_inc(&sqd->park_pending);
set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
mutex_lock(&sqd->lock);
if (sqd->thread)
wake_up_process(sqd->thread);
tsk = sqpoll_task_locked(sqd);
if (tsk) {
WARN_ON_ONCE(tsk == current);
wake_up_process(tsk);
}
}
void io_sq_thread_stop(struct io_sq_data *sqd)
{
WARN_ON_ONCE(sqd->thread == current);
struct task_struct *tsk;
WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state));
set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
mutex_lock(&sqd->lock);
if (sqd->thread)
wake_up_process(sqd->thread);
tsk = sqpoll_task_locked(sqd);
if (tsk) {
WARN_ON_ONCE(tsk == current);
wake_up_process(tsk);
}
mutex_unlock(&sqd->lock);
wait_for_completion(&sqd->exited);
}
@ -280,7 +288,8 @@ static int io_sq_thread(void *data)
/* offload context creation failed, just exit */
if (!current->io_uring) {
mutex_lock(&sqd->lock);
sqd->thread = NULL;
rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
mutex_unlock(&sqd->lock);
goto err_out;
}
@ -385,7 +394,8 @@ static int io_sq_thread(void *data)
io_sq_tw(&retry_list, UINT_MAX);
io_uring_cancel_generic(true, sqd);
sqd->thread = NULL;
rcu_assign_pointer(sqd->thread, NULL);
put_task_struct(current);
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags);
io_run_task_work();
@ -494,7 +504,11 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
goto err_sqpoll;
}
sqd->thread = tsk;
mutex_lock(&sqd->lock);
rcu_assign_pointer(sqd->thread, tsk);
mutex_unlock(&sqd->lock);
get_task_struct(tsk);
ret = io_uring_alloc_task_context(tsk, ctx);
wake_up_new_task(tsk);
if (ret)
@ -504,7 +518,6 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
ret = -EINVAL;
goto err;
}
return 0;
err_sqpoll:
complete(&ctx->sq_data->exited);
@ -520,10 +533,13 @@ __cold int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx,
int ret = -EINVAL;
if (sqd) {
struct task_struct *tsk;
io_sq_thread_park(sqd);
/* Don't set affinity for a dying thread */
if (sqd->thread)
ret = io_wq_cpu_affinity(sqd->thread->io_uring, mask);
tsk = sqpoll_task_locked(sqd);
if (tsk)
ret = io_wq_cpu_affinity(tsk->io_uring, mask);
io_sq_thread_unpark(sqd);
}

View File

@ -8,7 +8,7 @@ struct io_sq_data {
/* ctx's that are using this sqd */
struct list_head ctx_list;
struct task_struct *thread;
struct task_struct __rcu *thread;
struct wait_queue_head wait;
unsigned sq_thread_idle;
@ -29,3 +29,9 @@ void io_sq_thread_unpark(struct io_sq_data *sqd);
void io_put_sq_data(struct io_sq_data *sqd);
void io_sqpoll_wait_sq(struct io_ring_ctx *ctx);
int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, cpumask_var_t mask);
static inline struct task_struct *sqpoll_task_locked(struct io_sq_data *sqd)
{
return rcu_dereference_protected(sqd->thread,
lockdep_is_held(&sqd->lock));
}

View File

@ -20,6 +20,19 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
(con->flags & CON_BOOT) ? "boot" : "", \
con->name, con->index, ##__VA_ARGS__)
/*
* Identify if legacy printing is forced in a dedicated kthread. If
* true, all printing via console lock occurs within a dedicated
* legacy printer thread. The only exception is on panic, after the
* nbcon consoles have had their chance to print the panic messages
* first.
*/
#ifdef CONFIG_PREEMPT_RT
# define force_legacy_kthread() (true)
#else
# define force_legacy_kthread() (false)
#endif
#ifdef CONFIG_PRINTK
#ifdef CONFIG_PRINTK_CALLER
@ -45,16 +58,6 @@ enum printk_info_flags {
extern struct printk_ringbuffer *prb;
extern bool printk_threads_enabled;
extern bool have_legacy_console;
extern bool have_boot_console;
/*
* Specifies if the console lock/unlock dance is needed for console
* printing. If @have_boot_console is true, the nbcon consoles will
* be printed serially along with the legacy consoles because nbcon
* consoles cannot print simultaneously with boot consoles.
*/
#define printing_via_unlock (have_legacy_console || have_boot_console)
__printf(4, 0)
int vprintk_store(int facility, int level,
@ -79,6 +82,7 @@ bool printk_percpu_data_ready(void);
} while (0)
void defer_console_output(void);
bool is_printk_legacy_deferred(void);
u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags);
@ -164,7 +168,6 @@ static inline void nbcon_kthread_wake(struct console *con)
static inline void nbcon_kthread_wake(struct console *con) { }
static inline void nbcon_kthread_create(struct console *con) { }
#define printk_threads_enabled (false)
#define printing_via_unlock (false)
/*
* In !PRINTK builds we still export console_sem
@ -175,6 +178,7 @@ static inline void nbcon_kthread_create(struct console *con) { }
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
static inline bool printk_percpu_data_ready(void) { return false; }
static inline bool is_printk_legacy_deferred(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
@ -190,6 +194,112 @@ static inline bool console_is_usable(struct console *con, short flags,
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
extern bool have_nbcon_console;
extern bool have_legacy_console;
extern bool legacy_allow_panic_sync;
/**
* struct console_flush_type - Define available console flush methods
* @nbcon_atomic: Flush directly using nbcon_atomic() callback
* @nbcon_offload: Offload flush to printer thread
* @legacy_direct: Call the legacy loop in this context
* @legacy_offload: Offload the legacy loop into IRQ
*
* Note that the legacy loop also flushes the nbcon consoles.
*/
struct console_flush_type {
bool nbcon_atomic;
bool nbcon_offload;
bool legacy_direct;
bool legacy_offload;
};
extern bool console_irqwork_blocked;
/*
* Identify which console flushing methods should be used in the context of
* the caller.
*/
static inline void printk_get_console_flush_type(struct console_flush_type *ft)
{
memset(ft, 0, sizeof(*ft));
switch (nbcon_get_default_prio()) {
case NBCON_PRIO_NORMAL:
if (have_nbcon_console && !have_boot_console) {
if (printk_threads_enabled && !console_irqwork_blocked)
ft->nbcon_offload = true;
else
ft->nbcon_atomic = true;
/*
* nbcon atomic printing should happen during shutdown,
* since the printing threads may not get a chance to
* print the final messages, see printk_kthread_shutdown()
*/
if (ft->nbcon_offload && system_state > SYSTEM_RUNNING) {
ft->nbcon_atomic = true;
ft->nbcon_offload = false;
}
}
/* Legacy consoles are flushed directly when possible. */
if (have_legacy_console || have_boot_console) {
if (!is_printk_legacy_deferred())
ft->legacy_direct = true;
else if (!console_irqwork_blocked)
ft->legacy_offload = true;
}
break;
case NBCON_PRIO_EMERGENCY:
if (have_nbcon_console && !have_boot_console)
ft->nbcon_atomic = true;
/* Legacy consoles are flushed directly when possible. */
if (have_legacy_console || have_boot_console) {
if (!is_printk_legacy_deferred())
ft->legacy_direct = true;
else if (!console_irqwork_blocked)
ft->legacy_offload = true;
}
break;
case NBCON_PRIO_PANIC:
/*
* In panic, the nbcon consoles will directly print. But
* only allowed if there are no boot consoles.
*/
if (have_nbcon_console && !have_boot_console)
ft->nbcon_atomic = true;
if (have_legacy_console || have_boot_console) {
/*
* This is the same decision as NBCON_PRIO_NORMAL
* except that offloading never occurs in panic.
*
* Note that console_flush_on_panic() will flush
* legacy consoles anyway, even if unsafe.
*/
if (!is_printk_legacy_deferred())
ft->legacy_direct = true;
/*
* In panic, if nbcon atomic printing occurs,
* the legacy consoles must remain silent until
* explicitly allowed.
*/
if (ft->nbcon_atomic && !legacy_allow_panic_sync)
ft->legacy_direct = false;
}
break;
default:
WARN_ON_ONCE(1);
break;
}
}
extern struct printk_buffers printk_shared_pbufs;
/**

View File

@ -209,8 +209,9 @@ bool printk_threads_enabled __ro_after_init;
/**
* nbcon_context_try_acquire_direct - Try to acquire directly
* @ctxt: The context of the caller
* @cur: The current console state
* @ctxt: The context of the caller
* @cur: The current console state
* @is_reacquire: This acquire is a reacquire
*
* Acquire the console when it is released. Also acquire the console when
* the current owner has a lower priority and the console is in a safe state.
@ -220,25 +221,38 @@ bool printk_threads_enabled __ro_after_init;
*
* Errors:
*
* -EPERM: A panic is in progress and this is not the panic CPU.
* Or the current owner or waiter has the same or higher
* priority. No acquire method can be successful in
* this case.
* -EPERM: A panic is in progress and this is neither the panic
* CPU nor is this a reacquire. Or the current owner or
* waiter has the same or higher priority. No acquire
* method can be successful in these cases.
*
* -EBUSY: The current owner has a lower priority but the console
* in an unsafe state. The caller should try using
* the handover acquire method.
*/
static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
struct nbcon_state *cur)
struct nbcon_state *cur, bool is_reacquire)
{
unsigned int cpu = smp_processor_id();
struct console *con = ctxt->console;
struct nbcon_state new;
do {
if (other_cpu_in_panic())
/*
* Panic does not imply that the console is owned. However,
* since all non-panic CPUs are stopped during panic(), it
* is safer to have them avoid gaining console ownership.
*
* If this acquire is a reacquire (and an unsafe takeover
* has not previously occurred) then it is allowed to attempt
* a direct acquire in panic. This gives console drivers an
* opportunity to perform any necessary cleanup if they were
* interrupted by the panic CPU while printing.
*/
if (other_cpu_in_panic() &&
(!is_reacquire || cur->unsafe_takeover)) {
return -EPERM;
}
if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio)
return -EPERM;
@ -275,11 +289,20 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
*
* As a result, the following scenario is *not* possible:
*
* 1. Another context with a higher priority directly takes ownership.
* 2. The higher priority context releases the ownership.
* 3. A lower priority context takes the ownership.
* 4. Another context with the same priority as this context
* 1. This context is currently a waiter.
* 2. Another context with a higher priority than this context
* directly takes ownership.
* 3. The higher priority context releases the ownership.
* 4. Another lower priority context takes the ownership.
* 5. Another context with the same priority as this context
* creates a request and starts waiting.
*
* Event #1 implies this context is EMERGENCY.
* Event #2 implies the new context is PANIC.
* Event #3 occurs when panic() has flushed the console.
* Event #4 occurs when a non-panic CPU reacquires.
* Event #5 is not possible due to the other_cpu_in_panic() check
* in nbcon_context_try_acquire_handover().
*/
return (cur->req_prio == expected_prio);
@ -408,6 +431,16 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
WARN_ON_ONCE(!cur->unsafe);
/*
* Panic does not imply that the console is owned. However, it
* is critical that non-panic CPUs during panic are unable to
* wait for a handover in order to satisfy the assumptions of
* nbcon_waiter_matches(). In particular, the assumption that
* lower priorities are ignored during panic.
*/
if (other_cpu_in_panic())
return -EPERM;
/* Handover is not possible on the same CPU. */
if (cur->cpu == cpu)
return -EBUSY;
@ -535,7 +568,8 @@ static struct printk_buffers panic_nbcon_pbufs;
/**
* nbcon_context_try_acquire - Try to acquire nbcon console
* @ctxt: The context of the caller
* @ctxt: The context of the caller
* @is_reacquire: This acquire is a reacquire
*
* Context: Any context which could not be migrated to another CPU.
* Return: True if the console was acquired. False otherwise.
@ -545,7 +579,7 @@ static struct printk_buffers panic_nbcon_pbufs;
* in an unsafe state. Otherwise, on success the caller may assume
* the console is not in an unsafe state.
*/
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire)
{
unsigned int cpu = smp_processor_id();
struct console *con = ctxt->console;
@ -554,7 +588,7 @@ static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
nbcon_state_read(con, &cur);
try_again:
err = nbcon_context_try_acquire_direct(ctxt, &cur);
err = nbcon_context_try_acquire_direct(ctxt, &cur, is_reacquire);
if (err != -EBUSY)
goto out;
@ -852,7 +886,7 @@ void nbcon_reacquire(struct nbcon_write_context *wctxt)
struct console *con = ctxt->console;
struct nbcon_state cur;
while (!nbcon_context_try_acquire(ctxt))
while (!nbcon_context_try_acquire(ctxt, true))
cpu_relax();
wctxt->outbuf = NULL;
@ -1066,7 +1100,7 @@ wait_for_event:
*/
cant_migrate();
if (nbcon_context_try_acquire(ctxt)) {
if (nbcon_context_try_acquire(ctxt, false)) {
/*
* If the emit fails, this context is no
* longer the owner.
@ -1124,6 +1158,16 @@ void nbcon_wake_threads(void)
struct console *con;
int cookie;
if (!printk_threads_enabled)
return;
/*
* It is not allowed to call this function when console irq_work
* is blocked.
*/
if (WARN_ON_ONCE(console_irqwork_blocked))
return;
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
/*
@ -1144,8 +1188,14 @@ static unsigned int early_nbcon_pcpu_emergency_nesting __initdata;
/**
* nbcon_get_cpu_emergency_nesting - Get the per CPU emergency nesting pointer
*
* Context: For reading, any context. For writing, any context which could
* not be migrated to another CPU.
* Return: Either a pointer to the per CPU emergency nesting counter of
* the current CPU or to the init data during early boot.
*
* The function is safe for reading per-CPU variables in any context because
* preemption is disabled if the current CPU is in the emergency state. See
* also nbcon_cpu_emergency_enter().
*/
static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
{
@ -1157,7 +1207,7 @@ static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
if (!printk_percpu_data_ready())
return &early_nbcon_pcpu_emergency_nesting;
return this_cpu_ptr(&nbcon_pcpu_emergency_nesting);
return raw_cpu_ptr(&nbcon_pcpu_emergency_nesting);
}
/**
@ -1176,7 +1226,7 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
if (!nbcon_context_try_acquire(ctxt))
if (!nbcon_context_try_acquire(ctxt, false))
return false;
/*
@ -1196,9 +1246,13 @@ static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt)
* nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
* printing on the current CPU
*
* Context: Any context which could not be migrated to another CPU.
* Context: Any context.
* Return: The nbcon_prio to use for acquiring an nbcon console in this
* context for printing.
*
* The function is safe for reading per-CPU data in any context because
* preemption is disabled if the current CPU is in the emergency or panic
* state.
*/
enum nbcon_prio nbcon_get_default_prio(void)
{
@ -1242,7 +1296,7 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook
*handover = false;
/* Use the same locking order as console_emit_next_record(). */
if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (!force_legacy_kthread()) {
printk_safe_enter_irqsave(flags);
console_lock_spinning_enable();
stop_critical_timings();
@ -1258,7 +1312,7 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook
con->driver_exit(con, driver_flags);
if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (!force_legacy_kthread()) {
start_critical_timings();
*handover = console_lock_spinning_disable_and_check(cookie);
printk_safe_exit_irqrestore(flags);
@ -1275,10 +1329,11 @@ bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cook
*/
static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover)
{
struct console_flush_type ft;
struct nbcon_write_context wctxt = { };
struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
struct console *con;
bool any_progress;
bool any_progress, progress;
int cookie;
do {
@ -1295,6 +1350,7 @@ static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover)
if (!console_is_usable(con, flags, true))
continue;
again:
if (nbcon_seq_read(con) >= stop_seq)
continue;
@ -1318,9 +1374,25 @@ static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover)
ctxt->prio = nbcon_get_default_prio();
any_progress |= nbcon_atomic_emit_one(&wctxt);
progress = nbcon_atomic_emit_one(&wctxt);
local_irq_restore(irq_flags);
if (!progress)
continue;
any_progress = true;
/*
* If flushing was successful but more records are
* available, this context must flush those remaining
* records if the printer thread is not available do it.
*/
printk_get_console_flush_type(&ft);
if (!ft.nbcon_offload &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
stop_seq = prb_next_reserve_seq(prb);
goto again;
}
}
console_srcu_read_unlock(cookie);
} while (any_progress);
@ -1353,16 +1425,12 @@ void nbcon_atomic_flush_unsafe(void)
/**
* nbcon_cpu_emergency_enter - Enter an emergency section where printk()
* messages for that CPU are only stored
*
* Upon exiting the emergency section, all stored messages are flushed.
* messages for that CPU are flushed directly
*
* Context: Any context. Disables preemption.
*
* When within an emergency section, no printing occurs on that CPU. This
* is to allow all emergency messages to be dumped into the ringbuffer before
* flushing the ringbuffer. The actual printing occurs when exiting the
* outermost emergency section.
* When within an emergency section, printk() calls will attempt to flush any
* pending messages in the ringbuffer.
*/
void nbcon_cpu_emergency_enter(void)
{
@ -1375,32 +1443,20 @@ void nbcon_cpu_emergency_enter(void)
}
/**
* nbcon_cpu_emergency_exit - Exit an emergency section and flush the
* stored messages
* nbcon_cpu_emergency_exit - Exit an emergency section
*
* Flushing only occurs when exiting all nesting for the CPU.
*
* Context: Any context. Enables preemption.
* Context: Within an emergency section. Enables preemption.
*/
void nbcon_cpu_emergency_exit(void)
{
unsigned int *cpu_emergency_nesting;
bool do_trigger_flush = false;
cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
WARN_ON_ONCE(*cpu_emergency_nesting == 0);
if (*cpu_emergency_nesting == 1)
do_trigger_flush = true;
/* Undo the nesting count of nbcon_cpu_emergency_enter(). */
(*cpu_emergency_nesting)--;
if (!WARN_ON_ONCE(*cpu_emergency_nesting == 0))
(*cpu_emergency_nesting)--;
preempt_enable();
if (do_trigger_flush)
printk_trigger_flush();
}
/**
@ -1468,7 +1524,7 @@ static int __init printk_setup_threads(void)
printk_threads_enabled = true;
for_each_console(con)
nbcon_kthread_create(con);
if (IS_ENABLED(CONFIG_PREEMPT_RT) && printing_via_unlock)
if (force_legacy_kthread() && (have_legacy_console || have_boot_console))
nbcon_legacy_kthread_create();
console_list_unlock();
return 0;
@ -1588,7 +1644,7 @@ void nbcon_acquire(struct uart_port *up)
memset(&ctxt, 0, sizeof(ctxt));
ctxt.console = con;
ctxt.prio = NBCON_PRIO_NORMAL;
} while (!nbcon_context_try_acquire(&ctxt));
} while (!nbcon_context_try_acquire(&ctxt, false));
} while (!nbcon_context_enter_unsafe(&ctxt));

View File

@ -485,6 +485,12 @@ bool have_nbcon_console;
*/
bool have_boot_console;
/* See printk_legacy_allow_panic_sync() for details. */
bool legacy_allow_panic_sync;
/* Avoid using irq_work when suspending. */
bool console_irqwork_blocked;
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
@ -2339,23 +2345,28 @@ out:
return ret;
}
static bool legacy_allow_panic_sync;
/*
* This acts as a one-way switch to allow legacy consoles to print from
* the printk() caller context on a panic CPU.
*/
void printk_legacy_allow_panic_sync(void)
{
struct console_flush_type ft;
legacy_allow_panic_sync = true;
printk_get_console_flush_type(&ft);
if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
}
asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
bool do_trylock_unlock = printing_via_unlock &&
!IS_ENABLED(CONFIG_PREEMPT_RT);
struct console_flush_type ft;
int printed_len;
/* Suppress unimportant messages after panic happens */
@ -2370,56 +2381,25 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic())
return 0;
printk_get_console_flush_type(&ft);
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
/* If called from the scheduler, we can not call up(). */
do_trylock_unlock = false;
ft.legacy_offload |= ft.legacy_direct && !console_irqwork_blocked;
ft.legacy_direct = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
if (!have_boot_console && have_nbcon_console) {
bool is_panic_context = this_cpu_in_panic();
if (ft.nbcon_atomic)
nbcon_atomic_flush_all();
/*
* In panic, the legacy consoles are not allowed to print from
* the printk calling context unless explicitly allowed. This
* gives the safe nbcon consoles a chance to print out all the
* panic messages first. This restriction only applies if
* there are nbcon consoles registered.
*/
if (is_panic_context)
do_trylock_unlock &= legacy_allow_panic_sync;
if (ft.nbcon_offload)
nbcon_wake_threads();
/*
* There are situations where nbcon atomic printing should
* happen in the printk() caller context:
*
* - When this CPU is in panic.
*
* - When booting, before the printing threads have been
* started.
*
* - During shutdown, since the printing threads may not get
* a chance to print the final messages.
*
* Note that if boot consoles are registered, the
* console_lock/console_unlock dance must be relied upon
* instead because nbcon consoles cannot print simultaneously
* with boot consoles.
*/
if (is_panic_context ||
!printk_threads_enabled ||
(system_state > SYSTEM_RUNNING)) {
nbcon_atomic_flush_all();
}
}
nbcon_wake_threads();
if (do_trylock_unlock) {
if (ft.legacy_direct) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@ -2430,32 +2410,21 @@ asmlinkage int vprintk_emit(int facility, int level,
* Also, nbcon_get_default_prio() requires migration disabled.
*/
preempt_disable();
/*
* Do not emit for EMERGENCY priority. The console will be
* explicitly flushed when exiting the emergency section.
* Try to acquire and then immediately release the console
* semaphore. The release will print out buffers. With the
* spinning variant, this context tries to take over the
* printing from another printing context.
*/
if (nbcon_get_default_prio() == NBCON_PRIO_EMERGENCY) {
do_trylock_unlock = false;
} else {
/*
* Try to acquire and then immediately release the
* console semaphore. The release will print out
* buffers. With the spinning variant, this context
* tries to take over the printing from another
* printing context.
*/
if (console_trylock_spinning())
console_unlock();
}
if (console_trylock_spinning())
console_unlock();
preempt_enable();
}
if (do_trylock_unlock)
wake_up_klogd();
else
if (ft.legacy_offload)
defer_console_output();
else if (!console_irqwork_blocked)
wake_up_klogd();
return printed_len;
}
@ -2689,10 +2658,20 @@ void suspend_console(void)
{
struct console *con;
if (console_suspend_enabled)
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
/*
* Flush any console backlog and then avoid queueing irq_work until
* console_resume_all(). Until then deferred printing is no longer
* triggered, NBCON consoles transition to atomic flushing, and
* any klogd waiters are not triggered.
*/
pr_flush(1000, true);
console_irqwork_blocked = true;
if (!console_suspend_enabled)
return;
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
pr_flush(1000, true);
console_list_lock();
for_each_console(con)
@ -2710,38 +2689,37 @@ void suspend_console(void)
void resume_console(void)
{
struct console_flush_type ft;
struct console *con;
short flags;
int cookie;
if (!console_suspend_enabled)
return;
console_list_lock();
for_each_console(con)
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
console_list_unlock();
/*
* Ensure that all SRCU list walks have completed. All printing
* contexts must be able to see they are no longer suspended so
* that they are guaranteed to wake up and resume printing.
* Allow queueing irq_work. After restoring console state, deferred
* printing and any klogd waiters need to be triggered in case there
* is now a console backlog.
*/
synchronize_srcu(&console_srcu);
console_irqwork_blocked = false;
/*
* Since this runs in task context, wake the threaded printers
* directly rather than scheduling irq_work to do it.
*/
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
flags = console_srcu_read_flags(con);
if (flags & CON_NBCON)
nbcon_kthread_wake(con);
if (console_suspend_enabled) {
console_list_lock();
for_each_console(con)
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
console_list_unlock();
/*
* Ensure that all SRCU list walks have completed. All printing
* contexts must be able to see they are no longer suspended so
* that they are guaranteed to wake up and resume printing.
*/
synchronize_srcu(&console_srcu);
}
console_srcu_read_unlock(cookie);
wake_up_legacy_kthread();
printk_get_console_flush_type(&ft);
if (ft.nbcon_offload)
nbcon_wake_threads();
if (ft.legacy_offload)
defer_console_output();
else
wake_up_klogd();
pr_flush(1000, true);
}
@ -2757,11 +2735,16 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
if (!cpuhp_tasks_frozen && printing_via_unlock &&
!IS_ENABLED(CONFIG_PREEMPT_RT)) {
/* If trylock fails, someone else is doing the printing */
if (console_trylock())
console_unlock();
struct console_flush_type ft;
if (!cpuhp_tasks_frozen) {
printk_get_console_flush_type(&ft);
if (ft.nbcon_atomic)
nbcon_atomic_flush_all();
if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
}
return 0;
}
@ -2987,7 +2970,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
/* Write everything out to the hardware. */
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (force_legacy_kthread()) {
/*
* On PREEMPT_RT this function is either in a thread or
* panic context. So there is no need for concern about
@ -3199,7 +3182,7 @@ void console_unlock(void)
* PREEMPT_RT relies on kthread and atomic consoles for printing.
* It never attempts to print from console_unlock().
*/
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (force_legacy_kthread()) {
__console_unlock();
return;
}
@ -3238,7 +3221,10 @@ void console_unblank(void)
*/
cookie = console_srcu_read_lock();
for_each_console_srcu(c) {
if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) {
if (!console_is_usable(c, console_srcu_read_flags(c), true))
continue;
if (c->unblank) {
found_unblank = true;
break;
}
@ -3275,7 +3261,10 @@ void console_unblank(void)
cookie = console_srcu_read_lock();
for_each_console_srcu(c) {
if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank)
if (!console_is_usable(c, console_srcu_read_flags(c), true))
continue;
if (c->unblank)
c->unblank();
}
console_srcu_read_unlock(cookie);
@ -3294,6 +3283,7 @@ void console_unblank(void)
*/
void console_flush_on_panic(enum con_flush_mode mode)
{
struct console_flush_type ft;
bool handover;
u64 next_seq;
@ -3339,9 +3329,12 @@ void console_flush_on_panic(enum con_flush_mode mode)
console_srcu_read_unlock(cookie);
}
nbcon_atomic_flush_all();
printk_get_console_flush_type(&ft);
if (ft.nbcon_atomic)
nbcon_atomic_flush_all();
if (printing_via_unlock)
/* Flush legacy consoles once allowed, even when dangerous. */
if (legacy_allow_panic_sync)
console_flush_all(false, &next_seq, &handover);
}
@ -3493,7 +3486,7 @@ void nbcon_legacy_kthread_create(void)
lockdep_assert_held(&console_mutex);
if (!IS_ENABLED(CONFIG_PREEMPT_RT))
if (!force_legacy_kthread())
return;
if (!printk_threads_enabled || nbcon_legacy_kthread)
@ -3936,7 +3929,7 @@ static int unregister_console_locked(struct console *console)
}
#ifdef CONFIG_PRINTK
if (!printing_via_unlock && nbcon_legacy_kthread) {
if (!(have_legacy_console || have_boot_console) && nbcon_legacy_kthread) {
kthread_stop(nbcon_legacy_kthread);
nbcon_legacy_kthread = NULL;
}
@ -4088,6 +4081,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
{
unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
unsigned long remaining_jiffies = timeout_jiffies;
struct console_flush_type ft;
struct console *c;
u64 last_diff = 0;
u64 printk_seq;
@ -4106,7 +4100,10 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
* Otherwise this function will just wait for the threaded printers
* to print up to @seq.
*/
if (printing_via_unlock && !IS_ENABLED(CONFIG_PREEMPT_RT)) {
printk_get_console_flush_type(&ft);
if (ft.nbcon_atomic)
nbcon_atomic_flush_all();
if (ft.legacy_direct) {
console_lock();
console_unlock();
}
@ -4118,7 +4115,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
locked = false;
diff = 0;
if (printing_via_unlock) {
if (have_legacy_console || have_boot_console) {
/*
* Hold the console_lock to guarantee safe access to
* console->seq. Releasing console_lock flushes more
@ -4214,7 +4211,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
int pending = this_cpu_xchg(printk_pending, 0);
if (pending & PRINTK_PENDING_OUTPUT) {
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (force_legacy_kthread()) {
wake_up_interruptible(&legacy_wait);
} else {
/*
@ -4238,6 +4235,13 @@ static void __wake_up_klogd(int val)
if (!printk_percpu_data_ready())
return;
/*
* It is not allowed to call this function when console irq_work
* is blocked.
*/
if (WARN_ON_ONCE(console_irqwork_blocked))
return;
preempt_disable();
/*
* Guarantee any new records can be seen by tasks preparing to wait
@ -4293,15 +4297,35 @@ void defer_console_output(void)
*/
int val = PRINTK_PENDING_WAKEUP;
if (printing_via_unlock)
if (have_legacy_console || have_boot_console)
val |= PRINTK_PENDING_OUTPUT;
__wake_up_klogd(val);
}
/**
* printk_trigger_flush - Attempt to flush printk buffer to consoles.
*
* If possible, flush the printk buffer to all consoles in the caller's
* context. If offloading is available, trigger deferred printing.
*
* This is best effort. Depending on the system state, console states,
* and caller context, no actual flushing may result from this call.
*/
void printk_trigger_flush(void)
{
nbcon_wake_threads();
defer_console_output();
struct console_flush_type ft;
printk_get_console_flush_type(&ft);
if (ft.nbcon_atomic)
nbcon_atomic_flush_all();
if (ft.nbcon_offload)
nbcon_wake_threads();
if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
if (ft.legacy_offload)
defer_console_output();
}
int vprintk_deferred(const char *fmt, va_list args)

View File

@ -38,6 +38,17 @@ void __printk_deferred_exit(void)
this_cpu_dec(printk_context);
}
bool is_printk_legacy_deferred(void)
{
/*
* The per-CPU variable @printk_context can be read safely in any
* context. CPU migration is always disabled when set.
*/
return (force_legacy_kthread() ||
this_cpu_read(printk_context) ||
in_nmi());
}
asmlinkage int vprintk(const char *fmt, va_list args)
{
#ifdef CONFIG_KGDB_KDB
@ -45,15 +56,6 @@ asmlinkage int vprintk(const char *fmt, va_list args)
if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0))
return vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
#endif
/*
* Use the main logbuf even in NMI. But avoid calling console
* drivers that might have their own locks.
*/
if (this_cpu_read(printk_context) || in_nmi())
return vprintk_deferred(fmt, args);
/* No obstacles. */
return vprintk_default(fmt, args);
}
EXPORT_SYMBOL(vprintk);

View File

@ -899,9 +899,7 @@ static void smc_copy_netdev_ifindex(struct smc_ib_device *smcibdev, int port)
struct ib_device *ibdev = smcibdev->ibdev;
struct net_device *ndev;
if (!ibdev->ops.get_netdev)
return;
ndev = ibdev->ops.get_netdev(ibdev, port + 1);
ndev = ib_device_get_netdev(ibdev, port + 1);
if (ndev) {
smcibdev->ndev_ifidx[port] = ndev->ifindex;
dev_put(ndev);
@ -921,9 +919,7 @@ void smc_ib_ndev_change(struct net_device *ndev, unsigned long event)
port_cnt = smcibdev->ibdev->phys_port_cnt;
for (i = 0; i < min_t(size_t, port_cnt, SMC_MAX_PORTS); i++) {
libdev = smcibdev->ibdev;
if (!libdev->ops.get_netdev)
continue;
lndev = libdev->ops.get_netdev(libdev, i + 1);
lndev = ib_device_get_netdev(libdev, i + 1);
dev_put(lndev);
if (lndev != ndev)
continue;

View File

@ -1057,9 +1057,7 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev,
for (i = 1; i <= SMC_MAX_PORTS; i++) {
if (!rdma_is_port_valid(ibdev->ibdev, i))
continue;
if (!ibdev->ibdev->ops.get_netdev)
continue;
ndev = ibdev->ibdev->ops.get_netdev(ibdev->ibdev, i);
ndev = ib_device_get_netdev(ibdev->ibdev, i);
if (!ndev)
continue;
dev_put(ndev);

View File

@ -1,3 +1,28 @@
* Sat Feb 28 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.38.1.el9_7]
- mlxsw: spectrum_mr: Fix use-after-free when updating multicast route stats (CKI Backport Bot) [RHEL-143194] {CVE-2025-68800}
Resolves: RHEL-143194
* Thu Feb 26 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.37.1.el9_7]
- printk: Use console_is_usable on console_unblank (CKI Backport Bot) [RHEL-148302]
- printk: Check CON_SUSPEND when unblanking a console (CKI Backport Bot) [RHEL-148302]
- printk: Avoid irq_work for printk_deferred() on suspend (CKI Backport Bot) [RHEL-148302]
- printk: Avoid scheduling irq_work on suspend (CKI Backport Bot) [RHEL-148302]
- printk: nbcon: Allow reacquire during panic (CKI Backport Bot) [RHEL-148302]
- printk: Allow printk_trigger_flush() to flush all types (CKI Backport Bot) [RHEL-148302]
- printk: nbcon: Use raw_cpu_ptr() instead of open coding (CKI Backport Bot) [RHEL-148302]
- backport "printk: Add helper for flush type logic" and associated changes (CKI Backport Bot) [RHEL-148302]
- printk: Remove redundant deferred check in vprintk() (CKI Backport Bot) [RHEL-148302]
- printk: Introduce force_legacy_kthread() macro (CKI Backport Bot) [RHEL-148302]
- printk: Add is_printk_legacy_deferred() (CKI Backport Bot) [RHEL-148302]
- io_uring/sqpoll: don't put task_struct on tctx setup failure (Jeff Moyer) [RHEL-137988]
- io_uring: consistently use rcu semantics with sqpoll thread (Jeff Moyer) [RHEL-137988]
- io_uring: fix use-after-free of sq->thread in __io_uring_show_fdinfo() (Jeff Moyer) [RHEL-137988] {CVE-2025-38106}
- io_uring/sqpoll: fix sqpoll error handling races (Jeff Moyer) [RHEL-137988]
- io_uring/sqpoll: annotate debug task == current with data_race() (Jeff Moyer) [RHEL-137988]
- macvlan: fix possible UAF in macvlan_forward_source() (CKI Backport Bot) [RHEL-144125] {CVE-2026-23001}
- net/smc: Fix lookup of netdev by using ib_device_get_netdev() (CKI Backport Bot) [RHEL-114786]
Resolves: RHEL-114786, RHEL-137988, RHEL-144125, RHEL-148302
* Tue Feb 24 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.36.1.el9_7]
- net/smc: Remove validation of reserved bits in CLC Decline message (Mete Durlu) [RHEL-143718]
- autofs: dont trigger mount if it cant succeed (Ian Kent) [RHEL-149495]