Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 78648
b: refs/heads/master
c: 3ab224b
h: refs/heads/master
v: v3
  • Loading branch information
Hideo Aoki authored and David S. Miller committed Jan 28, 2008
1 parent c04517e commit 1d19aeb
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 176 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a06b494b61de44617dd58612164bdde56fca7bfb
refs/heads/master: 3ab224be6d69de912ee21302745ea45a99274dbc
3 changes: 1 addition & 2 deletions trunk/include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,7 @@ static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
skb->destructor = sctp_sock_rfree;
atomic_add(event->rmem_len, &sk->sk_rmem_alloc);
/*
* This mimics the behavior of
* sk_stream_set_owner_r
* This mimics the behavior of skb_set_owner_r
*/
sk->sk_forward_alloc -= event->rmem_len;
}
Expand Down
98 changes: 57 additions & 41 deletions trunk/include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,25 +460,6 @@ 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)
{
skb_truesize_check(skb);
sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
sk->sk_wmem_queued -= skb->truesize;
sk->sk_forward_alloc += skb->truesize;
__kfree_skb(skb);
}

/* The per-socket spinlock must be held here. */
static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
{
Expand Down Expand Up @@ -576,7 +557,7 @@ struct proto {
/*
* 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
* All the __sk_mem_schedule() is of this nature: accounting
* is strict, actions are advisory and have some latency.
*/
int *memory_pressure;
Expand Down Expand Up @@ -712,33 +693,73 @@ 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);
/*
* Functions for memory accounting
*/
extern int __sk_mem_schedule(struct sock *sk, int size, int kind);
extern void __sk_mem_reclaim(struct sock *sk);

#define SK_STREAM_MEM_QUANTUM ((int)PAGE_SIZE)
#define SK_STREAM_MEM_QUANTUM_SHIFT ilog2(SK_STREAM_MEM_QUANTUM)
#define SK_MEM_QUANTUM ((int)PAGE_SIZE)
#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM)
#define SK_MEM_SEND 0
#define SK_MEM_RECV 1

static inline int sk_stream_pages(int amt)
static inline int sk_mem_pages(int amt)
{
return (amt + SK_STREAM_MEM_QUANTUM - 1) >> SK_STREAM_MEM_QUANTUM_SHIFT;
return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT;
}

static inline void sk_stream_mem_reclaim(struct sock *sk)
static inline int sk_has_account(struct sock *sk)
{
if (sk->sk_forward_alloc >= SK_STREAM_MEM_QUANTUM)
__sk_stream_mem_reclaim(sk);
/* return true if protocol supports memory accounting */
return !!sk->sk_prot->memory_allocated;
}

static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb)
static inline int sk_wmem_schedule(struct sock *sk, int size)
{
return (int)skb->truesize <= sk->sk_forward_alloc ||
sk_stream_mem_schedule(sk, skb->truesize, 1);
if (!sk_has_account(sk))
return 1;
return size <= sk->sk_forward_alloc ||
__sk_mem_schedule(sk, size, SK_MEM_SEND);
}

static inline int sk_stream_wmem_schedule(struct sock *sk, int size)
static inline int sk_rmem_schedule(struct sock *sk, int size)
{
if (!sk_has_account(sk))
return 1;
return size <= sk->sk_forward_alloc ||
sk_stream_mem_schedule(sk, size, 0);
__sk_mem_schedule(sk, size, SK_MEM_RECV);
}

static inline void sk_mem_reclaim(struct sock *sk)
{
if (!sk_has_account(sk))
return;
if (sk->sk_forward_alloc >= SK_MEM_QUANTUM)
__sk_mem_reclaim(sk);
}

static inline void sk_mem_charge(struct sock *sk, int size)
{
if (!sk_has_account(sk))
return;
sk->sk_forward_alloc -= size;
}

static inline void sk_mem_uncharge(struct sock *sk, int size)
{
if (!sk_has_account(sk))
return;
sk->sk_forward_alloc += size;
}

static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
{
skb_truesize_check(skb);
sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
sk->sk_wmem_queued -= skb->truesize;
sk_mem_uncharge(sk, skb->truesize);
__kfree_skb(skb);
}

