um: convert count_lock to mutex, fix a race in line_open()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 9 Sep 2011 21:36:37 +0000 (17:36 -0400)
committerRichard Weinberger <richard@nod.at>
Sat, 24 Mar 2012 23:29:53 +0000 (00:29 +0100)
If two processes are opening the same line, the second to get
into line_open() will decide that it doesn't need to do anything
(correctly) or wait for anything.  The latter, unfortunately,
is incorrect - the first opener might not be through yet.  We
need to have exclusion covering the entire line_init(), including
the blocking parts.  Moreover, the next patch will need to
widen the exclusion on mconsole side of things, also including
the blocking bits, so let's just convert that sucker to mutex...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Richard Weinberger <richard@nod.at>
arch/um/drivers/line.c
arch/um/drivers/line.h
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c

index 3eea99e98a1106aff270e5e03f003484aa6c37f7..dc7e216df6a5446452b5a75371573f34fff04026 100644 (file)
@@ -409,7 +409,7 @@ int line_open(struct line *lines, struct tty_struct *tty)
        struct line *line = &lines[tty->index];
        int err = -ENODEV;
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        if (!line->valid)
                goto out_unlock;
 
@@ -421,10 +421,9 @@ int line_open(struct line *lines, struct tty_struct *tty)
        tty->driver_data = line;
        line->tty = tty;
 
-       spin_unlock(&line->count_lock);
        err = enable_chan(line);
        if (err) /* line_close() will be called by our caller */
-               return err;
+               goto out_unlock;
 
        INIT_DELAYED_WORK(&line->task, line_timer_cb);
 
@@ -435,11 +434,8 @@ int line_open(struct line *lines, struct tty_struct *tty)
 
        chan_window_size(&line->chan_list, &tty->winsize.ws_row,
                         &tty->winsize.ws_col);
-
-       return 0;
-
 out_unlock:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
        return err;
 }
 
@@ -459,7 +455,7 @@ void line_close(struct tty_struct *tty, struct file * filp)
        /* We ignore the error anyway! */
        flush_buffer(line);
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        BUG_ON(!line->valid);
 
        if (--line->count)
@@ -468,17 +464,13 @@ void line_close(struct tty_struct *tty, struct file * filp)
        line->tty = NULL;
        tty->driver_data = NULL;
 
-       spin_unlock(&line->count_lock);
-
        if (line->sigio) {
                unregister_winch(tty);
                line->sigio = 0;
        }
 
-       return;
-
 out_unlock:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
 }
 
 void close_lines(struct line *lines, int nlines)
@@ -495,7 +487,7 @@ static int setup_one_line(struct line *lines, int n, char *init,
        struct line *line = &lines[n];
        int err = -EINVAL;
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
 
        if (line->count) {
                *error_out = "Device is already open";
@@ -510,7 +502,7 @@ static int setup_one_line(struct line *lines, int n, char *init,
        }
        err = 0;
 out:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
        return err;
 }
 
@@ -609,13 +601,13 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
 
        line = &lines[dev];
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        if (!line->valid)
                CONFIG_CHUNK(str, size, n, "none", 1);
        else if (line->tty == NULL)
                CONFIG_CHUNK(str, size, n, line->init_str, 1);
        else n = chan_config_string(&line->chan_list, str, size, error_out);
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
 
        return n;
 }
index 0c4dadf5e03e613d4be1f0d5af57c48f9198af53..471f477b271ed4d57933d50462691566e9d07bb6 100644 (file)
@@ -32,7 +32,7 @@ struct line_driver {
 
 struct line {
        struct tty_struct *tty;
-       spinlock_t count_lock;
+       struct mutex count_lock;
        unsigned long count;
        int valid;
 
index 445288ff0650bcecbf21133d40d1df47f1ba3466..23cffd6d85af1fed181a6e4b368399dcea89da20 100644 (file)
@@ -201,7 +201,7 @@ static int ssl_init(void)
                        serial_lines[i].valid = 1;
                }
                spin_lock_init(&serial_lines[i].lock);
-               spin_lock_init(&serial_lines[i].count_lock);
+               mutex_init(&serial_lines[i].count_lock);
                serial_lines[i].driver = &driver;
        }
        ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
index 6d244f47096878f6c6f95adbc1c020a2e9bb095d..f8d4325b28b73adedc6eb1e429e9f8e0eb2d1171 100644 (file)
@@ -173,7 +173,7 @@ static int stdio_init(void)
                        vts[i].valid = 1;
                }
                spin_lock_init(&vts[i].lock);
-               spin_lock_init(&vts[i].count_lock);
+               mutex_init(&vts[i].count_lock);
                vts[i].driver = &driver;
        }
        console_driver = register_lines(&driver, &console_ops, vts,