Commit f348d70a authored by Davide Libenzi's avatar Davide Libenzi Committed by Linus Torvalds

[PATCH] POLLRDHUP/EPOLLRDHUP handling for half-closed devices notifications

Implement the half-closed devices notifiation, by adding a new POLLRDHUP
(and its alias EPOLLRDHUP) bit to the existing poll/select sets.  Since the
existing POLLHUP handling, that does not report correctly half-closed
devices, was feared to be changed, this implementation leaves the current
POLLHUP reporting unchanged and simply add a new bit that is set in the few
places where it makes sense.  The same thing was discussed and conceptually
agreed quite some time ago:

http://lkml.org/lkml/2003/7/12/116

Since this new event bit is added to the existing Linux poll infrastruture,
even the existing poll/select system calls will be able to use it.  As far
as the existing POLLHUP handling, the patch leaves it as is.  The
pollrdhup-2.6.16.rc5-0.10.diff defines the POLLRDHUP for all the existing
archs and sets the bit in the six relevant files.  The other attached diff
is the simple change required to sys/epoll.h to add the EPOLLRDHUP
definition.

There is "a stupid program" to test POLLRDHUP delivery here:

 http://www.xmailserver.org/pollrdhup-test.c

It tests poll(2), but since the delivery is same epoll(2) will work equally.
Signed-off-by: default avatarDavide Libenzi <davidel@xmailserver.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 501f2499
...@@ -599,7 +599,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) ...@@ -599,7 +599,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
switch (op) { switch (op) {
case EPOLL_CTL_ADD: case EPOLL_CTL_ADD:
if (!epi) { if (!epi) {
epds.events |= POLLERR | POLLHUP; epds.events |= POLLERR | POLLHUP | POLLRDHUP;
error = ep_insert(ep, &epds, tfile, fd); error = ep_insert(ep, &epds, tfile, fd);
} else } else
...@@ -613,7 +613,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) ...@@ -613,7 +613,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
break; break;
case EPOLL_CTL_MOD: case EPOLL_CTL_MOD:
if (epi) { if (epi) {
epds.events |= POLLERR | POLLHUP; epds.events |= POLLERR | POLLHUP | POLLRDHUP;
error = ep_modify(ep, epi, &epds); error = ep_modify(ep, epi, &epds);
} else } else
error = -ENOENT; error = -ENOENT;
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#define POLLWRBAND (1 << 9) #define POLLWRBAND (1 << 9)
#define POLLMSG (1 << 10) #define POLLMSG (1 << 10)
#define POLLREMOVE (1 << 11) #define POLLREMOVE (1 << 11)
#define POLLRDHUP (1 << 12)
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define POLLWRNORM 0x0100 #define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define POLLWRBAND 512 #define POLLWRBAND 512
#define POLLMSG 1024 #define POLLMSG 1024
#define POLLREMOVE 4096 #define POLLREMOVE 4096
#define POLLRDHUP 8192
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define POLLRDBAND 128 #define POLLRDBAND 128
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define POLLRDBAND 128 #define POLLRDBAND 128
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
/* These seem to be more or less nonstandard ... */ /* These seem to be more or less nonstandard ... */
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define POLLWRNORM 0x0100 #define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 512 #define POLLMSG 512
#define POLLREMOVE 1024 #define POLLREMOVE 1024
#define POLLRDHUP 2048
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define POLLWRBAND 256 #define POLLWRBAND 256
#define POLLMSG 512 #define POLLMSG 512
#define POLLREMOVE 1024 #define POLLREMOVE 1024
#define POLLRDHUP 2048
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define POLLWRBAND 0x0100 #define POLLWRBAND 0x0100
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define POLLWRBAND 0x0200 #define POLLWRBAND 0x0200
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x1000 #define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define POLLMSG 0x0400 #define POLLMSG 0x0400
#define POLLREMOVE 0x0800 #define POLLREMOVE 0x0800
#define POLLRDHUP 0x2000
struct pollfd { struct pollfd {
int fd; int fd;
......
...@@ -238,6 +238,9 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w ...@@ -238,6 +238,9 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;
......
...@@ -500,6 +500,8 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, ...@@ -500,6 +500,8 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
/* exceptional events? */ /* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;
......
...@@ -350,7 +350,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock, ...@@ -350,7 +350,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED) if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */ /* Connected? */
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) { if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
......
...@@ -365,7 +365,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -365,7 +365,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */ /* Connected? */
if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
......
...@@ -4894,6 +4894,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -4894,6 +4894,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
/* Is there any exceptional events? */ /* Is there any exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;
......
...@@ -1878,6 +1878,8 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl ...@@ -1878,6 +1878,8 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl
mask |= POLLERR; mask |= POLLERR;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP; mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
/* readable? */ /* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue) || if (!skb_queue_empty(&sk->sk_receive_queue) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment