sock: Introduce the SO_PEEK_OFF sock option
authorPavel Emelyanov <xemul@parallels.com>
Tue, 21 Feb 2012 07:31:34 +0000 (07:31 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 21 Feb 2012 20:03:48 +0000 (15:03 -0500)
This one specifies where to start MSG_PEEK-ing queue data from. When
set to negative value means that MSG_PEEK works as ususally -- peeks
from the head of the queue always.

When some bytes are peeked from queue and the peeking offset is non
negative it is moved forward so that the next peek will return next
portion of data.

When non-peeking recvmsg occurs and the peeking offset is non negative
is is moved backward so that the next peek will still peek the proper
data (i.e. the one that would have been picked if there were no non
peeking recv in between).

The offset is set using per-proto opteration to let the protocol handle
the locking issues and to check whether the peeking offset feature is
supported by the protocol the socket belongs to.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
20 files changed:
arch/alpha/include/asm/socket.h
arch/arm/include/asm/socket.h
arch/avr32/include/asm/socket.h
arch/cris/include/asm/socket.h
arch/frv/include/asm/socket.h
arch/h8300/include/asm/socket.h
arch/ia64/include/asm/socket.h
arch/m32r/include/asm/socket.h
arch/m68k/include/asm/socket.h
arch/mips/include/asm/socket.h
arch/mn10300/include/asm/socket.h
arch/parisc/include/asm/socket.h
arch/powerpc/include/asm/socket.h
arch/s390/include/asm/socket.h
arch/sparc/include/asm/socket.h
arch/xtensa/include/asm/socket.h
include/asm-generic/socket.h
include/linux/net.h
include/net/sock.h
net/core/sock.c

index 082355f159e67930c284b76d33a4bb7f9a090b3a..16449d330dae91fa33e6559516a45121607b5b30 100644 (file)
@@ -71,6 +71,7 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
index dec6f9afb3cf949de01bb4928dc9ba1429bc9b59..d958c74e5260839c9c35b0a8d5aff6038f320138 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
index 247b88c760bef0615b9b470defb29e8b7645bd1d..30078f98b3ab8f4e228bf200a99374f3fd1c92a1 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* __ASM_AVR32_SOCKET_H */
index e269264df7c4f38b35c8aafa07579a935afd1a23..048aba64600c98dd5cd70e442e32bf725caa10c1 100644 (file)
@@ -66,6 +66,7 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
 
index ce80fdadcce57ad1975c9daab73c823721a21f10..7a361810f3cce60a61fdc0c4a192b5062a149c9b 100644 (file)
@@ -64,6 +64,7 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
 
index cf1daab6f27efb11007af681ee93fb29f64bb63c..e7bbfcee5b9919629e70879d59bc7db672f6cc03 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
index 4b03664e3fb50534b27d9429c951f8b78a272210..ced62de9d5a92fd9d937c9272691655b82a586cd 100644 (file)
@@ -73,5 +73,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_IA64_SOCKET_H */
index e8b8c5bb053c12135328d43fbc00fbe12b7db1b9..696cb4c7ca4e4bb694bfe836ffa29cf9bee0ec7c 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_M32R_SOCKET_H */
index d4708ce466e068d6bc8935cc222eb923fc27b1a7..e8b41a6775f9ce053c3e58e97cc39a8576b3a6c8 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
index ad5c0a7a02a7e34eaff203cf40d0d4b2f235c795..52104872e9e3679136184e068553c138b5b620a0 100644 (file)
@@ -84,6 +84,7 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #ifdef __KERNEL__
 
index 876356d7852248898968f012c8f70c22ad474e1d..013fcc51698f8e72dc7f77afe951f7298c8a1050 100644 (file)
@@ -64,5 +64,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
index d28c51b61067edab8da863ef0bd76861e2a0b4ff..f717c9bec16fe5ea553abddd7eb1534fdc48cf28 100644 (file)
@@ -63,6 +63,7 @@
 
 #define SO_WIFI_STATUS         0x4022
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            0x4023
 
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
index 2fc2af8fbf59b892598844db7a254da4f4251b57..fe1c0b478fd7b7121156e89f1ea218f7018a43a8 100644 (file)
@@ -71,5 +71,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_POWERPC_SOCKET_H */
index 67b5c1b14b51177851efca5e6d86f5a2729e61ea..581702fa1b0c54f8cc96f26e09c5bbb2840908cd 100644 (file)
@@ -72,5 +72,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _ASM_SOCKET_H */
index 8af1b64168b3abb17ddcf2711b9de2ca07b5ce58..68e2e2746f6f87d64c602c04df9f7f01b0d61165 100644 (file)
@@ -60,6 +60,7 @@
 
 #define SO_WIFI_STATUS         0x0025
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            0x0026
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index bb06968be227b0337ab7d77dbee537204fa898c4..74818b161362b5658a13af5aded717d8bad29914 100644 (file)
@@ -75,5 +75,6 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 
 #endif /* _XTENSA_SOCKET_H */
index 49c1704173e757a5e75db1dca27fbf4081aa2dd7..d9aaac0c36d461e2c43c0b7fce61ccccc8602732 100644 (file)
@@ -67,4 +67,5 @@
 
 #define SO_WIFI_STATUS         41
 #define SCM_WIFI_STATUS        SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
 #endif /* __ASM_GENERIC_SOCKET_H */
index b29923006b11e50b4aac2c99f9a81be14afc7fd1..be60c7f5e145d657d158ff58bb80f3ebda2e2fde 100644 (file)
@@ -206,6 +206,7 @@ struct proto_ops {
                                      int offset, size_t size, int flags);
        ssize_t         (*splice_read)(struct socket *sock,  loff_t *ppos,
                                       struct pipe_inode_info *pipe, size_t len, unsigned int flags);
+       void            (*set_peek_off)(struct sock *sk, int val);
 };
 
 #define DECLARE_SOCKADDR(type, dst, src)       \
