hvc: ensure hvc_init is only ever called once in hvc_console.c
Commit3e6c6f630a
("Delay creation of khcvd thread") moved the call of hvc_init from being a device_initcall into hvc_alloc, and used a non-null hvc_driver as indication of whether hvc_init had already been called. The problem with this is that hvc_driver is only assigned a value at the bottom of hvc_init, and so there is a window where multiple hvc_alloc calls can be in progress at the same time and hence try and call hvc_init multiple times. Previously the use of device_init guaranteed that hvc_init was only called once. This manifests itself as sporadic instances of two hvc_init calls racing each other, and with the loser of the race getting -EBUSY from tty_register_driver() and hence that virtual console fails: Couldn't register hvc console driver virtio-ports vport0p1: error -16 allocating hvc for port Here we add an atomic_t to guarantee we'll never run hvc_init twice. Cc: stable@vger.kernel.org # v2.6.24+ Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Fixes:3e6c6f630a
("Delay creation of khcvd thread") Reported-by: Jim Somerville <Jim.Somerville@windriver.com> Tested-by: Jim Somerville <Jim.Somerville@windriver.com> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9be16b38cf
commit
f76a1cbed1
|
@ -31,6 +31,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
@ -70,6 +71,9 @@ static struct task_struct *hvc_task;
|
|||
/* Picks up late kicks after list walk but before schedule() */
|
||||
static int hvc_kicked;
|
||||
|
||||
/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */
|
||||
static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1);
|
||||
|
||||
static int hvc_init(void);
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
|
@ -851,7 +855,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
|||
int i;
|
||||
|
||||
/* We wait until a driver actually comes along */
|
||||
if (!hvc_driver) {
|
||||
if (atomic_inc_not_zero(&hvc_needs_init)) {
|
||||
int err = hvc_init();
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
|
Loading…
Reference in New Issue