History

Merge tag 'rxrpc-fixes-20190827' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says: ==================== rxrpc: Fix use of skb_cow_data() Here's a series of patches that replaces the use of skb_cow_data() in rxrpc with skb_unshare() early on in the input process. The problem that is being seen is that skb_cow_data() indirectly requires that the maximum usage count on an sk_buff be 1, and it may generate an assertion failure in pskb_expand_head() if not. This can occur because rxrpc_input_data() may be still holding a ref when it has just attached the sk_buff to the rx ring and given that attachment its own ref. If recvmsg happens fast enough, skb_cow_data() can see the ref still held by the softirq handler. Further, a packet may contain multiple subpackets, each of which gets its own attachment to the ring and its own ref - also making skb_cow_data() go bang. Fix this by: (1) The DATA packet is currently parsed for subpackets twice by the input routines. Parse it just once instead and make notes in the sk_buff private data. (2) Use the notes from (1) when attaching the packet to the ring multiple times. Once the packet is attached to the ring, recvmsg can see it and start modifying it, so the softirq handler is not permitted to look inside it from that point. (3) Pass the ref from the input code to the ring rather than getting an extra ref. rxrpc_input_data() uses a ref on the second refcount to prevent the packet from evaporating under it. (4) Call skb_unshare() on secured DATA packets in rxrpc_input_packet() before we take call->input_lock. Other sorts of packets don't get modified and so can be left. A trace is emitted if skb_unshare() eats the skb. Note that skb_share() for our accounting in this regard as we can't see the parameters in the packet to log in a trace line if it releases it. (5) Remove the calls to skb_cow_data(). These are then no longer necessary. There are also patches to improve the rxrpc_skb tracepoint to make sure that Tx-derived buffers are identified separately from Rx-derived buffers in the trace. ====================

David S. Miller committed 7 years ago

Commit a285c1f2 parents 3b25528 d0d5c0c14 files · +319 −268Browse files

Showing the changes to include (1 of 14 files). Show all

Unified · Split

include/trace/events/rxrpc.h+28−31
@@ -23,20 +23,17 @@ · 22 unmodified lines
23#define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY23#define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY
24 24
25enum rxrpc_skb_trace {25enum rxrpc_skb_trace {
26 rxrpc_skb_rx_cleaned,26 rxrpc_skb_cleaned,
27 rxrpc_skb_rx_freed,27 rxrpc_skb_freed,
28 rxrpc_skb_rx_got,28 rxrpc_skb_got,
29 rxrpc_skb_rx_lost,29 rxrpc_skb_lost,
30 rxrpc_skb_rx_purged,30 rxrpc_skb_new,
31 rxrpc_skb_rx_received,31 rxrpc_skb_purged,
32 rxrpc_skb_rx_rotated,32 rxrpc_skb_received,
33 rxrpc_skb_rx_seen,33 rxrpc_skb_rotated,
34 rxrpc_skb_tx_cleaned,34 rxrpc_skb_seen,
35 rxrpc_skb_tx_freed,35 rxrpc_skb_unshared,
36 rxrpc_skb_tx_got,36 rxrpc_skb_unshared_nomem,
37 rxrpc_skb_tx_new,
38 rxrpc_skb_tx_rotated,
39 rxrpc_skb_tx_seen,
40};37};
41 38
42enum rxrpc_local_trace {39enum rxrpc_local_trace {
@@ -228,20 +225,17 @@ enum rxrpc_tx_point { · 185 unmodified lines
228 * Declare tracing information enums and their string mappings for display.225 * Declare tracing information enums and their string mappings for display.
229 */226 */
230#define rxrpc_skb_traces \227#define rxrpc_skb_traces \
231 EM(rxrpc_skb_rx_cleaned, "Rx CLN") \228 EM(rxrpc_skb_cleaned, "CLN") \
232 EM(rxrpc_skb_rx_freed, "Rx FRE") \229 EM(rxrpc_skb_freed, "FRE") \
233 EM(rxrpc_skb_rx_got, "Rx GOT") \230 EM(rxrpc_skb_got, "GOT") \
234 EM(rxrpc_skb_rx_lost, "Rx *L*") \231 EM(rxrpc_skb_lost, "*L*") \
235 EM(rxrpc_skb_rx_purged, "Rx PUR") \232 EM(rxrpc_skb_new, "NEW") \
236 EM(rxrpc_skb_rx_received, "Rx RCV") \233 EM(rxrpc_skb_purged, "PUR") \
237 EM(rxrpc_skb_rx_rotated, "Rx ROT") \234 EM(rxrpc_skb_received, "RCV") \
238 EM(rxrpc_skb_rx_seen, "Rx SEE") \235 EM(rxrpc_skb_rotated, "ROT") \
239 EM(rxrpc_skb_tx_cleaned, "Tx CLN") \236 EM(rxrpc_skb_seen, "SEE") \
240 EM(rxrpc_skb_tx_freed, "Tx FRE") \237 EM(rxrpc_skb_unshared, "UNS") \
241 EM(rxrpc_skb_tx_got, "Tx GOT") \238 E_(rxrpc_skb_unshared_nomem, "US0")
242 EM(rxrpc_skb_tx_new, "Tx NEW") \
243 EM(rxrpc_skb_tx_rotated, "Tx ROT") \
244 E_(rxrpc_skb_tx_seen, "Tx SEE")
245 239
246#define rxrpc_local_traces \240#define rxrpc_local_traces \
247 EM(rxrpc_local_got, "GOT") \241 EM(rxrpc_local_got, "GOT") \
@@ -643,13 +637,14 @@ TRACE_EVENT(rxrpc_call, · 395 unmodified lines
643 637
644TRACE_EVENT(rxrpc_skb,638TRACE_EVENT(rxrpc_skb,
645 TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op,639 TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op,
646 int usage, int mod_count, const void *where),640 int usage, int mod_count, u8 flags, const void *where),
647 641
648 TP_ARGS(skb, op, usage, mod_count, where),642 TP_ARGS(skb, op, usage, mod_count, flags, where),
649 643
650 TP_STRUCT__entry(644 TP_STRUCT__entry(
651 __field(struct sk_buff *, skb )645 __field(struct sk_buff *, skb )
652 __field(enum rxrpc_skb_trace, op )646 __field(enum rxrpc_skb_trace, op )
647 __field(u8, flags )
653 __field(int, usage )648 __field(int, usage )
654 __field(int, mod_count )649 __field(int, mod_count )
655 __field(const void *, where )650 __field(const void *, where )
@@ -657,14 +652,16 @@ TRACE_EVENT(rxrpc_skb, · 1 unmodified line
657 652
658 TP_fast_assign(653 TP_fast_assign(
659 __entry->skb = skb;654 __entry->skb = skb;
655 __entry->flags = flags;
660 __entry->op = op;656 __entry->op = op;
661 __entry->usage = usage;657 __entry->usage = usage;
662 __entry->mod_count = mod_count;658 __entry->mod_count = mod_count;
663 __entry->where = where;659 __entry->where = where;
664 ),660 ),
665 661
666 TP_printk("s=%p %s u=%d m=%d p=%pSR",662 TP_printk("s=%p %cx %s u=%d m=%d p=%pSR",
667 __entry->skb,663 __entry->skb,
664 __entry->flags & RXRPC_SKB_TX_BUFFER ? 'T' : 'R',
668 __print_symbolic(__entry->op, rxrpc_skb_traces),665 __print_symbolic(__entry->op, rxrpc_skb_traces),
669 __entry->usage,666 __entry->usage,
670 __entry->mod_count,667 __entry->mod_count,