Skip to content

Commit 5cae92e

Browse files
committed
Merge branch 'rework/write_atomic-unsafe' into for-linus
2 parents 4f132d8 + 187de7c commit 5cae92e

File tree

2 files changed

+48
-18
lines changed

2 files changed

+48
-18
lines changed

include/linux/console.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ static inline void con_debug_leave(void) { }
186186
* printing callbacks must not be called.
187187
* @CON_NBCON: Console can operate outside of the legacy style console_lock
188188
* constraints.
189+
* @CON_NBCON_ATOMIC_UNSAFE: The write_atomic() callback is not safe and is
190+
* therefore only used by nbcon_atomic_flush_unsafe().
189191
*/
190192
enum cons_flags {
191193
CON_PRINTBUFFER = BIT(0),
@@ -197,6 +199,7 @@ enum cons_flags {
197199
CON_EXTENDED = BIT(6),
198200
CON_SUSPENDED = BIT(7),
199201
CON_NBCON = BIT(8),
202+
CON_NBCON_ATOMIC_UNSAFE = BIT(9),
200203
};
201204

202205
/**
@@ -608,6 +611,7 @@ extern void nbcon_write_context_set_buf(struct nbcon_write_context *wctxt,
608611
extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
609612
extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
610613
extern void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt);
614+
extern bool nbcon_allow_unsafe_takeover(void);
611615
extern bool nbcon_kdb_try_acquire(struct console *con,
612616
struct nbcon_write_context *wctxt);
613617
extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
@@ -627,9 +631,18 @@ static inline bool console_is_usable(struct console *con, short flags, bool use_
627631
return false;
628632

629633
if (flags & CON_NBCON) {
630-
/* The write_atomic() callback is optional. */
631-
if (use_atomic && !con->write_atomic)
632-
return false;
634+
if (use_atomic) {
635+
/* The write_atomic() callback is optional. */
636+
if (!con->write_atomic)
637+
return false;
638+
639+
/*
640+
* An unsafe write_atomic() callback is only usable
641+
* when unsafe takeovers are allowed.
642+
*/
643+
if ((flags & CON_NBCON_ATOMIC_UNSAFE) && !nbcon_allow_unsafe_takeover())
644+
return false;
645+
}
633646

634647
/*
635648
* For the !use_atomic case, @printk_kthreads_running is not

kernel/printk/nbcon.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,26 @@ enum nbcon_prio nbcon_get_default_prio(void)
14371437
return NBCON_PRIO_NORMAL;
14381438
}
14391439

1440+
/*
1441+
* Track if it is allowed to perform unsafe hostile takeovers of console
1442+
* ownership. When true, console drivers might perform unsafe actions while
1443+
* printing. It is externally available via nbcon_allow_unsafe_takeover().
1444+
*/
1445+
static bool panic_nbcon_allow_unsafe_takeover;
1446+
1447+
/**
1448+
* nbcon_allow_unsafe_takeover - Check if unsafe console takeovers are allowed
1449+
*
1450+
* Return: True, when it is permitted to perform unsafe console printing
1451+
*
1452+
* This is also used by console_is_usable() to determine if it is allowed to
1453+
* call write_atomic() callbacks flagged as unsafe (CON_NBCON_ATOMIC_UNSAFE).
1454+
*/
1455+
bool nbcon_allow_unsafe_takeover(void)
1456+
{
1457+
return panic_on_this_cpu() && panic_nbcon_allow_unsafe_takeover;
1458+
}
1459+
14401460
/**
14411461
* nbcon_legacy_emit_next_record - Print one record for an nbcon console
14421462
* in legacy contexts
@@ -1507,7 +1527,6 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
15071527
* write_atomic() callback
15081528
* @con: The nbcon console to flush
15091529
* @stop_seq: Flush up until this record
1510-
* @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
15111530
*
15121531
* Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on
15131532
* failure.
@@ -1526,8 +1545,7 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
15261545
* returned, it cannot be expected that the unfinalized record will become
15271546
* available.
15281547
*/
1529-
static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
1530-
bool allow_unsafe_takeover)
1548+
static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
15311549
{
15321550
struct nbcon_write_context wctxt = { };
15331551
struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
@@ -1536,7 +1554,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
15361554
ctxt->console = con;
15371555
ctxt->spinwait_max_us = 2000;
15381556
ctxt->prio = nbcon_get_default_prio();
1539-
ctxt->allow_unsafe_takeover = allow_unsafe_takeover;
1557+
ctxt->allow_unsafe_takeover = nbcon_allow_unsafe_takeover();
15401558

15411559
while (nbcon_seq_read(con) < stop_seq) {
15421560
if (!nbcon_context_try_acquire(ctxt, false))
@@ -1568,15 +1586,13 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
15681586
* write_atomic() callback
15691587
* @con: The nbcon console to flush
15701588
* @stop_seq: Flush up until this record
1571-
* @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
15721589
*
15731590
* This will stop flushing before @stop_seq if another context has ownership.
15741591
* That context is then responsible for the flushing. Likewise, if new records
15751592
* are added while this context was flushing and there is no other context
15761593
* to handle the printing, this context must also flush those records.
15771594
*/
1578-
static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
1579-
bool allow_unsafe_takeover)
1595+
static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
15801596
{
15811597
struct console_flush_type ft;
15821598
unsigned long flags;
@@ -1591,7 +1607,7 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
15911607
*/
15921608
local_irq_save(flags);
15931609

1594-
err = __nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
1610+
err = __nbcon_atomic_flush_pending_con(con, stop_seq);
15951611

15961612
local_irq_restore(flags);
15971613

@@ -1623,9 +1639,8 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
16231639
* __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
16241640
* write_atomic() callback
16251641
* @stop_seq: Flush up until this record
1626-
* @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
16271642
*/
1628-
static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeover)
1643+
static void __nbcon_atomic_flush_pending(u64 stop_seq)
16291644
{
16301645
struct console *con;
16311646
int cookie;
@@ -1643,7 +1658,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeove
16431658
if (nbcon_seq_read(con) >= stop_seq)
16441659
continue;
16451660

1646-
nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
1661+
nbcon_atomic_flush_pending_con(con, stop_seq);
16471662
}
16481663
console_srcu_read_unlock(cookie);
16491664
}
@@ -1659,7 +1674,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeove
16591674
*/
16601675
void nbcon_atomic_flush_pending(void)
16611676
{
1662-
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
1677+
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
16631678
}
16641679

16651680
/**
@@ -1671,7 +1686,9 @@ void nbcon_atomic_flush_pending(void)
16711686
*/
16721687
void nbcon_atomic_flush_unsafe(void)
16731688
{
1674-
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
1689+
panic_nbcon_allow_unsafe_takeover = true;
1690+
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
1691+
panic_nbcon_allow_unsafe_takeover = false;
16751692
}
16761693

16771694
/**
@@ -1894,7 +1911,7 @@ void nbcon_device_release(struct console *con)
18941911
* using the legacy loop.
18951912
*/
18961913
if (ft.nbcon_atomic) {
1897-
__nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
1914+
__nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));
18981915
} else if (ft.legacy_direct) {
18991916
if (console_trylock())
19001917
console_unlock();
@@ -1964,5 +1981,5 @@ void nbcon_kdb_release(struct nbcon_write_context *wctxt)
19641981
* The console was locked only when the write_atomic() callback
19651982
* was usable.
19661983
*/
1967-
__nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb), false);
1984+
__nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb));
19681985
}

0 commit comments

Comments
 (0)