
 Documentation/dbus.txt           |   28 ++++++++
 arch/i386/kernel/cpu/mcheck/p4.c |    3 
 drivers/cdrom/cdrom.c            |   17 ++++-
 drivers/md/dm-ioctl-v1.c         |   18 +----
 drivers/md/dm-ioctl-v4.c         |   18 +----
 drivers/md/md.c                  |    4 +
 fs/namespace.c                   |   27 +++++++-
 include/linux/dbus.h             |   13 +++
 include/linux/netlink.h          |    1 
 include/linux/string.h           |    2 
 kernel/Makefile                  |    2 
 kernel/dbus.c                    |  130 +++++++++++++++++++++++++++++++++++++++
 lib/string.c                     |   18 +++++
 13 files changed, 249 insertions(+), 32 deletions(-)

diff -urN linux-2.6.0-test10-mm1/arch/i386/kernel/cpu/mcheck/p4.c linux/arch/i386/kernel/cpu/mcheck/p4.c
--- linux-2.6.0-test10-mm1/arch/i386/kernel/cpu/mcheck/p4.c	2003-12-10 20:26:39.000000000 -0500
+++ linux/arch/i386/kernel/cpu/mcheck/p4.c	2003-12-10 20:24:00.000000000 -0500
@@ -9,6 +9,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/smp.h>
+#include <linux/dbus.h>
 
 #include <asm/processor.h> 
 #include <asm/system.h>
@@ -53,8 +54,10 @@
 	if (l & 1) {
 		printk(KERN_EMERG "CPU#%d: Temperature above threshold\n", cpu);
 		printk(KERN_EMERG "CPU#%d: Running in modulated clock mode\n", cpu);
+		dbus_send_broadcast(DBUS_POWER, "org.kernel.cpu.temperature","high");
 	} else {
 		printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
+		dbus_send_broadcast(DBUS_POWER, "org.kernel.cpu.temperature","normal");
 	}
 }
 
diff -urN linux-2.6.0-test10-mm1/Documentation/dbus.txt linux/Documentation/dbus.txt
--- linux-2.6.0-test10-mm1/Documentation/dbus.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux/Documentation/dbus.txt	2003-12-15 18:39:05.690762056 -0500
@@ -0,0 +1,28 @@
+
+		  Kernel-to-DBUS-via-Netlink Event Layer HOWTO
+	       Or, How Kernel-space and User-space can be Friends
+			    Rob Love <rml@tech9.net>
+
+			   Last updated: 09-Dec-2003
+
+Kernel side
+-----------
+
+[TODO: description of the beautiful magic]
+
+There is a single, simple interface for generating a D-BUS event:
+
+	#include <linux/dbus.h>
+	void dbus_send_broadcast(int type, char *msg, char *fmt, ...);
+
+For example:
+
+	dbus_send_broadcast(DBUS_MOOD, "org.kernel.computer.mood", "happy");
+
+Simple.
+
+User side
+---------
+
+In short: listen on the NETLINK_DBUS netlink socket
+
diff -urN linux-2.6.0-test10-mm1/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.6.0-test10-mm1/drivers/cdrom/cdrom.c	2003-12-10 20:26:35.000000000 -0500
+++ linux/drivers/cdrom/cdrom.c	2003-12-15 18:19:11.079370592 -0500
@@ -269,6 +269,7 @@
 #include <linux/fcntl.h>
 #include <linux/blkdev.h>
 #include <linux/times.h>
+#include <linux/dbus.h>
 
 #include <asm/uaccess.h>
 
@@ -811,16 +812,30 @@
 	int ret = !!(cdi->mc_flags & mask);
 
 	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
-	    return ret;
+	    goto out;
 	/* changed since last call? */
 	if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
 		cdi->mc_flags = 0x3;    /* set bit on both queues */
 		ret |= 1;
 	}
 	cdi->mc_flags &= ~mask;         /* clear bit */
+
+out:
+	/* FIXME: need to give user-space more information */
+	if (ret)
+		dbus_send_broadcast(DBUS_STORAGE,
+			"org.kernel.drivers.cdrom.media", "%s changed",
+			cdi->name);
+
 	return ret;
 }
 
