Re: [Utopia] kernel -> dbus event delivery?
- From: Kay Sievers <kay sievers vrfy org>
- To: Robert Love <rml ximian com>
- Cc: utopia-list gnome org
- Subject: Re: [Utopia] kernel -> dbus event delivery?
- Date: Fri, 9 Jul 2004 01:39:54 +0200
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(¤t->namespace->sem);
@@ -430,6 +441,14 @@
if (retval)
security_sb_umount_busy(mnt);
up_write(¤t->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]