index 91c1c8baf020d3c5e80df8c3f7eb88323003408f..9c0553b9e451aa07eae214f3dac8a00057f1dbe4 100644 (file)
@@ -357,6 +357,7 @@ struct sock {
        struct page             *sk_sndmsg_page;
        struct sk_buff          *sk_send_head;
        __u32                   sk_sndmsg_off;
+       __s32                   sk_peek_off;
        int                     sk_write_pending;
 #ifdef CONFIG_SECURITY
        void                    *sk_security;
@@ -373,6 +374,30 @@ struct sock {
        void                    (*sk_destruct)(struct sock *sk);
 };
 
+static inline int sk_peek_offset(struct sock *sk, int flags)
+{
+       if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0))
+               return sk->sk_peek_off;
+       else
+               return 0;
+}
+
+static inline void sk_peek_offset_bwd(struct sock *sk, int val)
+{
+       if (sk->sk_peek_off >= 0) {
+               if (sk->sk_peek_off >= val)
+                       sk->sk_peek_off -= val;
+               else
+                       sk->sk_peek_off = 0;
+       }
+}
+
+static inline void sk_peek_offset_fwd(struct sock *sk, int val)
+{
+       if (sk->sk_peek_off >= 0)
+               sk->sk_peek_off += val;
+}
+
 /*
  * Hashed lists helper routines
  */
index 02f8dfe320b771ee96ba3bb5bae52b2974608bd8..19942d4bb6e6e63a6b52ebc51c66698adcc5876a 100644 (file)
@@ -793,6 +793,12 @@ set_rcvbuf:
                sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
                break;
 
+       case SO_PEEK_OFF:
+               if (sock->ops->set_peek_off)
+                       sock->ops->set_peek_off(sk, val);
+               else
+                       ret = -EOPNOTSUPP;
+               break;
        default:
                ret = -ENOPROTOOPT;
                break;
@@ -1018,6 +1024,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
                break;
 
+       case SO_PEEK_OFF:
+               if (!sock->ops->set_peek_off)
+                       return -EOPNOTSUPP;
+
+               v.val = sk->sk_peek_off;
+               break;
        default:
                return -ENOPROTOOPT;
        }
@@ -2092,6 +2104,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        sk->sk_sndmsg_page      =       NULL;
        sk->sk_sndmsg_off       =       0;
+       sk->sk_peek_off         =       -1;
 
        sk->sk_peer_pid         =       NULL;
        sk->sk_peer_cred        =       NULL;