lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 6 May 2007 01:32:13 +0400
From:	Oleg Nesterov <oleg@...sign.ru>
To:	Andrew Morton <akpm@...ux-foundation.org>
Cc:	David Chinner <dgc@....com>, David Howells <dhowells@...hat.com>,
	Gautham Shenoy <ego@...ibm.com>,
	Jarek Poplawski <jarkao2@...pl>, Ingo Molnar <mingo@...e.hu>,
	Srivatsa Vaddagiri <vatsa@...ibm.com>,
	linux-kernel@...r.kernel.org
Subject: [PATCH] make-cancel_rearming_delayed_work-reliable-fix

on top of
	make-cancel_rearming_delayed_work-reliable-spelling.patch

Add cpu-relax() into spinloops, and a comments update.

Small note. The new implementation has another downside. Suppose that rearming
work->func() gets a preemtion after setting WORK_STRUCT_PENDING but before
add_timer/__queue_work. In that case cancel_rearming_delayed_work() will burn
CPU in a busy-wait loop. Fortunately this can happen only with CONFIG_PREEMPT
and we spin with preemption enabled.

We can avoid this,

	void cancel_rearming_delayed_work(struct delayed_work *dwork)
	{
		int retry;

		do {
			retry = !del_timer(&dwork->timer) &&
				!try_to_grab_pending(&dwork->work);
			wait_on_work(&dwork->work);
		} while (retry);

		work_clear_pending(&dwork->work);
	}

but I don't think this is worth fixing.

Signed-off-by: Oleg Nesterov <oleg@...sign.ru>

--- OLD/kernel/workqueue.c~2_RELAX	2007-05-05 23:17:48.000000000 +0400
+++ OLD/kernel/workqueue.c	2007-05-05 23:59:59.000000000 +0400
@@ -475,13 +475,16 @@ static void wait_on_work(struct work_str
  * case it only guarantees that work->func() has completed on the last queued
  * workqueue.
  *
+ * cancel_work_sync(&delayed_work->work) should be used only if ->timer is not
+ * pending, otherwise it goes into a busy-wait loop until the timer expires.
+ *
  * The caller must ensure that workqueue_struct on which this work was last
  * queued can't be destroyed before this function returns.
  */
 void cancel_work_sync(struct work_struct *work)
 {
 	while (!try_to_grab_pending(work))
-		;
+		cpu_relax();
 	wait_on_work(work);
 	work_clear_pending(work);
 }
@@ -498,7 +501,7 @@ void cancel_rearming_delayed_work(struct
 {
 	while (!del_timer(&dwork->timer) &&
 	       !try_to_grab_pending(&dwork->work))
-		;
+		cpu_relax();
 	wait_on_work(&dwork->work);
 	work_clear_pending(&dwork->work);
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