Add dm-daemon.
--- diff/drivers/md/Makefile	2004-02-09 10:39:52.000000000 +0000
+++ source/drivers/md/Makefile	2004-02-09 10:43:28.000000000 +0000
@@ -3,7 +3,7 @@
 #
 
 dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-		   dm-ioctl.o
+		   dm-ioctl.o dm-daemon.o
 raid6-objs	:= raid6main.o raid6algos.o raid6recov.o raid6tables.o \
 		   raid6int1.o raid6int2.o raid6int4.o \
 		   raid6int8.o raid6int16.o raid6int32.o \
--- diff/drivers/md/dm.h	2004-02-09 10:43:22.000000000 +0000
+++ source/drivers/md/dm.h	2004-02-09 10:43:28.000000000 +0000
@@ -20,6 +20,11 @@
 #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
 
 /*
+ * FIXME: There must be a better place for this.
+ */
+typedef typeof(jiffies) jiffy_t;
+
+/*
  * FIXME: I think this should be with the definition of sector_t
  * in types.h.
  */
--- diff/drivers/md/dm-daemon.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-daemon.c	2004-02-09 10:43:28.000000000 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the LGPL.
+ */
+
+#include "dm.h"
+#include "dm-daemon.h"
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+
+static int daemon(void *arg)
+{
+	struct dm_daemon *dd = (struct dm_daemon *) arg;
+	DECLARE_WAITQUEUE(wq, current);
+	jiffy_t timeout;
+
+	daemonize("%s", dd->name);
+
+	atomic_set(&dd->please_die, 0);
+
+	add_wait_queue(&dd->job_queue, &wq);
+
+	complete(&dd->start);
+
+	/*
+	 * dd->fn() could do anything, very likely it will
+	 * suspend.  So we can't set the state to
+	 * TASK_INTERRUPTIBLE before calling it.  In order to
+	 * prevent a race with a waking thread we do this little
+	 * dance with the dd->woken variable.
+	 */
+	while (1) {
+		if (atomic_read(&dd->please_die))
+			goto out;
+
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_IOTHREAD);
+
+		do {
+			set_current_state(TASK_RUNNING);
+			atomic_set(&dd->woken, 0);
+			timeout = dd->fn();
+			set_current_state(TASK_INTERRUPTIBLE);
+
+		} while (atomic_read(&dd->woken));
+
+		if (timeout)
+			schedule_timeout(timeout);
+		else
+			schedule();
+	}
+
+ out:
+	remove_wait_queue(&dd->job_queue, &wq);
+	complete_and_exit(&dd->run, 0);
+}
+
+int dm_daemon_start(struct dm_daemon *dd, const char *name, jiffy_t (*fn)(void))
+{
+	pid_t pid = 0;
+
+	/*
+	 * Initialise the dm_daemon.
+	 */
+	dd->fn = fn;
+	strncpy(dd->name, name, sizeof(dd->name) - 1);
+	init_completion(&dd->start);
+	init_completion(&dd->run);
+	init_waitqueue_head(&dd->job_queue);
+
+	/*
+	 * Start the new thread.
+	 */
+	pid = kernel_thread(daemon, dd, CLONE_KERNEL);
+	if (pid <= 0) {
+		DMERR("Failed to start %s thread", name);
+		return -EAGAIN;
+	}
+
+	/*
+	 * wait for the daemon to up this mutex.
+	 */
+	wait_for_completion(&dd->start);
+
+	return 0;
+}
+
+void dm_daemon_stop(struct dm_daemon *dd)
+{
+	atomic_set(&dd->please_die, 1);
+	dm_daemon_wake(dd);
+	wait_for_completion(&dd->run);
+}
+
+void dm_daemon_wake(struct dm_daemon *dd)
+{
+	atomic_set(&dd->woken, 1);
+	wake_up_interruptible(&dd->job_queue);
+}
+
+EXPORT_SYMBOL(dm_daemon_start);
+EXPORT_SYMBOL(dm_daemon_stop);
+EXPORT_SYMBOL(dm_daemon_wake);
--- diff/drivers/md/dm-daemon.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-daemon.h	2004-02-09 10:43:28.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef DM_DAEMON_H
+#define DM_DAEMON_H
+
+#include <asm/atomic.h>
+#include <linux/completion.h>
+
+/*
+ * The daemons work function returns a *hint* as to when it
+ * should next be woken up.
+ */
+struct dm_daemon {
+	jiffy_t (*fn)(void);
+	char name[16];
+	atomic_t please_die;
+	struct completion start;
+	struct completion run;
+
+	atomic_t woken;
+	wait_queue_head_t job_queue;
+};
+
+int dm_daemon_start(struct dm_daemon *dd, const char *name, jiffy_t (*fn)(void));
+void dm_daemon_stop(struct dm_daemon *dd);
+void dm_daemon_wake(struct dm_daemon *dd);
+int dm_daemon_running(struct dm_daemon *dd);
+
+#endif
