[RFC PATCH 3/3] epoll: add read()/write()/ioctl() operations

2014-02-02 Thread Nathaniel Yazdani
The eventpoll implementation is largely interface-agnostic, aside from the
userspace structure format and epoll_ctl(). Particularly as each field of the
structure is handled independently, replacing usage of epoll_event internally
was straighforward and clarifies the code some. As for epoll_ctl(), its
functionality was moved into the new ep_eventpoll_write() function, and
epoll_ctl() just hands off its work to it. The ep_eventpoll_read() function is
very similar to epoll_wait(), which remains independent but shares the vast
majority of code for minimal redundancy. Finally, ep_eventpoll_ioctl() is a
simple interface to configure a default timeout for read() operations on the
given eventpoll.

Signed-off-by: Nathaniel Yazdani 
---
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index af90312..7f0ce59 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -168,8 +168,11 @@ struct epitem {
/* wakeup_source used when EPOLLWAKEUP is set */
struct wakeup_source __rcu *ws;
 
-   /* The structure that describe the interested events and the source fd 
*/
-   struct epoll_event event;
+   /* Interested events */
+   int events;
+
+   /* The userspace identifier for this entry */
+   long long ident;
 };
 
 /*
@@ -216,6 +219,9 @@ struct eventpoll {
 
struct file *file;
 
+   /* Default timeout */
+   int timeout;
+
/* used to optimize loop detection check */
int visited;
struct list_head visited_list_link;
@@ -251,6 +257,13 @@ struct ep_send_events_data {
struct epoll_event __user *events;
 };
 
+/* ep_scan_ready_list() callback data for ep_send_epes() */
+struct ep_send_epes_data
+{
+   int max;
+   struct epoll __user *epes;
+};
+
 /*
  * Configuration options available inside /proc/sys/fs/epoll/
  */
@@ -795,9 +808,9 @@ static int ep_eventpoll_release(struct inode *inode, struct 
file *file)
 
 static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt)
 {
-   pt->_key = epi->event.events;
+   pt->_key = epi->events;
 
-   return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events;
+   return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->events;
 }
 
 static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
@@ -881,8 +894,8 @@ static int ep_show_fdinfo(struct seq_file *m, struct file 
*f)
struct epitem *epi = rb_entry(rbp, struct epitem, rbn);
 
ret = seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
-epi->ffd.fd, epi->event.events,
-(long long)epi->event.data);
+epi->ffd.fd, epi->events,
+(long long)epi->ident);
if (ret)
break;
}
@@ -892,6 +905,15 @@ static int ep_show_fdinfo(struct seq_file *m, struct file 
*f)
 }
 #endif
 
