From: Lucas De Marchi <lucas.demarchi@profusion.mobi>
To: Greg KH <gregkh@suse.de>
Cc: Kay Sievers <kay.sievers@vrfy.org>,
Andrew Morton <akpm@linux-foundation.org>,
"Eric W. Biederman" <ebiederm@xmission.com>,
Alan Cox <alan@lxorguk.ukuu.org.uk>,
linux-kernel@vger.kernel.org, Nick Piggin <npiggin@kernel.dk>,
Al Viro <viro@zeniv.linux.org.uk>, Christoph Hellwig <hch@lst.de>,
Stephen Rothwell <sfr@canb.auug.org.au>,
David Howells <dhowells@redhat.com>,
"Serge E. Hallyn" <serge.hallyn@canonical.com>,
Daniel Lezcano <daniel.lezcano@free.fr>,
Jiri Slaby <jslaby@suse.cz>, James Morris <jmorris@namei.org>,
neilb@suse.de
Subject: Re: [PATCH] sysctl: add support for poll()
Date: Tue, 2 Aug 2011 22:12:50 -0300 [thread overview]
Message-ID: <20110803011250.GA27227@vigoh> (raw)
In-Reply-To: <20110802231641.GA2598@suse.de>
>From dae691ba16a6c6c50ca05e2cd69bdc808f2c4f89 Mon Sep 17 00:00:00 2001
From: Lucas De Marchi <lucas.demarchi@profusion.mobi>
Date: Wed, 1 Jun 2011 09:14:36 -0300
Subject: [PATCH] sysctl: add support for poll()
Cc: linux-kernel@vger.kernel.org
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 <lucas.demarchi@profusion.mobi>
Acked-By: Kay Sievers <kay.sievers@vrfy.org>
---
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 1a77dbe..cf4bc7c 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -3,6 +3,7 @@
*/
#include <linux/init.h>
#include <linux/sysctl.h>
+#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/namei.h>
@@ -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,
@@ -364,6 +402,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 <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
+#include <linux/wait.h>
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 <linux/nsproxy.h>
#include <linux/err.h>
+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 a101ba3..2347043 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1241,6 +1241,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;
}
@@ -1291,6 +1292,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 <linux/uts.h>
#include <linux/utsname.h>
#include <linux/sysctl.h>
+#include <linux/wait.h>
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.6
next prev parent reply other threads:[~2011-08-03 1:11 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-01 12:14 [PATCH] sysctl: add support for poll() Lucas De Marchi
2011-06-02 2:51 ` Lucas De Marchi
2011-06-02 3:31 ` Eric W. Biederman
2011-06-02 12:06 ` Kay Sievers
2011-06-02 12:43 ` Alan Cox
2011-06-02 13:01 ` Kay Sievers
2011-06-02 13:02 ` Lucas De Marchi
2011-06-02 13:12 ` Alan Cox
2011-06-02 13:24 ` Kay Sievers
2011-06-02 13:56 ` Eric W. Biederman
2011-06-02 17:32 ` Kay Sievers
2011-06-08 22:17 ` Andrew Morton
2011-06-09 13:16 ` Kay Sievers
2011-06-13 16:05 ` Kay Sievers
2011-06-14 3:53 ` Lucas De Marchi
2011-06-14 4:17 ` NeilBrown
2011-07-26 2:17 ` Lucas De Marchi
2011-08-02 22:53 ` Kay Sievers
2011-08-02 23:16 ` Greg KH
2011-08-03 1:12 ` Lucas De Marchi [this message]
2011-08-03 9:40 ` Eric W. Biederman
2011-08-03 13:17 ` Lucas De Marchi
2011-08-03 18:08 ` Eric W. Biederman
2011-08-03 18:45 ` Lucas De Marchi
2011-08-04 18:57 ` Lucas De Marchi
2011-08-23 17:57 ` Greg KH
2011-08-26 21:06 ` Andrew Morton
2011-06-12 15:34 ` Eric W. Biederman
2011-06-13 14:28 ` Kay Sievers
2011-06-02 14:16 ` Eric W. Biederman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110803011250.GA27227@vigoh \
--to=lucas.demarchi@profusion.mobi \
--cc=akpm@linux-foundation.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=daniel.lezcano@free.fr \
--cc=dhowells@redhat.com \
--cc=ebiederm@xmission.com \
--cc=gregkh@suse.de \
--cc=hch@lst.de \
--cc=jmorris@namei.org \
--cc=jslaby@suse.cz \
--cc=kay.sievers@vrfy.org \
--cc=linux-kernel@vger.kernel.org \
--cc=neilb@suse.de \
--cc=npiggin@kernel.dk \
--cc=serge.hallyn@canonical.com \
--cc=sfr@canb.auug.org.au \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox