aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/chan_kern.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-09-10 08:17:04 -0400
committerRichard Weinberger <richard@nod.at>2012-03-25 00:29:54 +0100
commit0fcd719934cd3521ae4a977f454e75e2be60b7ff (patch)
treef6679910030fa0361ab52603987b72bc5e7ef314 /arch/um/drivers/chan_kern.c
parentum: line->have_irq is never checked... (diff)
downloadlinux-dev-0fcd719934cd3521ae4a977f454e75e2be60b7ff.tar.xz
linux-dev-0fcd719934cd3521ae4a977f454e75e2be60b7ff.zip
um: race fix: initialize delayed_work *before* registering IRQ
... since chan_interrupt() might schedule it if there's too much incoming data. Kill task argument of chan_interrupt(), while we are at it - it's always &line->task. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/drivers/chan_kern.c')
-rw-r--r--arch/um/drivers/chan_kern.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 73d7bc018ab2..4744b5840fa9 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -146,12 +146,22 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
register_winch(chan->fd, tty);
}
+static void line_timer_cb(struct work_struct *work)
+{
+ struct line *line = container_of(work, struct line, task.work);
+
+ if (!line->throttled)
+ chan_interrupt(line, line->tty, line->driver->read_irq);
+}
+
int enable_chan(struct line *line)
{
struct list_head *ele;
struct chan *chan;
int err;
+ INIT_DELAYED_WORK(&line->task, line_timer_cb);
+
list_for_each(ele, &line->chan_list) {
chan = list_entry(ele, struct chan, list);
err = open_one_chan(chan);
@@ -552,8 +562,7 @@ int parse_chan_pair(char *str, struct line *line, int device,
return 0;
}
-void chan_interrupt(struct line *line, struct delayed_work *task,
- struct tty_struct *tty, int irq)
+void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
{
struct chan *chan = line->chan_in;
int err;
@@ -564,7 +573,7 @@ void chan_interrupt(struct line *line, struct delayed_work *task,
do {
if (tty && !tty_buffer_request_room(tty, 1)) {
- schedule_delayed_work(task, 1);
+ schedule_delayed_work(&line->task, 1);
goto out;
}
err = chan->ops->read(chan->fd, &c, chan->data);