VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / include / net / sock.h
index 8bc7d34..fb4df58 100644 (file)
@@ -53,6 +53,7 @@
 
 #include <asm/atomic.h>
 #include <net/dst.h>
+#include <net/checksum.h>
 
 /*
  * This structure really needs to be cleaned up.
@@ -170,6 +171,11 @@ struct sock_common {
   *    @sk_socket - Identd and reporting IO signals
   *    @sk_user_data - RPC layer private data
   *    @sk_owner - module that owns this socket
+  *    @sk_sndmsg_page - cached page for sendmsg
+  *    @sk_sndmsg_off - cached offset for sendmsg
+  *    @sk_send_head - front of stuff to transmit
+  *    @sk_write_pending - a write to stream socket waits to start
+  *    @sk_queue_shrunk - write queue has been shrunk recently
   *    @sk_state_change - callback to indicate change in the state of the sock
   *    @sk_data_ready - callback to indicate there is data to be processed
   *    @sk_write_space - callback to indicate there is bf sending space available
@@ -254,7 +260,13 @@ struct sock {
        struct socket           *sk_socket;
        void                    *sk_user_data;
        struct module           *sk_owner;
+       struct page             *sk_sndmsg_page;
+       __u32                   sk_sndmsg_off;
+       struct sk_buff          *sk_send_head;
+       int                     sk_write_pending;
        void                    *sk_security;
+       __u8                    sk_queue_shrunk;
+       /* three bytes hole, try to pack */
        void                    (*sk_state_change)(struct sock *sk);
        void                    (*sk_data_ready)(struct sock *sk, int bytes);
        void                    (*sk_write_space)(struct sock *sk);
@@ -421,6 +433,44 @@ static inline int sk_acceptq_is_full(struct sock *sk)
        return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
 }
 
