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 #include #include +#include #include #include @@ -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 + + 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 + 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 #include #include +#include #include @@ -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 #include #include +#include #include @@ -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 #include #include +#include #include @@ -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 #include /* for invalidate_bdev */ #include +#include #include @@ -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 #include #include +#include +#include #include 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(¤t->namespace->sem); @@ -362,6 +373,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; } @@ -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 + * + * Portions derived from the netlink code in NetKeeper Firewall for Linux + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 "); +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 #include #include +#include #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);