#define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY
 
 enum rxrpc_skb_trace {
-       rxrpc_skb_rx_cleaned,
-       rxrpc_skb_rx_freed,
-       rxrpc_skb_rx_got,
-       rxrpc_skb_rx_lost,
-       rxrpc_skb_rx_purged,
-       rxrpc_skb_rx_received,
-       rxrpc_skb_rx_rotated,
-       rxrpc_skb_rx_seen,
-       rxrpc_skb_tx_cleaned,
-       rxrpc_skb_tx_freed,
-       rxrpc_skb_tx_got,
-       rxrpc_skb_tx_new,
-       rxrpc_skb_tx_rotated,
-       rxrpc_skb_tx_seen,
+       rxrpc_skb_cleaned,
+       rxrpc_skb_freed,
+       rxrpc_skb_got,
+       rxrpc_skb_lost,
+       rxrpc_skb_new,
+       rxrpc_skb_purged,
+       rxrpc_skb_received,
+       rxrpc_skb_rotated,
+       rxrpc_skb_seen,
 };
 
 enum rxrpc_local_trace {
  * Declare tracing information enums and their string mappings for display.
  */
 #define rxrpc_skb_traces \
-       EM(rxrpc_skb_rx_cleaned,                "Rx CLN") \
-       EM(rxrpc_skb_rx_freed,                  "Rx FRE") \
-       EM(rxrpc_skb_rx_got,                    "Rx GOT") \
-       EM(rxrpc_skb_rx_lost,                   "Rx *L*") \
-       EM(rxrpc_skb_rx_purged,                 "Rx PUR") \
-       EM(rxrpc_skb_rx_received,               "Rx RCV") \
-       EM(rxrpc_skb_rx_rotated,                "Rx ROT") \
-       EM(rxrpc_skb_rx_seen,                   "Rx SEE") \
-       EM(rxrpc_skb_tx_cleaned,                "Tx CLN") \
-       EM(rxrpc_skb_tx_freed,                  "Tx FRE") \
-       EM(rxrpc_skb_tx_got,                    "Tx GOT") \
-       EM(rxrpc_skb_tx_new,                    "Tx NEW") \
-       EM(rxrpc_skb_tx_rotated,                "Tx ROT") \
-       E_(rxrpc_skb_tx_seen,                   "Tx SEE")
+       EM(rxrpc_skb_cleaned,                   "CLN") \
+       EM(rxrpc_skb_freed,                     "FRE") \
+       EM(rxrpc_skb_got,                       "GOT") \
+       EM(rxrpc_skb_lost,                      "*L*") \
+       EM(rxrpc_skb_new,                       "NEW") \
+       EM(rxrpc_skb_purged,                    "PUR") \
+       EM(rxrpc_skb_received,                  "RCV") \
+       EM(rxrpc_skb_rotated,                   "ROT") \
+       E_(rxrpc_skb_seen,                      "SEE")
 
 #define rxrpc_local_traces \
        EM(rxrpc_local_got,                     "GOT") \
            TP_STRUCT__entry(
                    __field(struct sk_buff *,           skb             )
                    __field(enum rxrpc_skb_trace,       op              )
+                   __field(u8,                         flags           )
                    __field(int,                        usage           )
                    __field(int,                        mod_count       )
                    __field(const void *,               where           )
 
            TP_fast_assign(
                    __entry->skb = skb;
+                   __entry->flags = rxrpc_skb(skb)->rx_flags;
                    __entry->op = op;
                    __entry->usage = usage;
                    __entry->mod_count = mod_count;
                    __entry->where = where;
                           ),
 
-           TP_printk("s=%p %s u=%d m=%d p=%pSR",
+           TP_printk("s=%p %cx %s u=%d m=%d p=%pSR",
                      __entry->skb,
+                     __entry->flags & RXRPC_SKB_TX_BUFFER ? 'T' : 'R',
                      __print_symbolic(__entry->op, rxrpc_skb_traces),
                      __entry->usage,
                      __entry->mod_count,
 
  * - max 48 bytes (struct sk_buff::cb)
  */
 struct rxrpc_skb_priv {
+       atomic_t        nr_ring_pins;           /* Number of rxtx ring pins */
        u8              nr_subpackets;          /* Number of subpackets */
        u8              rx_flags;               /* Received packet flags */
 #define RXRPC_SKB_INCL_LAST    0x01            /* - Includes last packet */
 
                        continue;
 
                skb = call->rxtx_buffer[ix];
-               rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
 
                if (anno_type == RXRPC_TX_ANNO_UNACK) {
                        if (ktime_after(skb->tstamp, max_age)) {
                        continue;
 
                skb = call->rxtx_buffer[ix];
-               rxrpc_get_skb(skb, rxrpc_skb_tx_got);
+               rxrpc_get_skb(skb, rxrpc_skb_got);
                spin_unlock_bh(&call->lock);
 
                if (rxrpc_send_data_packet(call, skb, true) < 0) {
-                       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        return;
                }
 
                if (rxrpc_is_client_call(call))
                        rxrpc_expose_client_call(call);
 
-               rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                spin_lock_bh(&call->lock);
 
                /* We need to clear the retransmit state, but there are two
 
        int i;
 
        for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
-               rxrpc_free_skb(call->rxtx_buffer[i],
-                              (call->tx_phase ? rxrpc_skb_tx_cleaned :
-                               rxrpc_skb_rx_cleaned));
+               rxrpc_free_skb(call->rxtx_buffer[i], rxrpc_skb_cleaned);
                call->rxtx_buffer[i] = NULL;
        }
 }
        ASSERTCMP(call->conn, ==, NULL);
 
        rxrpc_cleanup_ring(call);
-       rxrpc_free_skb(call->tx_pending, rxrpc_skb_tx_cleaned);
+       rxrpc_free_skb(call->tx_pending, rxrpc_skb_cleaned);
 
        call_rcu(&call->rcu, rxrpc_rcu_destroy_call);
 }
 
        /* go through the conn-level event packets, releasing the ref on this
         * connection that each one has when we've finished with it */
        while ((skb = skb_dequeue(&conn->rx_queue))) {
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                ret = rxrpc_process_event(conn, skb, &abort_code);
                switch (ret) {
                case -EPROTO:
                        goto requeue_and_leave;
                case -ECONNABORTED:
                default:
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        break;
                }
        }
 protocol_error:
        if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
                goto requeue_and_leave;
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        goto out;
 }
 
                ix = call->tx_hard_ack & RXRPC_RXTX_BUFF_MASK;
                skb = call->rxtx_buffer[ix];
                annotation = call->rxtx_annotations[ix];
-               rxrpc_see_skb(skb, rxrpc_skb_tx_rotated);
+               rxrpc_see_skb(skb, rxrpc_skb_rotated);
                call->rxtx_buffer[ix] = NULL;
                call->rxtx_annotations[ix] = 0;
                skb->next = list;
                skb = list;
                list = skb->next;
                skb_mark_not_on_list(skb);
-               rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        return rot_last;
 
        state = READ_ONCE(call->state);
        if (state >= RXRPC_CALL_COMPLETE) {
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                return;
        }
 
                 * and also rxrpc_fill_out_ack().
                 */
                if (!terminal)
-                       rxrpc_get_skb(skb, rxrpc_skb_rx_got);
+                       rxrpc_get_skb(skb, rxrpc_skb_got);
                call->rxtx_annotations[ix] = annotation;
                smp_wmb();
                call->rxtx_buffer[ix] = skb;
 
 unlock:
        spin_unlock(&call->input_lock);
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" [queued]");
 }
 
                break;
        }
 
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
 no_free:
        _leave("");
 }
                skb_queue_tail(&local->event_queue, skb);
                rxrpc_queue_local(local);
        } else {
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 }
 
                skb_queue_tail(&local->reject_queue, skb);
                rxrpc_queue_local(local);
        } else {
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 }
 
        if (skb->tstamp == 0)
                skb->tstamp = ktime_get_real();
 
