Re: [Utopia] kernel -> dbus event delivery?



On Thu, Jul 08, 2004 at 10:34:18AM -0400, Robert Love wrote:
> On Thu, 2004-07-08 at 13:12 +0200, Kay Sievers wrote:
> 
> > does anybody know about the current state of the kernel<->dbus event-link?
> > Is there anything I can play with :) The only reference I could find, is
> > Arjan's patch:
> >   http://people.redhat.com/arjanv/linux-2.6.0-dbus.patch
> > 
> > What is the glue between the kernels NETLINK_DBUS and the dbus-daemon?
> 
> The work is a bit stagnate because I don't have overwhelming support
> from the community.  Also, we have not found any huge needs for an
> asynchronous event system - processor over[h]eating, not withstanding.
> It will be nice to send up file system events so we don't have to pull
> mtab, et al, but that is an optimization and not a requirement.
> 
> Oh, some IBM guys are super interested, as a mechanism to provide event
> logging from drivers.
> 
> I will be talking at OLS on the event system and D-BUS, so hopefully I
> can attract some attention.
> 
> Anyhow, my latest patch is here:
> 
> http://www.kernel.org/pub/linux/kernel/people/rml/events/

For those, who want to play with it, here is a updated patch that applies
to the current linux tree and a small listening example:

  [root pim src]# ./kdbus
  service 'org.kernel.fs.mount' sent value '/dev/hda3 on /mnt/tmp/'
  service 'org.kernel.fs.unmount' sent value '/dev/hda3 from foo'
  service 'org.kernel.drivers.cdrom.media' sent value 'hdc changed'

Have fun,
Kay
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h> 

#ifndef NETLINK_DBUS
#define NETLINK_DBUS		15
#define DBUS_GENERAL		0 
#define DBUS_STORAGE		1 
#define DBUS_POWER		2 
#define DBUS_FS			3 
#endif

#define dbg(x) printf(x);

int main(int argc, char *argv[])
{
	int sock;
	char buf[1024];
	struct sockaddr_nl snl;
	int retval;
	int len;
	
	if (getuid() != 0) {
		dbg("need to be root, exit");
		exit(1);
	}

	memset(&snl, 0x00, sizeof(struct sockaddr_nl));
	snl.nl_family = AF_NETLINK;
	snl.nl_pid = getpid();
	snl.nl_groups = 1 << DBUS_GENERAL |
			1 << DBUS_STORAGE |
			1 << DBUS_POWER |
			1 << DBUS_FS;

	sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_DBUS);
	if (sock == -1) {
		dbg("error getting socket, exit");
		exit(1);
	}

	retval = bind(sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
	if (retval < 0) {
		dbg("bind failed, exit");
		goto exit;
	}

	while (1) {
		retval = recv(sock, &buf, sizeof(buf), 0);
		if (retval <  0)
			dbg("error receiving message");

		len = strlen(buf);
		printf("service '%s' sent '%s'\n", buf, &buf[len+1]);
	}

exit:
	close(sock);
	exit(1);
}
diff -Nru a/Documentation/dbus.txt b/Documentation/dbus.txt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/Documentation/dbus.txt	2004-07-09 01:31:02 +02:00
@@ -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 -Nru a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
--- a/arch/i386/kernel/cpu/mcheck/p4.c	2004-07-09 01:31:02 +02:00
+++ b/arch/i386/kernel/cpu/mcheck/p4.c	2004-07-09 01:31:02 +02:00
@@ -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>
@@ -60,8 +61,10 @@
 		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 -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	2004-07-09 01:31:02 +02:00
+++ b/drivers/cdrom/cdrom.c	2004-07-09 01:31:02 +02:00
@@ -275,6 +275,7 @@
 #include <linux/fcntl.h>
 #include <linux/blkdev.h>
 #include <linux/times.h>
+#include <linux/dbus.h>
 
 #include <asm/uaccess.h>
 
