Commit 7d4c04fc authored by Keller, Jacob E's avatar Keller, Jacob E Committed by David S. Miller

net: add option to enable error queue packets waking select

Currently, when a socket receives something on the error queue it only wakes up
the socket on select if it is in the "read" list, that is the socket has
something to read. It is useful also to wake the socket if it is in the error
list, which would enable software to wait on error queue packets without waking
up for regular data on the socket. The main use case is for receiving
timestamped transmit packets which return the timestamp to the socket via the
error queue. This enables an application to select on the socket for the error
queue only instead of for the regular traffic.

-v2-
* Added the SO_SELECT_ERR_QUEUE socket option to every architechture specific file
* Modified every socket poll function that checks error queue
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Cc: Jeffrey Kirsher <jeffrey.t.kirsher@intel.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Matthew Vick <matthew.vick@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4eb06148
...@@ -79,4 +79,6 @@ ...@@ -79,4 +79,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _UAPI_ASM_SOCKET_H */ #endif /* _UAPI_ASM_SOCKET_H */
...@@ -72,4 +72,6 @@ ...@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* __ASM_AVR32_SOCKET_H */ #endif /* __ASM_AVR32_SOCKET_H */
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -72,5 +72,7 @@ ...@@ -72,5 +72,7 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -72,4 +72,6 @@ ...@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -81,4 +81,6 @@ ...@@ -81,4 +81,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_IA64_SOCKET_H */ #endif /* _ASM_IA64_SOCKET_H */
...@@ -72,4 +72,6 @@ ...@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_M32R_SOCKET_H */ #endif /* _ASM_M32R_SOCKET_H */
...@@ -90,4 +90,6 @@ ...@@ -90,4 +90,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _UAPI_ASM_SOCKET_H */ #endif /* _UAPI_ASM_SOCKET_H */
...@@ -72,4 +72,6 @@ ...@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define SO_LOCK_FILTER 0x4025 #define SO_LOCK_FILTER 0x4025
#define SO_SELECT_ERR_QUEUE 0x4026
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we /* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here. * have to define SOCK_NONBLOCK to a different value here.
*/ */
......
...@@ -79,4 +79,6 @@ ...@@ -79,4 +79,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_POWERPC_SOCKET_H */ #endif /* _ASM_POWERPC_SOCKET_H */
...@@ -78,4 +78,6 @@ ...@@ -78,4 +78,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
#define SO_LOCK_FILTER 0x0028 #define SO_LOCK_FILTER 0x0028
#define SO_SELECT_ERR_QUEUE 0x0029
/* Security levels - as per NRL IPv6 - don't actually do anything */ /* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
......
...@@ -83,4 +83,6 @@ ...@@ -83,4 +83,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* _XTENSA_SOCKET_H */ #endif /* _XTENSA_SOCKET_H */
...@@ -667,6 +667,7 @@ enum sock_flags { ...@@ -667,6 +667,7 @@ enum sock_flags {
* user-space instead. * user-space instead.
*/ */
SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
}; };
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
......
...@@ -74,4 +74,6 @@ ...@@ -74,4 +74,6 @@
#define SO_LOCK_FILTER 44 #define SO_LOCK_FILTER 44
#define SO_SELECT_ERR_QUEUE 45
#endif /* __ASM_GENERIC_SOCKET_H */ #endif /* __ASM_GENERIC_SOCKET_H */
...@@ -422,7 +422,8 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, ...@@ -422,7 +422,8 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
return bt_accept_poll(sk); return bt_accept_poll(sk);
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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM; mask |= POLLRDHUP | POLLIN | POLLRDNORM;
......
...@@ -749,7 +749,9 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, ...@@ -749,7 +749,9 @@ 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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM; mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
......
...@@ -907,6 +907,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -907,6 +907,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
sock_valbool_flag(sk, SOCK_NOFCS, valbool); sock_valbool_flag(sk, SOCK_NOFCS, valbool);
break; break;
case SO_SELECT_ERR_QUEUE:
sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
break;
default: default:
ret = -ENOPROTOOPT; ret = -ENOPROTOOPT;
break; break;
...@@ -1160,6 +1164,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -1160,6 +1164,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sock_flag(sk, SOCK_FILTER_LOCKED); v.val = sock_flag(sk, SOCK_FILTER_LOCKED);
break; break;
case SO_SELECT_ERR_QUEUE:
v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE);
break;
default: default:
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
......
...@@ -1461,7 +1461,8 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock, ...@@ -1461,7 +1461,8 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
return iucv_accept_poll(sk); return iucv_accept_poll(sk);
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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP; mask |= POLLRDHUP;
......
...@@ -521,7 +521,8 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock, ...@@ -521,7 +521,8 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
return llcp_accept_poll(sk); return llcp_accept_poll(sk);
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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (!skb_queue_empty(&sk->sk_receive_queue)) if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
......
...@@ -6185,7 +6185,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -6185,7 +6185,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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM; mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
......
...@@ -2196,7 +2196,9 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, ...@@ -2196,7 +2196,9 @@ static unsigned int unix_dgram_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 |
sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM; mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK) if (sk->sk_shutdown == SHUTDOWN_MASK)
......
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