/* Used by processes to "lock" a socket state, so that
Expand Down Expand Up @@ -1076,12 +1097,6 @@ static inline int sk_can_gso(const struct sock *sk)

extern void sk_setup_caps(struct sock *sk, struct dst_entry *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)
Expand All @@ -1101,7 +1116,7 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
skb->data_len += copy;
skb->truesize += copy;
sk->sk_wmem_queued += copy;
sk->sk_forward_alloc -= copy;
sk_mem_charge(sk, copy);
return 0;
}

Expand All @@ -1127,6 +1142,7 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
skb->sk = sk;
skb->destructor = sock_rfree;
atomic_add(skb->truesize, &sk->sk_rmem_alloc);
sk_mem_charge(sk, skb->truesize);
}

extern void sk_reset_timer(struct sock *sk, struct timer_list* timer,
Expand Down
4 changes: 2 additions & 2 deletions trunk/include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1196,8 +1196,8 @@ static inline void tcp_write_queue_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);
sk_wmem_free_skb(sk, skb);
sk_mem_reclaim(sk);
}

static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/core/datagram.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
{
kfree_skb(skb);
sk_mem_reclaim(sk);
}

/**
Expand Down Expand Up @@ -248,6 +249,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
}

kfree_skb(skb);
sk_mem_reclaim(sk);
return err;
}

Expand Down
104 changes: 104 additions & 0 deletions trunk/net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (err)
goto out;

if (!sk_rmem_schedule(sk, skb->truesize)) {
err = -ENOBUFS;
goto out;
}

skb->dev = NULL;
skb_set_owner_r(skb, sk);

Expand Down Expand Up @@ -1107,7 +1112,9 @@ void sock_rfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;

skb_truesize_check(skb);
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
sk_mem_uncharge(skb->sk, skb->truesize);
}


Expand Down Expand Up @@ -1384,6 +1391,103 @@ int sk_wait_data(struct sock *sk, long *timeo)

EXPORT_SYMBOL(sk_wait_data);

/**
* __sk_mem_schedule - increase sk_forward_alloc and memory_allocated
* @sk: socket
* @size: memory size to allocate
* @kind: allocation type
*
* If kind is SK_MEM_SEND, it means wmem allocation. Otherwise it means
* rmem allocation. This function assumes that protocols which have
* memory_pressure use sk_wmem_queued as write buffer accounting.
*/
int __sk_mem_schedule(struct sock *sk, int size, int kind)
{
struct proto *prot = sk->sk_prot;
int amt = sk_mem_pages(size);
int allocated;

sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
allocated = atomic_add_return(amt, prot->memory_allocated);

/* Under limit. */
if (allocated <= prot->sysctl_mem[0]) {
if (prot->memory_pressure && *prot->memory_pressure)
*prot->memory_pressure = 0;
return 1;
}

/* Under pressure. */
if (allocated > prot->sysctl_mem[1])
if (prot->enter_memory_pressure)
prot->enter_memory_pressure();

/* Over hard limit. */
if (allocated > prot->sysctl_mem[2])
goto suppress_allocation;

/* guarantee minimum buffer size under pressure */
if (kind == SK_MEM_RECV) {
if (atomic_read(&sk->sk_rmem_alloc) < prot->sysctl_rmem[0])
return 1;
} else { /* SK_MEM_SEND */
if (sk->sk_type == SOCK_STREAM) {
if (sk->sk_wmem_queued < prot->sysctl_wmem[0])
return 1;
} else if (atomic_read(&sk->sk_wmem_alloc) <
prot->sysctl_wmem[0])
return 1;
}

if (prot->memory_pressure) {
if (!*prot->memory_pressure ||
prot->sysctl_mem[2] > atomic_read(prot->sockets_allocated) *
sk_mem_pages(sk->sk_wmem_queued +
atomic_read(&sk->sk_rmem_alloc) +
sk->sk_forward_alloc))
return 1;
}

suppress_allocation:

if (kind == SK_MEM_SEND && sk->sk_type == SOCK_STREAM) {
sk_stream_moderate_sndbuf(sk);

/* Fail only if socket is _under_ its sndbuf.
* In this case we cannot block, so that we have to fail.
*/
if (sk->sk_wmem_queued + size >= sk->sk_sndbuf)
return 1;
}

/* Alas. Undo changes. */
sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM;
atomic_sub(amt, prot->memory_allocated);
return 0;
}

EXPORT_SYMBOL(__sk_mem_schedule);

/**
* __sk_reclaim - reclaim memory_allocated
* @sk: socket
*/
void __sk_mem_reclaim(struct sock *sk)
{
struct proto *prot = sk->sk_prot;

atomic_sub(sk->sk_forward_alloc / SK_MEM_QUANTUM,
prot->memory_allocated);
sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1;

if (prot->memory_pressure && *prot->memory_pressure &&
(atomic_read(prot->memory_allocated) < prot->sysctl_mem[0]))
*prot->memory_pressure = 0;
}

EXPORT_SYMBOL(__sk_mem_reclaim);


/*
* Set of default routines for initialising struct proto_ops when
* the protocol does not support a particular function. In certain
Expand Down
Loading

0 comments on commit 1d19aeb

Please sign in to comment.