-       rxrpc_new_skb(skb, rxrpc_skb_rx_received);
+       rxrpc_new_skb(skb, rxrpc_skb_received);
 
        skb_pull(skb, sizeof(struct udphdr));
 
                static int lose;
                if ((lose++ & 7) == 7) {
                        trace_rxrpc_rx_lose(sp);
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_lost);
+                       rxrpc_free_skb(skb, rxrpc_skb_lost);
                        return 0;
                }
        }
        goto out;
 
 discard:
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
 out:
        trace_rxrpc_rx_done(0, 0);
        return 0;
 
        if (skb) {
                struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
 
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
 
                switch (sp->hdr.type) {
                        break;
                }
 
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        _leave("");
 
        memset(&whdr, 0, sizeof(whdr));
 
        while ((skb = skb_dequeue(&local->reject_queue))) {
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                sp = rxrpc_skb(skb);
 
                switch (skb->mark) {
                        ioc = 2;
                        break;
                default:
-                       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+                       rxrpc_free_skb(skb, rxrpc_skb_freed);
                        continue;
                }
 
                                                      rxrpc_tx_point_reject);
                }
 
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
        }
 
        _leave("");
 
                _leave("UDP socket errqueue empty");
                return;
        }
-       rxrpc_new_skb(skb, rxrpc_skb_rx_received);
+       rxrpc_new_skb(skb, rxrpc_skb_received);
        serr = SKB_EXT_ERR(skb);
        if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
                _leave("UDP empty message");
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                return;
        }
 
                peer = NULL;
        if (!peer) {
                rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                _leave(" [no peer]");
                return;
        }
             serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
                rxrpc_adjust_mtu(peer, serr);
                rcu_read_unlock();
