On Wed, 2016-09-21 at 19:23 +0200, Paolo Abeni wrote: > Avoid usage of common memory accounting functions, since > the logic is pretty much different. > > To account for forward allocation, a couple of new atomic_t > members are added to udp_sock: 'mem_alloced' and 'mem_freed'. > The current forward allocation is estimated as 'mem_alloced' > minus 'mem_freed' minus 'sk_rmem_alloc'. > > When the forward allocation can't cope with the packet to be > enqueued, 'mem_alloced' is incremented by the packet size > rounded-up to the next SK_MEM_QUANTUM. > After a dequeue, we try to partially reclaim of the forward > allocated memory rounded down to an SK_MEM_QUANTUM and > 'mem_freed' is increased by that amount. > sk->sk_forward_alloc is set after each allocated/freed memory > update, to the currently estimated forward allocation, without > any lock or protection. > This value is updated/maintained only to expose some > semi-reasonable value to the eventual reader, and is guaranteed > to be 0 at socket destruction time. > > The above needs custom memory reclaiming on shutdown, provided > by the udp_destruct_sock() helper, which completely reclaim > the allocated forward memory. > > Helpers are provided for skb free, consume and purge, respecting > the above constraints. > > The socket lock is still used to protect the updates to sk_peek_off, > but is acquired only if peeking with offset is enabled. > > As a consequence of the above schema, enqueue to sk_error_queue > will cause larger forward allocation on following normal data > (due to sk_rmem_alloc grow), but this allows amortizing the cost > of the atomic operation on SK_MEM_QUANTUM/skb->truesize packets. > The use of separate atomics for 'mem_alloced' and 'mem_freed' > allows the use of a single atomic operation to protect against > concurrent dequeue. > > Acked-by: Hannes Frederic Sowa <hannes@xxxxxxxxxxxxxxxxxxx> > Signed-off-by: Paolo Abeni <pabeni@xxxxxxxxxx> > --- > include/linux/udp.h | 2 + > include/net/udp.h | 5 ++ > net/ipv4/udp.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 158 insertions(+) > > diff --git a/include/linux/udp.h b/include/linux/udp.h > index d1fd8cd..cd72645 100644 > --- a/include/linux/udp.h > +++ b/include/linux/udp.h > @@ -42,6 +42,8 @@ static inline u32 udp_hashfn(const struct net *net, u32 num, u32 mask) > struct udp_sock { > /* inet_sock has to be the first member */ > struct inet_sock inet; > + atomic_t mem_allocated; > + atomic_t mem_freed; Hi Paolo, thanks for working on this. All this code looks quite invasive to me ? Also does inet_diag properly give the forward_alloc to user ? $ ss -mua State Recv-Q Send-Q Local Address:Port Peer Addres s:Port UNCONN 51584 0 *:52460 *:* skmem:(r51584,rb327680,t0,tb327680,f1664,w0,o0,bl0,d575) Couldn't we instead use an union of an atomic_t and int for sk->sk_forward_alloc ? All udp queues/dequeues would manipulate the atomic_t using regular atomic ops and use a special skb destructor (instead of sock_rfree()) Also I would not bother 'reclaiming' forward_alloc at dequeue, unless udp is under memory pressure. Please share your performance numbers, thanks ! -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html