Skip to content

Commit 6f88367

Browse files
jognesspmladek
authored andcommitted
printk, xen: fbfront: create/use safe function for forcing preferred
With commit 9e124fe("xen: Enable console tty by default in domU if it's not a dummy") a hack was implemented to make sure that the tty console remains the console behind the /dev/console device. The main problem with the hack is that, after getting the console pointer to the tty console, it is assumed the pointer is still valid after releasing the console_sem. This assumption is incorrect and unsafe. Make the hack safe by introducing a new function console_force_preferred_locked() and perform the full operation under the console_list_lock. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2c6b4b7 commit 6f88367

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

drivers/video/fbdev/xen-fbfront.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -504,18 +504,14 @@ static void xenfb_make_preferred_console(void)
504504
if (console_set_on_cmdline)
505505
return;
506506

507-
console_lock();
507+
console_list_lock();
508508
for_each_console(c) {
509509
if (!strcmp(c->name, "tty") && c->index == 0)
510510
break;
511511
}
512-
console_unlock();
513-
if (c) {
514-
unregister_console(c);
515-
c->flags |= CON_CONSDEV;
516-
c->flags &= ~CON_PRINTBUFFER; /* don't print again */
517-
register_console(c);
518-
}
512+
if (c)
513+
console_force_preferred_locked(c);
514+
console_list_unlock();
519515
}
520516

521517
static int xenfb_resume(struct xenbus_device *dev)

include/linux/console.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ enum con_flush_mode {
291291
};
292292

293293
extern int add_preferred_console(char *name, int idx, char *options);
294+
extern void console_force_preferred_locked(struct console *con);
294295
extern void register_console(struct console *);
295296
extern int unregister_console(struct console *);
296297
extern void console_lock(void);

kernel/printk/printk.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,10 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
248248
void console_list_lock(void)
249249
{
250250
/*
251-
* In unregister_console(), synchronize_srcu() is called with the
252-
* console_list_lock held. Therefore it is not allowed that the
253-
* console_list_lock is taken with the srcu_lock held.
251+
* In unregister_console() and console_force_preferred_locked(),
252+
* synchronize_srcu() is called with the console_list_lock held.
253+
* Therefore it is not allowed that the console_list_lock is taken
254+
* with the srcu_lock held.
254255
*
255256
* Detecting if this context is really in the read-side critical
256257
* section is only possible if the appropriate debug options are
@@ -3490,6 +3491,48 @@ int unregister_console(struct console *console)
34903491
}
34913492
EXPORT_SYMBOL(unregister_console);
34923493

3494+
/**
3495+
* console_force_preferred_locked - force a registered console preferred
3496+
* @con: The registered console to force preferred.
3497+
*
3498+
* Must be called under console_list_lock().
3499+
*/
3500+
void console_force_preferred_locked(struct console *con)
3501+
{
3502+
struct console *cur_pref_con;
3503+
3504+
if (!console_is_registered_locked(con))
3505+
return;
3506+
3507+
cur_pref_con = console_first();
3508+
3509+
/* Already preferred? */
3510+
if (cur_pref_con == con)
3511+
return;
3512+
3513+
/*
3514+
* Delete, but do not re-initialize the entry. This allows the console
3515+
* to continue to appear registered (via any hlist_unhashed_lockless()
3516+
* checks), even though it was briefly removed from the console list.
3517+
*/
3518+
hlist_del_rcu(&con->node);
3519+
3520+
/*
3521+
* Ensure that all SRCU list walks have completed so that the console
3522+
* can be added to the beginning of the console list and its forward
3523+
* list pointer can be re-initialized.
3524+
*/
3525+
synchronize_srcu(&console_srcu);
3526+
3527+
con->flags |= CON_CONSDEV;
3528+
WARN_ON(!con->device);
3529+
3530+
/* Only the new head can have CON_CONSDEV set. */
3531+
console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
3532+
hlist_add_head_rcu(&con->node, &console_list);
3533+
}
3534+
EXPORT_SYMBOL(console_force_preferred_locked);
3535+
34933536
/*
34943537
* Initialize the console device. This is called *early*, so
34953538
* we can't necessarily depend on lots of kernel help here.

0 commit comments

Comments
 (0)