from: Stef Bon I would like to apply a patch to the kernel to enable the sending of a netlink message when setting or removing an inotify watch. My goal is to make FUSE filesystems notify aware. Since inotify works in the kernel space, and FUSE filesystems are in userspace, FUSE fs's do not "know" when a watch has been set or removed. I think it's a good thing the fs "knows" about a watch, since it can then set a backend specific notify watch on the backend, and report anything back to the kernel when something changes. The new netlink.c file is almost a copy of the netlink.c file in fs/quota. I've got a testprogram which receives messages in the group GENERIC/VFS_INOTIFY. If you want to test please email me. It just gives the information a watch has been set (by who, and where, which mask) and when removed (pid/fd/wd). Signed-off-by: Stef Bon <stefbon@xxxxxxxxx> --- diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig index b981fc0..07f9bfc 100644 --- a/fs/notify/inotify/Kconfig +++ b/fs/notify/inotify/Kconfig @@ -15,3 +15,11 @@ config INOTIFY_USER For more information, see <file:Documentation/filesystems/inotify.txt> If unsure, say Y. + +config INOTIFY_USER_NETLINK_INTERFACE + bool "Report inotify add/remove watch messages through netlink interface" + depends on INOTIFY_USER && NET + ---help--- + If you say Y here, inotify messages (about a watch being set or removed + , not the events!) will be reported through netlink interface. If unsure, + say Y. diff --git a/fs/notify/inotify/Makefile b/fs/notify/inotify/Makefile index a380dab..f977eaa 100644 --- a/fs/notify/inotify/Makefile +++ b/fs/notify/inotify/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_INOTIFY_USER) += inotify_fsnotify.o inotify_user.o +obj-$(CONFIG_INOTIFY_USER_NETLINK_INTERFACE) += netlink.o \ No newline at end of file diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 8445fbc..3f056b9 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -786,6 +786,9 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, /* create/update an inode mark */ ret = inotify_update_watch(group, inode, mask); + + if ( ret>=0 ) inotify_send_add_message(fd, ret, mask, pathname); + path_put(&path); fput_and_out: fput_light(filp, fput_needed); @@ -822,6 +825,8 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) /* match ref taken by inotify_idr_find */ fsnotify_put_mark(&i_mark->fsn_mark); + inotify_send_remove_message(fd, wd); + out: fput_light(filp, fput_needed); return ret; diff --git a/fs/notify/inotify/netlink.c b/fs/notify/inotify/netlink.c new file mode 100644 index 0000000..b965c7f --- /dev/null +++ b/fs/notify/inotify/netlink.c @@ -0,0 +1,151 @@ + +#include <linux/cred.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/inotify.h> +#include <net/netlink.h> +#include <net/genetlink.h> + + +/* Netlink family structure for inotify */ +static struct genl_family inotify_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = "VFS_INOTIFY", + .version = 1, + .maxattr = INOTIFY_NL_A_MAX, +}; + +/** + * inotify_send_add_message + * @fd: inotify fd + * @wd: watch descriptor + * @mask: the mask + * @path: path + * + */ + +void inotify_send_add_message(u32 fd, u32 wd, u32 mask, const char *path) +{ + static atomic_t seq; + struct sk_buff *skb; + void *msg_head; + int ret; + int msg_size = 4 * nla_total_size(sizeof(u32)) + nla_total_size(strlen(path)) + 1; + + skb = genlmsg_new(msg_size, GFP_KERNEL); + + if (!skb) { + + printk(KERN_ERR "VFS: Not enough memory to compose inotify add wd netlink message.\n"); + return; + + } + + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), + &inotify_genl_family, 0, INOTIFY_NL_C_ADD_MESSAGE); + + if (!msg_head) { + + printk(KERN_ERR "VFS: Cannot store netlink header in inotify add wd netlink message.\n"); + goto err_out; + + } + + ret = nla_put_u32(skb, INOTIFY_NL_A_PID, current->pid); + if (ret) goto attr_err_out; + + ret = nla_put_u32(skb, INOTIFY_NL_A_FD, fd); + if (ret) goto attr_err_out; + + ret = nla_put_u32(skb, INOTIFY_NL_A_WD, wd); + if (ret) goto attr_err_out; + + + ret = nla_put_u32(skb, INOTIFY_NL_A_MASK, mask); + if (ret) goto attr_err_out; + + ret = nla_put_string(skb, INOTIFY_NL_A_PATH, path); + if (ret) goto attr_err_out; + + genlmsg_end(skb, msg_head); + + genlmsg_multicast(skb, 0, inotify_genl_family.id, GFP_KERNEL); + + return; +attr_err_out: + printk(KERN_ERR "VFS: Error when writing attributes to inotify add wd netlink message!\n"); +err_out: + kfree_skb(skb); +} +EXPORT_SYMBOL(inotify_send_add_message); + +/** + * inotify_send_remove_message + * @fd: inotify fd + * @wd: watch descriptor + * + */ + +void inotify_send_remove_message(u32 fd, u32 wd) +{ + static atomic_t seq; + struct sk_buff *skb; + void *msg_head; + int ret; + int msg_size = 3 * nla_total_size(sizeof(u32)); + + skb = genlmsg_new(msg_size, GFP_KERNEL); + + if (!skb) { + + printk(KERN_ERR "VFS: Not enough memory to send inotify remove wd netlink message.\n"); + return; + + } + + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), + &inotify_genl_family, 0, INOTIFY_NL_C_REMOVE_MESSAGE); + + if (!msg_head) { + + printk(KERN_ERR "VFS: Cannot store netlink header in inotify remove wd netlink message.\n"); + goto err_out; + + } + + ret = nla_put_u32(skb, INOTIFY_NL_A_PID, current->pid); + if (ret) goto attr_err_out; + + ret = nla_put_u32(skb, INOTIFY_NL_A_FD, fd); + if (ret) goto attr_err_out; + + ret = nla_put_u32(skb, INOTIFY_NL_A_WD, wd); + if (ret) goto attr_err_out; + + genlmsg_end(skb, msg_head); + + genlmsg_multicast(skb, 0, inotify_genl_family.id, GFP_KERNEL); + + return; +attr_err_out: + printk(KERN_ERR "VFS: Error when writing attributes to inotify remove wd netlink message\n"); +err_out: + kfree_skb(skb); +} +EXPORT_SYMBOL(inotify_send_remove_message); + + + + +static int __init inotify_init(void) +{ + if (genl_register_family(&inotify_genl_family) != 0) + printk(KERN_ERR"VFS: Failed to create inotify_user netlink interface.\n"); + return 0; +}; + +module_init(inotify_init); diff --git a/include/linux/inotify.h b/include/linux/inotify.h index d33041e..4ad0b4f 100644 --- a/include/linux/inotify.h +++ b/include/linux/inotify.h @@ -84,4 +84,44 @@ extern struct ctl_table inotify_table[]; /* for sysctl */ #endif +/* commands */ + +enum { + INOTIFY_NL_C_UNSPEC, + INOTIFY_NL_C_ADD_MESSAGE, + INOTIFY_NL_C_REMOVE_MESSAGE, + __INOTIFY_NL_C_MAX, +}; + +#define INOTIFY_NL_C_MAX (__INOTIFY_NL_C_MAX - 1) + +/* attributes */ + +enum { + INOTIFY_NL_A_UNSPEC, + INOTIFY_NL_A_PID, + INOTIFY_NL_A_FD, + INOTIFY_NL_A_WD, + INOTIFY_NL_A_MASK, + INOTIFY_NL_A_PATH, + __INOTIFY_NL_A_MAX, +}; + +#define INOTIFY_NL_A_MAX (__INOTIFY_NL_A_MAX - 1) + + +#ifdef CONFIG_INOTIFY_USER_NETLINK_INTERFACE +extern void inotify_send_add_message(u32 fd, u32 wd, u32 mask, const char *path); +extern void inotify_send_remove_message(u32 fd, u32 wd); +#else +static inline void inotify_send_add_message(u32 fd, u32 wd, u32 mask, const char *path) +{ + return; +} +static inline void inotify_send_remove_message(u32 fd, u32 wd); +{ + return; +} +#endif /* CONFIG_INOTIFY_USER_NETLINK_INTERFACE */ + #endif /* _LINUX_INOTIFY_H */ -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html