make cancel_rearming_delayed_work() reliable
authorOleg Nesterov <oleg@tv-sign.ru>
Wed, 9 May 2007 09:34:46 +0000 (02:34 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 9 May 2007 19:30:53 +0000 (12:30 -0700)
commit6e84d644b5929789398914b0ccf447355dec6fb0
tree0de4bd0c8d3bf4cd764275f02d56d8576f376ae5
parent7b0834c26fd796c79dfcc3939ed2b9122b75246f
make cancel_rearming_delayed_work() reliable

Thanks to Jarek Poplawski for the ideas and for spotting the bug in the
initial draft patch.

cancel_rearming_delayed_work() currently has many limitations, because it
requires that dwork always re-arms itself via queue_delayed_work().  So it
hangs forever if dwork doesn't do this, or cancel_rearming_delayed_work/
cancel_delayed_work was already called.  It uses flush_workqueue() in a
loop, so it can't be used if workqueue was freezed, and it is potentially
live- lockable on busy system if delay is small.

With this patch cancel_rearming_delayed_work() doesn't make any assumptions
about dwork, it can re-arm itself via queue_delayed_work(), or
queue_work(), or do nothing.

As a "side effect", cancel_work_sync() was changed to handle re-arming works
as well.

Disadvantages:

- this patch adds wmb() to insert_work().

- slowdowns the fast path (when del_timer() succeeds on entry) of
  cancel_rearming_delayed_work(), because wait_on_work() is called
  unconditionally. In that case, compared to the old version, we are
  doing "unneeded" lock/unlock for each online CPU.

  On the other hand, this means we don't need to use cancel_work_sync()
  after cancel_rearming_delayed_work().

- complicates the code (.text grows by 130 bytes).

[akpm@linux-foundation.org: fix speling]
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: David Chinner <dgc@sgi.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Gautham Shenoy <ego@in.ibm.com>
Acked-by: Jarek Poplawski <jarkao2@o2.pl>
Cc: Srivatsa Vaddagiri <vatsa@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/workqueue.c