From fd14d7a12e58f8089a6c9520c84ea70ddeb80570 Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Thu, 12 Mar 2026 04:35:32 +0000 Subject: [PATCH] Import of kernel-5.14.0-611.38.1.el9_7 --- ...11.36.1.el9 => COPYING-5.14.0-611.38.1.el9 | 0 Makefile.rhelver | 2 +- .../net/ethernet/mellanox/mlxsw/spectrum_mr.c | 2 + drivers/net/macvlan.c | 20 +- io_uring/fdinfo.c | 12 +- io_uring/io_uring.c | 4 +- io_uring/register.c | 7 +- io_uring/sqpoll.c | 42 ++- io_uring/sqpoll.h | 8 +- kernel/printk/internal.h | 132 +++++++++- kernel/printk/nbcon.c | 154 +++++++---- kernel/printk/printk.c | 244 ++++++++++-------- kernel/printk/printk_safe.c | 20 +- net/smc/smc_ib.c | 8 +- net/smc/smc_pnet.c | 4 +- redhat/kernel.changelog-9.7 | 25 ++ 16 files changed, 468 insertions(+), 216 deletions(-) rename COPYING-5.14.0-611.36.1.el9 => COPYING-5.14.0-611.38.1.el9 (100%) diff --git a/COPYING-5.14.0-611.36.1.el9 b/COPYING-5.14.0-611.38.1.el9 similarity index 100% rename from COPYING-5.14.0-611.36.1.el9 rename to COPYING-5.14.0-611.38.1.el9 diff --git a/Makefile.rhelver b/Makefile.rhelver index b118f9faf5..28051c4b1f 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -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 diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c index 5afe6b155e..81935f87bf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c @@ -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); } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index ff54a989fe..a0405cfd77 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -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; diff --git a/io_uring/fdinfo.c b/io_uring/fdinfo.c index 0e26a0d15d..eeaad5b6c1 100644 --- a/io_uring/fdinfo.c +++ b/io_uring/fdinfo.c @@ -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(); } } diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 83804acd82..61860d2fa9 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -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; diff --git a/io_uring/register.c b/io_uring/register.c index 11517b34cf..bef9b563c5 100644 --- a/io_uring/register.c +++ b/io_uring/register.c @@ -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; diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c index 4c9f2faf3a..15422b9ea1 100644 --- a/io_uring/sqpoll.c +++ b/io_uring/sqpoll.c @@ -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); } diff --git a/io_uring/sqpoll.h b/io_uring/sqpoll.h index 4171666b1c..b83dcdec97 100644 --- a/io_uring/sqpoll.h +++ b/io_uring/sqpoll.h @@ -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)); +} diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 7db6992c54..4ee74e8781 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -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; /** diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index b4278854ee..77cc164706 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -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)); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 74127f8be9..d17ab23af8 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -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) diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index 8d9408d653..5a31bb773c 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -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); diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 9297dc20bf..9c563cdbea 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -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; diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 19137060e3..598f7da5b0 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -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); diff --git a/redhat/kernel.changelog-9.7 b/redhat/kernel.changelog-9.7 index c7aee9685e..7f4ae95fc6 100644 --- a/redhat/kernel.changelog-9.7 +++ b/redhat/kernel.changelog-9.7 @@ -1,3 +1,28 @@ +* Sat Feb 28 2026 CKI KWF Bot [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 [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 [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]