+static ssize_t ep_eventpoll_write(struct file *file, const char __user *buf,
+ size_t bufsz, loff_t *pos);
+
+static ssize_t ep_eventpoll_read(struct file *file, char __user *buf,
+size_t bufsz, loff_t *pos);
+
+static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd,
+  unsigned long arg);
+
 /* File callbacks that implement the eventpoll file behaviour */
 static const struct file_operations eventpoll_fops = {
 #ifdef CONFIG_PROC_FS
@@ -899,6 +921,9 @@ static const struct file_operations eventpoll_fops = {
 #endif
.release= ep_eventpoll_release,
.poll   = ep_eventpoll_poll,
+   .read   = ep_eventpoll_read,
+   .write  = ep_eventpoll_write,
+   .unlocked_ioctl = ep_eventpoll_ioctl,
.llseek = noop_llseek,
 };
 
@@ -1025,7 +1050,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned 
mode, int sync, void *k
 * EPOLLONESHOT bit that disables the descriptor when an event is 
received,
 * until the next EPOLL_CTL_MOD will be issued.
 */
-   if (!(epi->event.events & ~EP_PRIVATE_BITS))
+   if (!(epi->events & ~EP_PRIVATE_BITS))
goto out_unlock;
 
/*
@@ -1034,7 +1059,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned 
mode, int sync, void *k
 * callback. We need to be able to handle both cases here, hence the
 * test for "key" != NULL before the event match test.
 */
-   if (key && !((unsigned long) key & epi->event.events))
+   if (key && !((unsigned long) key & epi->events))
goto out_unlock;
 
/*
@@ -1264,7 +1289,7 @@ static noinline void ep_destroy_wakeup_source(struct 
epitem *epi)
 /*
  * Must be called with "mtx" held.
  */
-static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
+static int ep_insert(struct eventpoll *ep, long long ident, int events,
 struct file *tfile, int fd, int 

[RFC PATCH 3/3] epoll: add read()/write()/ioctl() operations

2014-02-02 Thread Nathaniel Yazdani
The eventpoll implementation is largely interface-agnostic, aside from the
userspace structure format and epoll_ctl(). Particularly as each field of the
structure is handled independently, replacing usage of epoll_event internally
was straighforward and clarifies the code some. As for epoll_ctl(), its
functionality was moved into the new ep_eventpoll_write() function, and
epoll_ctl() just hands off its work to it. The ep_eventpoll_read() function is
very similar to epoll_wait(), which remains independent but shares the vast
majority of code for minimal redundancy. Finally, ep_eventpoll_ioctl() is a
simple interface to configure a default timeout for read() operations on the
given eventpoll.

Signed-off-by: Nathaniel Yazdani n1ght.4nd@gmail.com
---
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index af90312..7f0ce59 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -168,8 +168,11 @@ struct epitem {
/* wakeup_source used when EPOLLWAKEUP is set */
struct wakeup_source __rcu *ws;
 
-   /* The structure that describe the interested events and the source fd 
*/
-   struct epoll_event event;
+   /* Interested events */
+   int events;
+
+   /* The userspace identifier for this entry */
+   long long ident;
 };
 
 /*
@@ -216,6 +219,9 @@ struct eventpoll {
 
struct file *file;
 
+   /* Default timeout */
+   int timeout;
+
/* used to optimize loop detection check */
int visited;
struct list_head visited_list_link;
@@ -251,6 +257,13 @@ struct ep_send_events_data {
struct epoll_event __user *events;
 };
 
+/* ep_scan_ready_list() callback data for ep_send_epes() */
+struct ep_send_epes_data
+{
+   int max;
+   struct epoll __user *epes;
+};
+
 /*
  * Configuration options available inside /proc/sys/fs/epoll/
  */
@@ -795,9 +808,9 @@ static int ep_eventpoll_release(struct inode *inode, struct 
file *file)
 
 static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt)
 {
-   pt-_key = epi-event.events;
+   pt-_key = epi-events;
 
-   return epi-ffd.file-f_op-poll(epi-ffd.file, pt)  epi-event.events;
+   return epi-ffd.file-f_op-poll(epi-ffd.file, pt)  epi-events;
 }
 
 static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
@@ -881,8 +894,8 @@ static int ep_show_fdinfo(struct seq_file *m, struct file 
*f)
struct epitem *epi = rb_entry(rbp, struct epitem, rbn);
 
ret = seq_printf(m, tfd: %8d events: %8x data: %16llx\n,
-epi-ffd.fd, epi-event.events,
-(long long)epi-event.data);
+epi-ffd.fd, epi-events,
+(long long)epi-ident);
if (ret)
break;
}
@@ -892,6 +905,15 @@ static int ep_show_fdinfo(struct seq_file *m, struct file 
*f)
 }
 #endif
 
+static ssize_t ep_eventpoll_write(struct file *file, const char __user *buf,
+ size_t bufsz, loff_t *pos);
+
+static ssize_t ep_eventpoll_read(struct file *file, char __user *buf,
+size_t bufsz, loff_t *pos);
+
+static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd,
+  unsigned long arg);
+
 /* File callbacks that implement the eventpoll file behaviour */
 static const struct file_operations eventpoll_fops = {
 #ifdef CONFIG_PROC_FS
@@ -899,6 +921,9 @@ static const struct file_operations eventpoll_fops = {
 #endif
.release= ep_eventpoll_release,
.poll   = ep_eventpoll_poll,
+   .read   = ep_eventpoll_read,
+   .write  = ep_eventpoll_write,
+   .unlocked_ioctl = ep_eventpoll_ioctl,
.llseek = noop_llseek,
 };
 
@@ -1025,7 +1050,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned 
mode, int sync, void *k
 * EPOLLONESHOT bit that disables the descriptor when an event is 
received,
 * until the next EPOLL_CTL_MOD will be issued.
 */
-   if (!(epi-event.events  ~EP_PRIVATE_BITS))
+   if (!(epi-events  ~EP_PRIVATE_BITS))
goto out_unlock;
 
/*
@@ -1034,7 +1059,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned 
mode, int sync, void *k
 * callback. We need to be able to handle both cases here, hence the
 * test for key != NULL before the event match test.
 */
-   if (key  !((unsigned long) key  epi-event.events))
+   if (key  !((unsigned long) key  epi-events))
goto out_unlock;
 
/*
@@ -1264,7 +1289,7 @@ static noinline void ep_destroy_wakeup_source(struct 
epitem *epi)
 /*
  * Must be called with mtx held.
  */
-static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
+static int ep_insert(struct eventpoll *ep, long long ident, int events,
 struct file *tfile, int fd, int full_check)
 {