Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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: Davide Libenzi <davidel@xmailserver.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Davide Libenzi and committed by
Linus Torvalds
f348d70a 501f2499

+35 -4
+2 -2
fs/eventpoll.c
··· 599 599 switch (op) { 600 600 case EPOLL_CTL_ADD: 601 601 if (!epi) { 602 - epds.events |= POLLERR | POLLHUP; 602 + epds.events |= POLLERR | POLLHUP | POLLRDHUP; 603 603 604 604 error = ep_insert(ep, &epds, tfile, fd); 605 605 } else ··· 613 613 break; 614 614 case EPOLL_CTL_MOD: 615 615 if (epi) { 616 - epds.events |= POLLERR | POLLHUP; 616 + epds.events |= POLLERR | POLLHUP | POLLRDHUP; 617 617 error = ep_modify(ep, epi, &epds); 618 618 } else 619 619 error = -ENOENT;
+2
include/asm-alpha/poll.h
··· 13 13 #define POLLWRBAND (1 << 9) 14 14 #define POLLMSG (1 << 10) 15 15 #define POLLREMOVE (1 << 11) 16 + #define POLLRDHUP (1 << 12) 17 + 16 18 17 19 struct pollfd { 18 20 int fd;
+1
include/asm-arm/poll.h
··· 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 18 #define POLLREMOVE 0x1000 19 + #define POLLRDHUP 0x2000 19 20 20 21 struct pollfd { 21 22 int fd;
+1
include/asm-arm26/poll.h
··· 15 15 #define POLLWRNORM 0x0100 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 + #define POLLRDHUP 0x2000 18 19 19 20 struct pollfd { 20 21 int fd;
+1
include/asm-cris/poll.h
··· 15 15 #define POLLWRBAND 512 16 16 #define POLLMSG 1024 17 17 #define POLLREMOVE 4096 18 + #define POLLRDHUP 8192 18 19 19 20 struct pollfd { 20 21 int fd;
+1
include/asm-frv/poll.h
··· 12 12 #define POLLRDBAND 128 13 13 #define POLLWRBAND 256 14 14 #define POLLMSG 0x0400 15 + #define POLLRDHUP 0x2000 15 16 16 17 struct pollfd { 17 18 int fd;
+1
include/asm-h8300/poll.h
··· 12 12 #define POLLRDBAND 128 13 13 #define POLLWRBAND 256 14 14 #define POLLMSG 0x0400 15 + #define POLLRDHUP 0x2000 15 16 16 17 struct pollfd { 17 18 int fd;
+1
include/asm-i386/poll.h
··· 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 18 #define POLLREMOVE 0x1000 19 + #define POLLRDHUP 0x2000 19 20 20 21 struct pollfd { 21 22 int fd;
+1
include/asm-ia64/poll.h
··· 21 21 #define POLLWRBAND 0x0200 22 22 #define POLLMSG 0x0400 23 23 #define POLLREMOVE 0x1000 24 + #define POLLRDHUP 0x2000 24 25 25 26 struct pollfd { 26 27 int fd;
+1
include/asm-m32r/poll.h
··· 21 21 #define POLLWRBAND 0x0200 22 22 #define POLLMSG 0x0400 23 23 #define POLLREMOVE 0x1000 24 + #define POLLRDHUP 0x2000 24 25 25 26 struct pollfd { 26 27 int fd;
+1
include/asm-m68k/poll.h
··· 13 13 #define POLLWRBAND 256 14 14 #define POLLMSG 0x0400 15 15 #define POLLREMOVE 0x1000 16 + #define POLLRDHUP 0x2000 16 17 17 18 struct pollfd { 18 19 int fd;
+1
include/asm-mips/poll.h
··· 17 17 /* These seem to be more or less nonstandard ... */ 18 18 #define POLLMSG 0x0400 19 19 #define POLLREMOVE 0x1000 20 + #define POLLRDHUP 0x2000 20 21 21 22 struct pollfd { 22 23 int fd;
+1
include/asm-parisc/poll.h
··· 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 18 #define POLLREMOVE 0x1000 19 + #define POLLRDHUP 0x2000 19 20 20 21 struct pollfd { 21 22 int fd;
+1
include/asm-powerpc/poll.h
··· 13 13 #define POLLWRBAND 0x0200 14 14 #define POLLMSG 0x0400 15 15 #define POLLREMOVE 0x1000 16 + #define POLLRDHUP 0x2000 16 17 17 18 struct pollfd { 18 19 int fd;
+1
include/asm-s390/poll.h
··· 24 24 #define POLLWRBAND 0x0200 25 25 #define POLLMSG 0x0400 26 26 #define POLLREMOVE 0x1000 27 + #define POLLRDHUP 0x2000 27 28 28 29 struct pollfd { 29 30 int fd;
+1
include/asm-sh/poll.h
··· 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 18 #define POLLREMOVE 0x1000 19 + #define POLLRDHUP 0x2000 19 20 20 21 struct pollfd { 21 22 int fd;
+1
include/asm-sh64/poll.h
··· 26 26 #define POLLWRNORM 0x0100 27 27 #define POLLWRBAND 0x0200 28 28 #define POLLMSG 0x0400 29 + #define POLLRDHUP 0x2000 29 30 30 31 struct pollfd { 31 32 int fd;
+1
include/asm-sparc/poll.h
··· 13 13 #define POLLWRBAND 256 14 14 #define POLLMSG 512 15 15 #define POLLREMOVE 1024 16 + #define POLLRDHUP 2048 16 17 17 18 struct pollfd { 18 19 int fd;
+1
include/asm-sparc64/poll.h
··· 13 13 #define POLLWRBAND 256 14 14 #define POLLMSG 512 15 15 #define POLLREMOVE 1024 16 + #define POLLRDHUP 2048 16 17 17 18 struct pollfd { 18 19 int fd;
+1
include/asm-v850/poll.h
··· 13 13 #define POLLWRBAND 0x0100 14 14 #define POLLMSG 0x0400 15 15 #define POLLREMOVE 0x1000 16 + #define POLLRDHUP 0x2000 16 17 17 18 struct pollfd { 18 19 int fd;
+1
include/asm-x86_64/poll.h
··· 16 16 #define POLLWRBAND 0x0200 17 17 #define POLLMSG 0x0400 18 18 #define POLLREMOVE 0x1000 19 + #define POLLRDHUP 0x2000 19 20 20 21 struct pollfd { 21 22 int fd;
+1
include/asm-xtensa/poll.h
··· 27 27 28 28 #define POLLMSG 0x0400 29 29 #define POLLREMOVE 0x0800 30 + #define POLLRDHUP 0x2000 30 31 31 32 struct pollfd { 32 33 int fd;
+3
net/bluetooth/af_bluetooth.c
··· 238 238 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 239 239 mask |= POLLERR; 240 240 241 + if (sk->sk_shutdown & RCV_SHUTDOWN) 242 + mask |= POLLRDHUP; 243 + 241 244 if (sk->sk_shutdown == SHUTDOWN_MASK) 242 245 mask |= POLLHUP; 243 246
+2
net/core/datagram.c
··· 500 500 /* exceptional events? */ 501 501 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 502 502 mask |= POLLERR; 503 + if (sk->sk_shutdown & RCV_SHUTDOWN) 504 + mask |= POLLRDHUP; 503 505 if (sk->sk_shutdown == SHUTDOWN_MASK) 504 506 mask |= POLLHUP; 505 507
+1 -1
net/dccp/proto.c
··· 350 350 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED) 351 351 mask |= POLLHUP; 352 352 if (sk->sk_shutdown & RCV_SHUTDOWN) 353 - mask |= POLLIN | POLLRDNORM; 353 + mask |= POLLIN | POLLRDNORM | POLLRDHUP; 354 354 355 355 /* Connected? */ 356 356 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
+1 -1
net/ipv4/tcp.c
··· 365 365 if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) 366 366 mask |= POLLHUP; 367 367 if (sk->sk_shutdown & RCV_SHUTDOWN) 368 - mask |= POLLIN | POLLRDNORM; 368 + mask |= POLLIN | POLLRDNORM | POLLRDHUP; 369 369 370 370 /* Connected? */ 371 371 if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
+2
net/sctp/socket.c
··· 4894 4894 /* Is there any exceptional events? */ 4895 4895 if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 4896 4896 mask |= POLLERR; 4897 + if (sk->sk_shutdown & RCV_SHUTDOWN) 4898 + mask |= POLLRDHUP; 4897 4899 if (sk->sk_shutdown == SHUTDOWN_MASK) 4898 4900 mask |= POLLHUP; 4899 4901
+2
net/unix/af_unix.c
··· 1878 1878 mask |= POLLERR; 1879 1879 if (sk->sk_shutdown == SHUTDOWN_MASK) 1880 1880 mask |= POLLHUP; 1881 + if (sk->sk_shutdown & RCV_SHUTDOWN) 1882 + mask |= POLLRDHUP; 1881 1883 1882 1884 /* readable? */ 1883 1885 if (!skb_queue_empty(&sk->sk_receive_queue) ||