Import of kernel-5.14.0-611.38.1.el9_7
This commit is contained in:
parent
39d42eb2b3
commit
fd14d7a12e
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user