+/*
+ * cdrom_media_changed - has the given device's media been changed?
+ * @cdi: cdrom_device_info structure for the given device
+ *
+ * Returns 1 if the media has changed and 0 otherwise
+ */
 int cdrom_media_changed(struct cdrom_device_info *cdi)
 {
 	/* This talks to the VFS, which doesn't like errors - just 1 or 0.  
diff -urN linux-2.6.0-test10-mm1/drivers/md/dm-ioctl-v1.c linux/drivers/md/dm-ioctl-v1.c
--- linux-2.6.0-test10-mm1/drivers/md/dm-ioctl-v1.c	2003-12-10 20:26:35.000000000 -0500
+++ linux/drivers/md/dm-ioctl-v1.c	2003-12-14 19:36:06.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/string.h>
 
 #include <asm/uaccess.h>
 
@@ -115,17 +116,6 @@
 	return NULL;
 }
 
-/*-----------------------------------------------------------------
- * Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
-static inline char *kstrdup(const char *str)
-{
-	char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
-	if (r)
-		strcpy(r, str);
-	return r;
-}
-
 static struct hash_cell *alloc_cell(const char *name, const char *uuid,
 				    struct mapped_device *md)
 {
@@ -135,7 +125,7 @@
 	if (!hc)
 		return NULL;
 
-	hc->name = kstrdup(name);
+	hc->name = kstrdup(name, GFP_KERNEL);
 	if (!hc->name) {
 		kfree(hc);
 		return NULL;
@@ -145,7 +135,7 @@
 		hc->uuid = NULL;
 
 	else {
-		hc->uuid = kstrdup(uuid);
+		hc->uuid = kstrdup(uuid, GFP_KERNEL);
 		if (!hc->uuid) {
 			kfree(hc->name);
 			kfree(hc);
@@ -264,7 +254,7 @@
 	/*
 	 * duplicate new.
 	 */
-	new_name = kstrdup(new);
+	new_name = kstrdup(new, GFP_KERNEL);
 	if (!new_name)
 		return -ENOMEM;
 
diff -urN linux-2.6.0-test10-mm1/drivers/md/dm-ioctl-v4.c linux/drivers/md/dm-ioctl-v4.c
--- linux-2.6.0-test10-mm1/drivers/md/dm-ioctl-v4.c	2003-12-10 20:26:35.000000000 -0500
+++ linux/drivers/md/dm-ioctl-v4.c	2003-12-14 19:36:06.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/dm-ioctl.h>
+#include <linux/string.h>
 
 #include <asm/uaccess.h>
 
@@ -116,17 +117,6 @@
 	return NULL;
 }
 
-/*-----------------------------------------------------------------
- * Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
-static inline char *kstrdup(const char *str)
-{
-	char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
-	if (r)
-		strcpy(r, str);
-	return r;
-}
-
 static struct hash_cell *alloc_cell(const char *name, const char *uuid,
 				    struct mapped_device *md)
 {
@@ -136,7 +126,7 @@
 	if (!hc)
 		return NULL;
 
-	hc->name = kstrdup(name);
+	hc->name =kstrdup(name, GFP_KERNEL);
 	if (!hc->name) {
 		kfree(hc);
 		return NULL;
@@ -146,7 +136,7 @@
 		hc->uuid = NULL;
 
 	else {
-		hc->uuid = kstrdup(uuid);
+		hc->uuid = kstrdup(uuid, GFP_KERNEL);
 		if (!hc->uuid) {
 			kfree(hc->name);
 			kfree(hc);
@@ -268,7 +258,7 @@
 	/*
 	 * duplicate new.
 	 */
-	new_name = kstrdup(new);
+	new_name = kstrdup(new, GFP_KERNEL);
 	if (!new_name)
 		return -ENOMEM;
 
diff -urN linux-2.6.0-test10-mm1/drivers/md/md.c linux/drivers/md/md.c
--- linux-2.6.0-test10-mm1/drivers/md/md.c	2003-12-10 20:26:35.000000000 -0500
+++ linux/drivers/md/md.c	2003-12-10 20:23:56.000000000 -0500
@@ -36,6 +36,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/suspend.h>
+#include <linux/dbus.h>
 
 #include <linux/init.h>
 
@@ -3144,6 +3145,7 @@
 	int last_mark,m;
 	struct list_head *tmp;
 	unsigned long last_check;
+	char device[16];
 
 	/* just incase thread restarts... */
 	if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
@@ -3188,6 +3190,7 @@
 
 	max_sectors = mddev->size << 1;
 
+	dbus_send_broadcast(DBUS_STORAGE, "org.kernel.drivers.md.resync.start","md%d",mdidx(mddev));
 	printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev));
 	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
 		" %d KB/sec/disc.\n", sysctl_speed_limit_min);
@@ -3293,6 +3296,7 @@
 		}
 	}
 	printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev));