+/*
+ * Compute minimal free write space needed to queue new packets.
+ */
+static inline int sk_stream_min_wspace(struct sock *sk)
+{
+       return sk->sk_wmem_queued / 2;
+}
+
+static inline int sk_stream_wspace(struct sock *sk)
+{
+       return sk->sk_sndbuf - sk->sk_wmem_queued;
+}
+
+extern void sk_stream_write_space(struct sock *sk);
+
+static inline int sk_stream_memory_free(struct sock *sk)
+{
+       return sk->sk_wmem_queued < sk->sk_sndbuf;
+}
+
+extern void sk_stream_rfree(struct sk_buff *skb);
+
+static inline void sk_stream_set_owner_r(struct sk_buff *skb, struct sock *sk)
+{
+       skb->sk = sk;
+       skb->destructor = sk_stream_rfree;
+       atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+       sk->sk_forward_alloc -= skb->truesize;
+}
+
+static inline void sk_stream_free_skb(struct sock *sk, struct sk_buff *skb)
+{
+       sk->sk_queue_shrunk   = 1;
+       sk->sk_wmem_queued   -= skb->truesize;
+       sk->sk_forward_alloc += skb->truesize;
+       __kfree_skb(skb);
+}
+
 /* The per-socket spinlock must be held here. */
 #define sk_add_backlog(__sk, __skb)                            \
 do {   if (!(__sk)->sk_backlog.tail) {                         \
@@ -445,9 +495,15 @@ do {       if (!(__sk)->sk_backlog.tail) {                         \
        rc;                                                     \
 })
 
+extern int sk_stream_wait_connect(struct sock *sk, long *timeo_p);
+extern int sk_stream_wait_memory(struct sock *sk, long *timeo_p);
+extern void sk_stream_wait_close(struct sock *sk, long timeo_p);
+extern int sk_stream_error(struct sock *sk, int flags, int err);
+extern void sk_stream_kill_queues(struct sock *sk);
+
 extern int sk_wait_data(struct sock *sk, long *timeo);
 
-/* IP protocol blocks we attach to sockets.
+/* Networking protocol blocks we attach to sockets.
  * socket layer -> transport layer interface
  * transport -> network interface is defined by struct inet_proto
  */
@@ -491,6 +547,22 @@ struct proto {
        void                    (*unhash)(struct sock *sk);
        int                     (*get_port)(struct sock *sk, unsigned short snum);
 
+       /* Memory pressure */
+       void                    (*enter_memory_pressure)(void);
+       atomic_t                *memory_allocated;      /* Current allocated memory. */
+       atomic_t                *sockets_allocated;     /* Current number of sockets. */
+       /*
+        * Pressure flag: try to collapse.
+        * Technical note: it is used by multiple contexts non atomically.
+        * All the sk_stream_mem_schedule() is of this nature: accounting
+        * is strict, actions are advisory and have some latency.
+        */
+       int                     *memory_pressure;
+       int                     *sysctl_mem;
+       int                     *sysctl_wmem;
+       int                     *sysctl_rmem;
+       int                     max_header;
+
        char                    name[32];
 
        struct {
@@ -553,17 +625,17 @@ struct sock_iocb {
        struct scm_cookie       *scm;
        struct msghdr           *msg, async_msg;
        struct iovec            async_iov;
+       struct kiocb            *kiocb;
 };
 
 static inline struct sock_iocb *kiocb_to_siocb(struct kiocb *iocb)
 {
-       BUG_ON(sizeof(struct sock_iocb) > KIOCB_PRIVATE_SIZE);
        return (struct sock_iocb *)iocb->private;
 }
 
 static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)
 {
-       return container_of((void *)si, struct kiocb, private);
+       return si->kiocb;
 }
 
 struct socket_alloc {
@@ -581,6 +653,37 @@ static inline struct inode *SOCK_INODE(struct socket *socket)
        return &container_of(socket, struct socket_alloc, socket)->vfs_inode;
 }
 
+extern void __sk_stream_mem_reclaim(struct sock *sk);
+extern int sk_stream_mem_schedule(struct sock *sk, int size, int kind);
+
+#define SK_STREAM_MEM_QUANTUM ((int)PAGE_SIZE)
+
+static inline int sk_stream_pages(int amt)
+{
+       return (amt + SK_STREAM_MEM_QUANTUM - 1) / SK_STREAM_MEM_QUANTUM;
+}
+
+static inline void sk_stream_mem_reclaim(struct sock *sk)
+{
+       if (sk->sk_forward_alloc >= SK_STREAM_MEM_QUANTUM)
+               __sk_stream_mem_reclaim(sk);
+}
+
+static inline void sk_stream_writequeue_purge(struct sock *sk)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
+               sk_stream_free_skb(sk, skb);
+       sk_stream_mem_reclaim(sk);
+}
+
+static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb)
+{
+       return (int)skb->truesize <= sk->sk_forward_alloc ||
+               sk_stream_mem_schedule(sk, skb->truesize, 1);
+}
+
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
@@ -675,6 +778,19 @@ extern ssize_t                     sock_no_sendpage(struct socket *sock,
                                                int offset, size_t size, 
                                                int flags);
 
+/*
+ * Functions to fill in entries in struct proto_ops when a protocol
+ * uses the inet style.
+ */
+extern int sock_common_getsockopt(struct socket *sock, int level, int optname,
+                                 char __user *optval, int __user *optlen);
+extern int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
+                              struct msghdr *msg, size_t size, int flags);
+extern int sock_common_setsockopt(struct socket *sock, int level, int optname,
+                                 char __user *optval, int optlen);
+
+extern void sk_common_release(struct sock *sk);
+
 /*
  *     Default socket callbacks and setup code
  */
@@ -809,25 +925,8 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
        write_unlock_bh(&sk->sk_callback_lock);
 }
 
-static inline int sock_i_uid(struct sock *sk)
-{
-       int uid;
-
-       read_lock(&sk->sk_callback_lock);
-       uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0;
-       read_unlock(&sk->sk_callback_lock);
-       return uid;
-}
-
-static inline unsigned long sock_i_ino(struct sock *sk)
-{
-       unsigned long ino;
-
-       read_lock(&sk->sk_callback_lock);
-       ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0;
-       read_unlock(&sk->sk_callback_lock);
-       return ino;
-}
+extern int sock_i_uid(struct sock *sk);
+extern unsigned long sock_i_ino(struct sock *sk);
 
 static inline struct dst_entry *
 __sk_dst_get(struct sock *sk)
@@ -910,6 +1009,34 @@ sk_dst_check(struct sock *sk, u32 cookie)
        return dst;
 }
 
+static inline void sk_charge_skb(struct sock *sk, struct sk_buff *skb)
+{
+       sk->sk_wmem_queued   += skb->truesize;
+       sk->sk_forward_alloc -= skb->truesize;
+}
+
+static inline int skb_copy_to_page(struct sock *sk, char __user *from,
+                                  struct sk_buff *skb, struct page *page,
+                                  int off, int copy)
+{
+       if (skb->ip_summed == CHECKSUM_NONE) {
+               int err = 0;
+               unsigned int csum = csum_and_copy_from_user(from,
+                                                    page_address(page) + off,
+                                                           copy, 0, &err);
+               if (err)
+                       return err;
+               skb->csum = csum_block_add(skb->csum, csum, skb->len);
+       } else if (copy_from_user(page_address(page) + off, from, copy))
+               return -EFAULT;
+
+       skb->len             += copy;
+       skb->data_len        += copy;
+       skb->truesize        += copy;
+       sk->sk_wmem_queued   += copy;
+       sk->sk_forward_alloc -= copy;
+       return 0;
+}
 
 /*
  *     Queue a received datagram if it will fit. Stream and sequenced
@@ -1026,10 +1153,64 @@ static inline void sk_wake_async(struct sock *sk, int how, int band)
 #define SOCK_MIN_SNDBUF 2048
 #define SOCK_MIN_RCVBUF 256
 
+static inline void sk_stream_moderate_sndbuf(struct sock *sk)
+{
+       if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) {
+               sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued / 2);
+               sk->sk_sndbuf = max(sk->sk_sndbuf, SOCK_MIN_SNDBUF);
+       }
+}
+
+static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
+                                                  int size, int mem, int gfp)
+{
+       struct sk_buff *skb = alloc_skb(size + sk->sk_prot->max_header, gfp);
+
+       if (skb) {
+               skb->truesize += mem;
+               if (sk->sk_forward_alloc >= (int)skb->truesize ||
+                   sk_stream_mem_schedule(sk, skb->truesize, 0)) {
+                       skb_reserve(skb, sk->sk_prot->max_header);
+                       return skb;
+               }
+               __kfree_skb(skb);
+       } else {
+               sk->sk_prot->enter_memory_pressure();
+               sk_stream_moderate_sndbuf(sk);
+       }
+       return NULL;
+}
+
+static inline struct sk_buff *sk_stream_alloc_skb(struct sock *sk,
+                                                 int size, int gfp)
+{
+       return sk_stream_alloc_pskb(sk, size, 0, gfp);
+}
+
+static inline struct page *sk_stream_alloc_page(struct sock *sk)
+{
+       struct page *page = NULL;
+
+       if (sk->sk_forward_alloc >= (int)PAGE_SIZE ||
+           sk_stream_mem_schedule(sk, PAGE_SIZE, 0))
+               page = alloc_pages(sk->sk_allocation, 0);
+       else {
+               sk->sk_prot->enter_memory_pressure();
+               sk_stream_moderate_sndbuf(sk);
+       }
+       return page;
+}
+
+#define sk_stream_for_retrans_queue(skb, sk)                           \
+               for (skb = (sk)->sk_write_queue.next;                   \
+                    (skb != (sk)->sk_send_head) &&                     \
+                    (skb != (struct sk_buff *)&(sk)->sk_write_queue);  \
+                    skb = skb->next)
+
 /*
  *     Default write policy as shown to user space via poll/select/SIGIO
  */
-static inline int sock_writeable(struct sock *sk) 
+static inline int sock_writeable(const struct sock *sk) 
 {
        return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf / 2);
 }
@@ -1039,17 +1220,17 @@ static inline int gfp_any(void)
        return in_softirq() ? GFP_ATOMIC : GFP_KERNEL;
 }
 
-static inline long sock_rcvtimeo(struct sock *sk, int noblock)
+static inline long sock_rcvtimeo(const struct sock *sk, int noblock)
 {
        return noblock ? 0 : sk->sk_rcvtimeo;
 }
 
-static inline long sock_sndtimeo(struct sock *sk, int noblock)
+static inline long sock_sndtimeo(const struct sock *sk, int noblock)
 {
        return noblock ? 0 : sk->sk_sndtimeo;
 }
 
-static inline int sock_rcvlowat(struct sock *sk, int waitall, int len)
+static inline int sock_rcvlowat(const struct sock *sk, int waitall, int len)
 {
        return (waitall ? len : min_t(int, sk->sk_rcvlowat, len)) ? : 1;
 }