Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759455Ab1FBCwA (ORCPT ); Wed, 1 Jun 2011 22:52:00 -0400 Received: from mail-pv0-f174.google.com ([74.125.83.174]:63703 "EHLO mail-pv0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759015Ab1FBCv6 convert rfc822-to-8bit (ORCPT ); Wed, 1 Jun 2011 22:51:58 -0400 MIME-Version: 1.0 In-Reply-To: <1306930476-1899-1-git-send-email-lucas.demarchi@profusion.mobi> References: <1306930476-1899-1-git-send-email-lucas.demarchi@profusion.mobi> From: Lucas De Marchi Date: Wed, 1 Jun 2011 23:51:37 -0300 Message-ID: Subject: Re: [PATCH] sysctl: add support for poll() To: linux-kernel@vger.kernel.org Cc: kay.sievers@vrfy.org, Lucas De Marchi , Nick Piggin , Al Viro , Christoph Hellwig , "Eric W. Biederman" , Stephen Rothwell , Andrew Morton , David Howells , "Serge E. Hallyn" , Daniel Lezcano , Jiri Slaby , Greg Kroah-Hartman , James Morris Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8523 Lines: 260 CC'ing people as suggested by get_maintainer.pl On Wed, Jun 1, 2011 at 9:14 AM, Lucas De Marchi wrote: > Adding support for poll() in sysctl fs allows userspace to receive > notifications when an entry in sysctl changes. This way it's possible to > know when hostname/domainname is changed due to the respective syscall > has been called or its file under /proc/sys has been written to. > > Signed-off-by: Lucas De Marchi > --- > ?fs/proc/proc_sysctl.c ? | ? 40 ++++++++++++++++++++++++++++++++++++++++ > ?include/linux/sysctl.h ?| ? ?8 ++++++++ > ?include/linux/utsname.h | ? 16 ++++++++++++++++ > ?kernel/sys.c ? ? ? ? ? ?| ? ?2 ++ > ?kernel/utsname_sysctl.c | ? 36 ++++++++++++++++++++++++++++++++++++ > ?5 files changed, 102 insertions(+), 0 deletions(-) > > diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c > index f50133c..2e5d3ec 100644 > --- a/fs/proc/proc_sysctl.c > +++ b/fs/proc/proc_sysctl.c > @@ -3,6 +3,7 @@ > ?*/ > ?#include > ?#include > +#include > ?#include > ?#include > ?#include > @@ -176,6 +177,43 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf, > ? ? ? ?return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); > ?} > > +static int proc_sys_open(struct inode *inode, struct file *filp) > +{ > + ? ? ? struct ctl_table *table = PROC_I(inode)->sysctl_entry; > + > + ? ? ? if (table->poll) { > + ? ? ? ? ? ? ? unsigned long event = atomic_read(&table->poll->event); > + > + ? ? ? ? ? ? ? filp->private_data = (void *)event; > + ? ? ? } > + > + ? ? ? return 0; > +} > + > +static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) > +{ > + ? ? ? struct inode *inode = filp->f_path.dentry->d_inode; > + ? ? ? struct ctl_table *table = PROC_I(inode)->sysctl_entry; > + ? ? ? unsigned long event = (unsigned long)filp->private_data; > + ? ? ? unsigned int ret = POLLIN | POLLRDNORM; > + > + ? ? ? if (!table->proc_handler) > + ? ? ? ? ? ? ? goto out; > + > + ? ? ? if (!table->poll) > + ? ? ? ? ? ? ? goto out; > + > + ? ? ? poll_wait(filp, &table->poll->wait, wait); > + > + ? ? ? if (event != atomic_read(&table->poll->event)) { > + ? ? ? ? ? ? ? filp->private_data = (void *)(unsigned long)atomic_read( > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &table->poll->event); > + ? ? ? ? ? ? ? ret = POLLIN | POLLRDNORM | POLLERR | POLLPRI; > + ? ? ? } > + > +out: > + ? ? ? return ret; > +} > > ?static int proc_sys_fill_cache(struct file *filp, void *dirent, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?filldir_t filldir, > @@ -367,6 +405,8 @@ static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct > ?} > > ?static const struct file_operations proc_sys_file_operations = { > + ? ? ? .open ? ? ? ? ? = proc_sys_open, > + ? ? ? .poll ? ? ? ? ? = proc_sys_poll, > ? ? ? ?.read ? ? ? ? ? = proc_sys_read, > ? ? ? ?.write ? ? ? ? ?= proc_sys_write, > ? ? ? ?.llseek ? ? ? ? = default_llseek, > diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h > index 11684d9..96c89ba 100644 > --- a/include/linux/sysctl.h > +++ b/include/linux/sysctl.h > @@ -25,6 +25,7 @@ > ?#include > ?#include > ?#include > +#include > > ?struct completion; > > @@ -1011,6 +1012,12 @@ extern int proc_do_large_bitmap(struct ctl_table *, int, > ?* cover common cases. > ?*/ > > +/* Support for userspace poll() to watch for changes */ > +struct ctl_table_poll { > + ? ? ? atomic_t event; > + ? ? ? wait_queue_head_t wait; > +}; > + > ?/* A sysctl table is an array of struct ctl_table: */ > ?struct ctl_table > ?{ > @@ -1021,6 +1028,7 @@ struct ctl_table > ? ? ? ?struct ctl_table *child; > ? ? ? ?struct ctl_table *parent; ? ? ? /* Automatically set */ > ? ? ? ?proc_handler *proc_handler; ? ? /* Callback for text formatting */ > + ? ? ? struct ctl_table_poll *poll; > ? ? ? ?void *extra1; > ? ? ? ?void *extra2; > ?}; > diff --git a/include/linux/utsname.h b/include/linux/utsname.h > index 4e5b021..c714ed7 100644 > --- a/include/linux/utsname.h > +++ b/include/linux/utsname.h > @@ -37,6 +37,14 @@ struct new_utsname { > ?#include > ?#include > > +enum uts_proc { > + ? ? ? UTS_PROC_OSTYPE, > + ? ? ? UTS_PROC_OSRELEASE, > + ? ? ? UTS_PROC_VERSION, > + ? ? ? UTS_PROC_HOSTNAME, > + ? ? ? UTS_PROC_DOMAINNAME, > +}; > + > ?struct user_namespace; > ?extern struct user_namespace init_user_ns; > > @@ -80,6 +88,14 @@ static inline struct uts_namespace *copy_utsname(unsigned long flags, > ?} > ?#endif > > +#ifdef CONFIG_PROC_SYSCTL > +extern void uts_proc_notify(enum uts_proc proc); > +#else > +static inline void uts_proc_notify(enum uts_proc proc) > +{ > +} > +#endif > + > ?static inline struct new_utsname *utsname(void) > ?{ > ? ? ? ?return ¤t->nsproxy->uts_ns->name; > diff --git a/kernel/sys.c b/kernel/sys.c > index e4128b2..ada9cd7 100644 > --- a/kernel/sys.c > +++ b/kernel/sys.c > @@ -1211,6 +1211,7 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) > ? ? ? ? ? ? ? ?memset(u->nodename + len, 0, sizeof(u->nodename) - len); > ? ? ? ? ? ? ? ?errno = 0; > ? ? ? ?} > + ? ? ? uts_proc_notify(UTS_PROC_HOSTNAME); > ? ? ? ?up_write(&uts_sem); > ? ? ? ?return errno; > ?} > @@ -1261,6 +1262,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) > ? ? ? ? ? ? ? ?memset(u->domainname + len, 0, sizeof(u->domainname) - len); > ? ? ? ? ? ? ? ?errno = 0; > ? ? ? ?} > + ? ? ? uts_proc_notify(UTS_PROC_DOMAINNAME); > ? ? ? ?up_write(&uts_sem); > ? ? ? ?return errno; > ?} > diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c > index a2cd77e..e96b766 100644 > --- a/kernel/utsname_sysctl.c > +++ b/kernel/utsname_sysctl.c > @@ -13,6 +13,7 @@ > ?#include > ?#include > ?#include > +#include > > ?static void *get_uts(ctl_table *table, int write) > ?{ > @@ -51,12 +52,28 @@ static int proc_do_uts_string(ctl_table *table, int write, > ? ? ? ?uts_table.data = get_uts(table, write); > ? ? ? ?r = proc_dostring(&uts_table,write,buffer,lenp, ppos); > ? ? ? ?put_uts(table, write, uts_table.data); > + > + ? ? ? if (write) { > + ? ? ? ? ? ? ? atomic_inc(&table->poll->event); > + ? ? ? ? ? ? ? wake_up_interruptible(&table->poll->wait); > + ? ? ? } > + > ? ? ? ?return r; > ?} > ?#else > ?#define proc_do_uts_string NULL > ?#endif > > +static struct ctl_table_poll hostname_poll = { > + ? ? ? .event ? ? ? ? ?= ATOMIC_INIT(0), > + ? ? ? .wait ? ? ? ? ? = __WAIT_QUEUE_HEAD_INITIALIZER(hostname_poll.wait), > +}; > + > +static struct ctl_table_poll domainname_poll = { > + ? ? ? .event ? ? ? ? ?= ATOMIC_INIT(0), > + ? ? ? .wait ? ? ? ? ? = __WAIT_QUEUE_HEAD_INITIALIZER(domainname_poll.wait), > +}; > + > ?static struct ctl_table uts_kern_table[] = { > ? ? ? ?{ > ? ? ? ? ? ? ? ?.procname ? ? ? = "ostype", > @@ -85,6 +102,7 @@ static struct ctl_table uts_kern_table[] = { > ? ? ? ? ? ? ? ?.maxlen ? ? ? ? = sizeof(init_uts_ns.name.nodename), > ? ? ? ? ? ? ? ?.mode ? ? ? ? ? = 0644, > ? ? ? ? ? ? ? ?.proc_handler ? = proc_do_uts_string, > + ? ? ? ? ? ? ? .poll ? ? ? ? ? = &hostname_poll, > ? ? ? ?}, > ? ? ? ?{ > ? ? ? ? ? ? ? ?.procname ? ? ? = "domainname", > @@ -92,6 +110,7 @@ static struct ctl_table uts_kern_table[] = { > ? ? ? ? ? ? ? ?.maxlen ? ? ? ? = sizeof(init_uts_ns.name.domainname), > ? ? ? ? ? ? ? ?.mode ? ? ? ? ? = 0644, > ? ? ? ? ? ? ? ?.proc_handler ? = proc_do_uts_string, > + ? ? ? ? ? ? ? .poll ? ? ? ? ? = &domainname_poll, > ? ? ? ?}, > ? ? ? ?{} > ?}; > @@ -105,6 +124,23 @@ static struct ctl_table uts_root_table[] = { > ? ? ? ?{} > ?}; > > +#ifdef CONFIG_PROC_SYSCTL > +/* > + * Notify userspace about a change in a certain entry of uts_kern_table, > + * identified by the parameter proc. > + */ > +void uts_proc_notify(enum uts_proc proc) > +{ > + ? ? ? struct ctl_table *table = &uts_kern_table[proc]; > + > + ? ? ? if (!table->poll) > + ? ? ? ? ? ? ? return; > + > + ? ? ? atomic_inc(&table->poll->event); > + ? ? ? wake_up_interruptible(&table->poll->wait); > +} > +#endif > + > ?static int __init utsname_sysctl_init(void) > ?{ > ? ? ? ?register_sysctl_table(uts_root_table); > -- > 1.7.5.2 > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/