@@ -1294,16 +1295,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 -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
--- a/drivers/md/dm-ioctl.c	2004-07-09 01:31:02 +02:00
+++ b/drivers/md/dm-ioctl.c	2004-07-09 01:31:02 +02:00
@@ -121,14 +121,6 @@
 /*-----------------------------------------------------------------
  * 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)
 {
@@ -138,7 +130,7 @@
 	if (!hc)
 		return NULL;
 
-	hc->name = kstrdup(name);
+	hc->name = kstrdup(name, GFP_KERNEL);
 	if (!hc->name) {
 		kfree(hc);
 		return NULL;
@@ -148,7 +140,7 @@
 		hc->uuid = NULL;
 
 	else {
-		hc->uuid = kstrdup(uuid);
+		hc->uuid = kstrdup(uuid, GFP_KERNEL);
 		if (!hc->uuid) {
 			kfree(hc->name);
 			kfree(hc);
@@ -270,7 +262,7 @@
 	/*
 	 * duplicate new.
 	 */
-	new_name = kstrdup(new);
+	new_name = kstrdup(new, GFP_KERNEL);
 	if (!new_name)
 		return -ENOMEM;
 
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	2004-07-09 01:31:02 +02:00
+++ b/drivers/md/md.c	2004-07-09 01:31:02 +02:00
@@ -37,6 +37,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>
 
@@ -3297,6 +3298,7 @@
 	int last_mark,m;
 	struct list_head *tmp;
 	sector_t last_check;
+	char device[16];
 
 	/* just incase thread restarts... */
 	if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
@@ -3347,6 +3349,7 @@
 	printk(KERN_INFO "md: using maximum available idle IO bandwith "
 	       "(but not more than %d KB/sec) for reconstruction.\n",
 	       sysctl_speed_limit_max);
+	dbus_send_broadcast(DBUS_STORAGE, "org.kernel.drivers.md.resync.start","md%d",mdname(mddev));
 
 	is_mddev_idle(mddev); /* this also initializes IO event counters */
 	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
@@ -3445,6 +3448,7 @@
 		}
 	}
 	printk(KERN_INFO "md: %s: sync done.\n",mdname(mddev));
+	dbus_send_broadcast(DBUS_STORAGE, "org.kernel.drivers.md.resync.finish", "md%d", mdname(mddev));
 	/*
 	 * this also signals 'finished resyncing' to md_stop
 	 */
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	2004-07-09 01:31:02 +02:00
+++ b/fs/namespace.c	2004-07-09 01:31:02 +02:00
@@ -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>
 #include <asm/unistd.h>
 
@@ -362,6 +364,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);
@@ -384,6 +387,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
@@ -404,7 +415,7 @@
 			unlock_kernel();
 		}
 		up_write(&sb->s_umount);
-		return retval;
+		goto out;
 	}
 
 	down_write(&current->namespace->sem);
@@ -430,6 +441,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;
 }
 
@@ -460,6 +479,7 @@
 		goto dput_and_out;
 
 	retval = do_umount(nd.mnt, flags);
+
 dput_and_out:
 	path_release(&nd);
 out:
@@ -862,6 +882,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 -Nru a/include/linux/dbus.h b/include/linux/dbus.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/dbus.h	2004-07-09 01:31:02 +02:00
@@ -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 -Nru a/include/linux/netlink.h b/include/linux/netlink.h
--- a/include/linux/netlink.h	2004-07-09 01:31:02 +02:00
+++ b/include/linux/netlink.h	2004-07-09 01:31:02 +02:00
@@ -17,6 +17,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 -Nru a/include/linux/string.h b/include/linux/string.h
--- a/include/linux/string.h	2004-07-09 01:31:02 +02:00
+++ b/include/linux/string.h	2004-07-09 01:31:02 +02:00
@@ -88,6 +88,8 @@
 extern void * memchr(const void *,int,__kernel_size_t);
 #endif
 
+extern char *kstrdup(const char *s, int gfp);
+
 #ifdef __cplusplus
 }
 #endif
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	2004-07-09 01:31:02 +02:00
+++ b/kernel/Makefile	2004-07-09 01:31:02 +02:00
@@ -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 -Nru a/kernel/dbus.c b/kernel/dbus.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/kernel/dbus.c	2004-07-09 01:31:02 +02:00
@@ -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 -Nru a/lib/string.c b/lib/string.c
--- a/lib/string.c	2004-07-09 01:31:02 +02:00
+++ b/lib/string.c	2004-07-09 01:31:02 +02:00
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #ifndef __HAVE_ARCH_STRNICMP
 /**
@@ -603,5 +604,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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]