+	dbus_send_broadcast(DBUS_STORAGE, "org.kernel.drivers.md.resync.finish", "md%d", mdidx(mddev));
 	/*
 	 * this also signals 'finished resyncing' to md_stop
 	 */
diff -urN linux-2.6.0-test10-mm1/fs/namespace.c linux/fs/namespace.c
--- linux-2.6.0-test10-mm1/fs/namespace.c	2003-12-10 20:27:45.000000000 -0500
+++ linux/fs/namespace.c	2003-12-15 18:40:22.692056080 -0500
@@ -21,6 +21,8 @@
 #include <linux/namei.h>
 #include <linux/security.h>
 #include <linux/mount.h>
+#include <linux/dbus.h>
+#include <linux/string.h>
 #include <asm/uaccess.h>
 
 extern int __init init_rootfs(void);
@@ -294,6 +296,7 @@
 static int do_umount(struct vfsmount *mnt, int flags)
 {
 	struct super_block * sb = mnt->mnt_sb;
+	char *devname;
 	int retval;
 
 	retval = security_sb_umount(mnt, flags);
@@ -316,6 +319,14 @@
 	unlock_kernel();
 
 	/*
+	 * Get the mount point and device name for the dbus broadcast now,
+	 * before we deallocate stuff and drop locks.  We could just do the
+	 * dbus broadcast now, but we want to make sure the unmount succeeds.
+	 */
+	devname = kstrdup(mnt->mnt_devname, GFP_KERNEL);
+	//d_path(foo, mnt, mountpoint, MOUNTPOINT_LEN);
+
+	/*
 	 * No sense to grab the lock for this test, but test itself looks
 	 * somewhat bogus. Suggestions for better replacement?
 	 * Ho-hum... In principle, we might treat that as umount + switch
@@ -336,7 +347,7 @@
 			unlock_kernel();
 		}
 		up_write(&sb->s_umount);
-		return retval;
+		goto out;
 	}
 
 	down_write(&current->namespace->sem);
@@ -362,6 +373,14 @@
 	if (retval)
 		security_sb_umount_busy(mnt);
 	up_write(&current->namespace->sem);
+
+	if (!retval)
+		dbus_send_broadcast(DBUS_FS, "org.kernel.fs.unmount",
+			"%s from %s", devname, "foo");
+
+out:
+	kfree(devname);
+
 	return retval;
 }
 
@@ -392,6 +411,7 @@
 		goto dput_and_out;
 
 	retval = do_umount(nd.mnt, flags);
+
 dput_and_out:
 	path_release(&nd);
 out:
@@ -783,6 +803,11 @@
 	else
 		retval = do_add_mount(&nd, type_page, flags, mnt_flags,
 				      dev_name, data_page);
+
+	if (!retval)
+		dbus_send_broadcast(DBUS_FS, "org.kernel.fs.mount",
+				"%s on %s", dev_name, dir_name);
+
 dput_out:
 	path_release(&nd);
 	return retval;
diff -urN linux-2.6.0-test10-mm1/include/linux/dbus.h linux/include/linux/dbus.h
--- linux-2.6.0-test10-mm1/include/linux/dbus.h	1969-12-31 19:00:00.000000000 -0500
+++ linux/include/linux/dbus.h	2003-12-15 18:31:49.000000000 -0500
@@ -0,0 +1,13 @@
+#ifndef _LINUX_DBUS_H
+#define _LINUX_DBUS_H
+
+extern void dbus_send_broadcast(int type, char *message, char *fmt, ...);
+
+/* dbus message types */
+
+#define DBUS_GENERAL	0
+#define DBUS_STORAGE	1
+#define DBUS_POWER	2
+#define DBUS_FS		3
+
+#endif	/* _LINUX_DBUS_H */
diff -urN linux-2.6.0-test10-mm1/include/linux/netlink.h linux/include/linux/netlink.h
--- linux-2.6.0-test10-mm1/include/linux/netlink.h	2003-12-10 20:27:11.000000000 -0500
+++ linux/include/linux/netlink.h	2003-12-14 19:33:01.000000000 -0500
@@ -15,6 +15,7 @@
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
+#define NETLINK_DBUS		15	/* DBUS messages*/
 #define NETLINK_TAPBASE		16	/* 16 to 31 are ethertap */
 
 #define MAX_LINKS 32		
diff -urN linux-2.6.0-test10-mm1/include/linux/string.h linux/include/linux/string.h
--- linux-2.6.0-test10-mm1/include/linux/string.h	2003-12-10 20:27:09.000000000 -0500
+++ linux/include/linux/string.h	2003-12-14 19:36:06.000000000 -0500
@@ -84,6 +84,8 @@
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
 
+extern char *kstrdup(const char *s, int gfp);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN linux-2.6.0-test10-mm1/kernel/dbus.c linux/kernel/dbus.c
--- linux-2.6.0-test10-mm1/kernel/dbus.c	1969-12-31 19:00:00.000000000 -0500
+++ linux/kernel/dbus.c	2003-12-15 18:41:28.470056304 -0500
@@ -0,0 +1,130 @@
+/*
+ * Kernel dbus integration over a netlink socket
+ * 
+ * Copyright (C) 2003 Red Hat, Inc. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Authors:
+ *	Arjan van de Ven	<arjanv@redhat.com>
+ *
+ *  Portions derived from the netlink code in NetKeeper Firewall for Linux
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/string.h>
+#include <linux/dbus.h>
+#include <net/sock.h>
+
+/* There is one global netlink socket for DBUS to userspace. */
+static struct sock *dbus_sock;
+
+/* Callback for requests to nk_netlink */
+static void dbus_netlink_receive(struct sock *sk, int length)
+{
+	struct sk_buff *skb;
+
+	/*
+	 * Since we don't currently take any messages from userspace,
+	 * just drop them all
+	 */
+	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
+		kfree_skb(skb);
+}
+
+static int netlink_send_message(int type, char *message, int length)
+{
+	struct sk_buff *skb;
+	char *data_start;
+
+	if (!message)
+		return -EINVAL;
+
+	if (length > PAGE_SIZE)
+		return -EINVAL;
+
+	skb = alloc_skb(length, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+	data_start = skb_put(skb, length);
+	memcpy(data_start, message, length);
+
+	return netlink_broadcast(dbus_sock, skb, 0, (1 << type), GFP_ATOMIC);
+}
+
+void dbus_send_broadcast(int type, char *message, char *fmt, ...)
+{
+	char *buffer, *c;
+	int length;
+	int ret;
+
+	if (!message)
+		return;
+
+	/*
+	 * Size limits: both the message and the value are limited to 1024
+	 * bytes each
+	 */
+	if (strlen(message) > 1024)
+		return;
+
+	buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	if (!buffer)
+		return;
+
+	strcpy(buffer, message);
+	length = strlen(message) + 1;
+	if (fmt) {
+		va_list args;
+
+		c = buffer + length;
+		va_start(args, fmt);
+		vsprintf(c, fmt, args);
+		va_end(args);
+		length += strlen(buffer + length) + 1;
+	}
+	ret = netlink_send_message(type, buffer, length);
+	free_page((unsigned long) buffer);
+}
+
+EXPORT_SYMBOL_GPL(dbus_send_broadcast);
+
+static int dbus_init(void)
+{
+	dbus_sock = netlink_kernel_create(NETLINK_DBUS, dbus_netlink_receive);
+	if (!dbus_sock) {
+		printk(KERN_ERR "Kernel dbus agent: "
+		       "unable to create netlink socket; aborting\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void dbus_exit(void)
+{
+	if (dbus_sock)
+		sock_release(dbus_sock->sk_socket);
+}
+
+MODULE_DESCRIPTION("Gateway between the kernel and the userspace dbus daemon");
+MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(dbus_init);
+module_exit(dbus_exit);
diff -urN linux-2.6.0-test10-mm1/kernel/Makefile linux/kernel/Makefile
--- linux-2.6.0-test10-mm1/kernel/Makefile	2003-12-10 20:28:02.000000000 -0500
+++ linux/kernel/Makefile	2003-12-10 20:25:33.000000000 -0500
@@ -3,7 +3,7 @@
 #
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-	    exit.o itimer.o time.o softirq.o resource.o \
+	    exit.o itimer.o time.o softirq.o resource.o dbus.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o
diff -urN linux-2.6.0-test10-mm1/lib/string.c linux/lib/string.c
--- linux-2.6.0-test10-mm1/lib/string.c	2003-12-10 20:28:04.000000000 -0500
+++ linux/lib/string.c	2003-12-14 19:36:06.000000000 -0500
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #ifndef __HAVE_ARCH_STRNICMP
 /**
@@ -584,5 +585,20 @@
 	}
 	return NULL;
 }
-
 #endif
+
+/*
+ * kstrdup - allocate space for and copy an existing string
+ *
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrdup(const char *s, int gfp)
+{
+	char *buf = kmalloc(strlen(s)+1, gfp);
+	if (buf)
+		strcpy(buf, s);
+	return buf;
+}
+
+EXPORT_SYMBOL(kstrdup);