-               rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+               rxrpc_free_skb(skb, rxrpc_skb_freed);
                rxrpc_put_peer(peer);
                _leave(" [MTU update]");
                return;
 
        rxrpc_store_error(peer, serr);
        rcu_read_unlock();
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        rxrpc_put_peer(peer);
 
        _leave("");
 
        hard_ack++;
        ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
        skb = call->rxtx_buffer[ix];
-       rxrpc_see_skb(skb, rxrpc_skb_rx_rotated);
+       rxrpc_see_skb(skb, rxrpc_skb_rotated);
        sp = rxrpc_skb(skb);
 
        subpacket = call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
        /* Barrier against rxrpc_input_data(). */
        smp_store_release(&call->rx_hard_ack, hard_ack);
 
-       rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
 
        trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
        if (last) {
                        break;
                }
                smp_rmb();
-               rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
+               rxrpc_see_skb(skb, rxrpc_skb_seen);
                sp = rxrpc_skb(skb);
 
                if (!(flags & MSG_PEEK)) {
 
        skb->tstamp = ktime_get_real();
 
        ix = seq & RXRPC_RXTX_BUFF_MASK;
-       rxrpc_get_skb(skb, rxrpc_skb_tx_got);
+       rxrpc_get_skb(skb, rxrpc_skb_got);
        call->rxtx_annotations[ix] = annotation;
        smp_wmb();
        call->rxtx_buffer[ix] = skb;
        }
 
 out:
-       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" = %d", ret);
        return ret;
 }
 
        skb = call->tx_pending;
        call->tx_pending = NULL;
-       rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
+       rxrpc_see_skb(skb, rxrpc_skb_seen);
 
        copied = 0;
        do {
 
                        sp = rxrpc_skb(skb);
                        sp->rx_flags |= RXRPC_SKB_TX_BUFFER;
-                       rxrpc_new_skb(skb, rxrpc_skb_tx_new);
+                       rxrpc_new_skb(skb, rxrpc_skb_new);
 
                        _debug("ALLOC SEND %p", skb);
 
        return ret;
 
 call_terminated:
-       rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
+       rxrpc_free_skb(skb, rxrpc_skb_freed);
        _leave(" = %d", call->error);
        return call->error;
 
 
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-#define select_skb_count(op) (op >= rxrpc_skb_tx_cleaned ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs)
+#define is_tx_skb(skb) (rxrpc_skb(skb)->rx_flags & RXRPC_SKB_TX_BUFFER)
+#define select_skb_count(skb) (is_tx_skb(skb) ? &rxrpc_n_tx_skbs : &rxrpc_n_rx_skbs)
 
 /*
  * Note the allocation or reception of a socket buffer.
 void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 {
        const void *here = __builtin_return_address(0);
-       int n = atomic_inc_return(select_skb_count(op));
+       int n = atomic_inc_return(select_skb_count(skb));
        trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
 }
 
 {
        const void *here = __builtin_return_address(0);
        if (skb) {
-               int n = atomic_read(select_skb_count(op));
+               int n = atomic_read(select_skb_count(skb));
                trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
        }
 }
 void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
 {
        const void *here = __builtin_return_address(0);
-       int n = atomic_inc_return(select_skb_count(op));
+       int n = atomic_inc_return(select_skb_count(skb));
        trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
        skb_get(skb);
 }
        if (skb) {
                int n;
                CHECK_SLAB_OKAY(&skb->users);
-               n = atomic_dec_return(select_skb_count(op));
+               n = atomic_dec_return(select_skb_count(skb));
                trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
                kfree_skb(skb);
        }
        const void *here = __builtin_return_address(0);
        struct sk_buff *skb;
        while ((skb = skb_dequeue((list))) != NULL) {
-               int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged));
-               trace_rxrpc_skb(skb, rxrpc_skb_rx_purged,
+               int n = atomic_dec_return(select_skb_count(skb));
+               trace_rxrpc_skb(skb, rxrpc_skb_purged,
                                refcount_read(&skb->users), n, here);
                kfree_skb(skb);
        }