On Wed, 14 Oct 2009, Linus Torvalds wrote: > > But it's certainly true that it just never happened before. At least for > the !low_latency case, I'm not so sure about the low_latency=1 case, but I > haven't checked either - it would depend on any higher-level > serialization. Btw, we _could_ try to solve this by adding some workqueue function to "run delayed work now", and then always doing the 'flush_to_ldisc()' through the workqueue logic. So this is an "alternate patch": instead of making flush_to_ldisc() be safe to re-enter, we try to make sure it's always called through the whole workqueue logic and thus serialized by that. Of course, keventd itself is multi-threaded, so I'm not entirely sure even -that- guarantees that one 'flush_to_ldisc()' couldn't be pending on one CPU while it is then scheduled and then run on another CPU concurrently too. The WORK_STRUCT_PENDING bit guarantees exclusion from the lists and from being pending, but the work might be both pending and _running_ at the same time, afaik. I'm adding Oleg to the Cc, because he's the workqueue-master. Oleg? The patch below is - surprise, surprise - entirely untested. I'm not sure my 'flush_delayed_work()' implementation is entirely kosher. But it looks like it might work, and it did compile for me (technically this is on top of my flush_to_ldisc() patch, but they should be independent of each other). Linus --- drivers/char/tty_buffer.c | 2 +- include/linux/workqueue.h | 1 + kernel/workqueue.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletions(-) diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c index 0296612..66fa4e1 100644 --- a/drivers/char/tty_buffer.c +++ b/drivers/char/tty_buffer.c @@ -468,7 +468,7 @@ static void flush_to_ldisc(struct work_struct *work) */ void tty_flush_to_ldisc(struct tty_struct *tty) { - flush_to_ldisc(&tty->buf.work.work); + flush_delayed_work(&tty->buf.work); } /** diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 7ef0c7b..cf24c20 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -207,6 +207,7 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, extern void flush_workqueue(struct workqueue_struct *wq); extern void flush_scheduled_work(void); +extern void flush_delayed_work(struct delayed_work *work); extern int schedule_work(struct work_struct *work); extern int schedule_work_on(int cpu, struct work_struct *work); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index addfe2d..ccefe57 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -640,6 +640,24 @@ int schedule_delayed_work(struct delayed_work *dwork, EXPORT_SYMBOL(schedule_delayed_work); /** + * flush_delayed_work - block until a dwork_struct's callback has terminated + * @dwork: the delayed work which is to be flushed + * + * Any timeout is cancelled, and any pending work is run immediately. + */ +void flush_delayed_work(struct delayed_work *dwork) +{ + if (del_timer(&dwork->timer)) { + struct cpu_workqueue_struct *cwq; + cwq = wq_per_cpu(keventd_wq, get_cpu()); + __queue_work(cwq, &dwork->work); + put_cpu(); + } + flush_work(&dwork->work); +} +EXPORT_SYMBOL(flush_delayed_work); + +/** * schedule_delayed_work_on - queue work in global workqueue on CPU after delay * @cpu: cpu to use * @dwork: job to be done -- To unsubscribe from this list: send the line "unsubscribe kernel-testers" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html