18c3e34a4SDavid Howells /* ar-skbuff.c: socket buffer destruction handling 28c3e34a4SDavid Howells * 38c3e34a4SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 48c3e34a4SDavid Howells * Written by David Howells (dhowells@redhat.com) 58c3e34a4SDavid Howells * 68c3e34a4SDavid Howells * This program is free software; you can redistribute it and/or 78c3e34a4SDavid Howells * modify it under the terms of the GNU General Public License 88c3e34a4SDavid Howells * as published by the Free Software Foundation; either version 98c3e34a4SDavid Howells * 2 of the License, or (at your option) any later version. 108c3e34a4SDavid Howells */ 118c3e34a4SDavid Howells 128c3e34a4SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 138c3e34a4SDavid Howells 148c3e34a4SDavid Howells #include <linux/module.h> 158c3e34a4SDavid Howells #include <linux/net.h> 168c3e34a4SDavid Howells #include <linux/skbuff.h> 178c3e34a4SDavid Howells #include <net/sock.h> 188c3e34a4SDavid Howells #include <net/af_rxrpc.h> 198c3e34a4SDavid Howells #include "ar-internal.h" 208c3e34a4SDavid Howells 21*71f3ca40SDavid Howells #define select_skb_count(op) (op >= rxrpc_skb_tx_cleaned ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs) 22*71f3ca40SDavid Howells 238c3e34a4SDavid Howells /* 24*71f3ca40SDavid Howells * Note the allocation or reception of a socket buffer. 25df844fd4SDavid Howells */ 26*71f3ca40SDavid Howells void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) 27df844fd4SDavid Howells { 28df844fd4SDavid Howells const void *here = __builtin_return_address(0); 29*71f3ca40SDavid Howells int n = atomic_inc_return(select_skb_count(op)); 30*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 31df844fd4SDavid Howells } 32df844fd4SDavid Howells 33df844fd4SDavid Howells /* 34df844fd4SDavid Howells * Note the re-emergence of a socket buffer from a queue or buffer. 35df844fd4SDavid Howells */ 36*71f3ca40SDavid Howells void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) 37df844fd4SDavid Howells { 38df844fd4SDavid Howells const void *here = __builtin_return_address(0); 39df844fd4SDavid Howells if (skb) { 40*71f3ca40SDavid Howells int n = atomic_read(select_skb_count(op)); 41*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 42df844fd4SDavid Howells } 43df844fd4SDavid Howells } 44df844fd4SDavid Howells 45df844fd4SDavid Howells /* 46df844fd4SDavid Howells * Note the addition of a ref on a socket buffer. 47df844fd4SDavid Howells */ 48*71f3ca40SDavid Howells void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) 49df844fd4SDavid Howells { 50df844fd4SDavid Howells const void *here = __builtin_return_address(0); 51*71f3ca40SDavid Howells int n = atomic_inc_return(select_skb_count(op)); 52*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 53df844fd4SDavid Howells skb_get(skb); 54df844fd4SDavid Howells } 55df844fd4SDavid Howells 56df844fd4SDavid Howells /* 57df844fd4SDavid Howells * Note the destruction of a socket buffer. 58df844fd4SDavid Howells */ 59*71f3ca40SDavid Howells void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) 60df844fd4SDavid Howells { 61df844fd4SDavid Howells const void *here = __builtin_return_address(0); 62df844fd4SDavid Howells if (skb) { 63df844fd4SDavid Howells int n; 64df844fd4SDavid Howells CHECK_SLAB_OKAY(&skb->users); 65*71f3ca40SDavid Howells n = atomic_dec_return(select_skb_count(op)); 66*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 67df844fd4SDavid Howells kfree_skb(skb); 68df844fd4SDavid Howells } 69df844fd4SDavid Howells } 70df844fd4SDavid Howells 71df844fd4SDavid Howells /* 72*71f3ca40SDavid Howells * Note the injected loss of a socket buffer. 73*71f3ca40SDavid Howells */ 74*71f3ca40SDavid Howells void rxrpc_lose_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) 75*71f3ca40SDavid Howells { 76*71f3ca40SDavid Howells const void *here = __builtin_return_address(0); 77*71f3ca40SDavid Howells if (skb) { 78*71f3ca40SDavid Howells int n; 79*71f3ca40SDavid Howells CHECK_SLAB_OKAY(&skb->users); 80*71f3ca40SDavid Howells if (op == rxrpc_skb_tx_lost) { 81*71f3ca40SDavid Howells n = atomic_read(select_skb_count(op)); 82*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 83*71f3ca40SDavid Howells } else { 84*71f3ca40SDavid Howells n = atomic_dec_return(select_skb_count(op)); 85*71f3ca40SDavid Howells trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here); 86*71f3ca40SDavid Howells kfree_skb(skb); 87*71f3ca40SDavid Howells } 88*71f3ca40SDavid Howells } 89*71f3ca40SDavid Howells } 90*71f3ca40SDavid Howells 91*71f3ca40SDavid Howells /* 92df844fd4SDavid Howells * Clear a queue of socket buffers. 93df844fd4SDavid Howells */ 94df844fd4SDavid Howells void rxrpc_purge_queue(struct sk_buff_head *list) 95df844fd4SDavid Howells { 96df844fd4SDavid Howells const void *here = __builtin_return_address(0); 97df844fd4SDavid Howells struct sk_buff *skb; 98df844fd4SDavid Howells while ((skb = skb_dequeue((list))) != NULL) { 99*71f3ca40SDavid Howells int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged)); 100*71f3ca40SDavid Howells trace_rxrpc_skb(skb, rxrpc_skb_rx_purged, 101*71f3ca40SDavid Howells atomic_read(&skb->users), n, here); 102df844fd4SDavid Howells kfree_skb(skb); 103df844fd4SDavid Howells } 104df844fd4SDavid Howells } 105