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
2323 #define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY
2424
2525 enum rxrpc_skb_trace {
26− rxrpc_skb_rx_cleaned,
27− rxrpc_skb_rx_freed,
28− rxrpc_skb_rx_got,
29− rxrpc_skb_rx_lost,
30− rxrpc_skb_rx_purged,
31− rxrpc_skb_rx_received,
32− rxrpc_skb_rx_rotated,
33− rxrpc_skb_rx_seen,
34− rxrpc_skb_tx_cleaned,
35− rxrpc_skb_tx_freed,
36− rxrpc_skb_tx_got,
37− rxrpc_skb_tx_new,
38− rxrpc_skb_tx_rotated,
39− rxrpc_skb_tx_seen,
26+ rxrpc_skb_cleaned,
27+ rxrpc_skb_freed,
28+ rxrpc_skb_got,
29+ rxrpc_skb_lost,
30+ rxrpc_skb_new,
31+ rxrpc_skb_purged,
32+ rxrpc_skb_received,
33+ rxrpc_skb_rotated,
34+ rxrpc_skb_seen,
35+ rxrpc_skb_unshared,
36+ rxrpc_skb_unshared_nomem,
4037 };
4138
4239 enum rxrpc_local_trace {
@@ -228,20 +225,17 @@ enum rxrpc_tx_point { · 185 unmodified lines
228225 * Declare tracing information enums and their string mappings for display.
229226 */
230227 #define rxrpc_skb_traces \
231− EM(rxrpc_skb_rx_cleaned, "Rx CLN") \
232− EM(rxrpc_skb_rx_freed, "Rx FRE") \
233− EM(rxrpc_skb_rx_got, "Rx GOT") \
234− EM(rxrpc_skb_rx_lost, "Rx *L*") \
235− EM(rxrpc_skb_rx_purged, "Rx PUR") \
236− EM(rxrpc_skb_rx_received, "Rx RCV") \
237− EM(rxrpc_skb_rx_rotated, "Rx ROT") \
238− EM(rxrpc_skb_rx_seen, "Rx SEE") \
239− EM(rxrpc_skb_tx_cleaned, "Tx CLN") \
240− EM(rxrpc_skb_tx_freed, "Tx FRE") \
241− EM(rxrpc_skb_tx_got, "Tx GOT") \
242− EM(rxrpc_skb_tx_new, "Tx NEW") \
243− EM(rxrpc_skb_tx_rotated, "Tx ROT") \
244− E_(rxrpc_skb_tx_seen, "Tx SEE")
228+ EM(rxrpc_skb_cleaned, "CLN") \
229+ EM(rxrpc_skb_freed, "FRE") \
230+ EM(rxrpc_skb_got, "GOT") \
231+ EM(rxrpc_skb_lost, "*L*") \
232+ EM(rxrpc_skb_new, "NEW") \
233+ EM(rxrpc_skb_purged, "PUR") \
234+ EM(rxrpc_skb_received, "RCV") \
235+ EM(rxrpc_skb_rotated, "ROT") \
236+ EM(rxrpc_skb_seen, "SEE") \
237+ EM(rxrpc_skb_unshared, "UNS") \
238+ E_(rxrpc_skb_unshared_nomem, "US0")
245239
246240 #define rxrpc_local_traces \
247241 EM(rxrpc_local_got, "GOT") \
@@ -643,13 +637,14 @@ TRACE_EVENT(rxrpc_call, · 395 unmodified lines
643637
644638 TRACE_EVENT(rxrpc_skb,
645639 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),
647641
648− TP_ARGS(skb, op, usage, mod_count, where),
642+ TP_ARGS(skb, op, usage, mod_count, flags, where),
649643
650644 TP_STRUCT__entry(
651645 __field(struct sk_buff *, skb )
652646 __field(enum rxrpc_skb_trace, op )
647+ __field(u8, flags )
653648 __field(int, usage )
654649 __field(int, mod_count )
655650 __field(const void *, where )
@@ -657,14 +652,16 @@ TRACE_EVENT(rxrpc_skb, · 1 unmodified line
657652
658653 TP_fast_assign(
659654 __entry->skb = skb;
655+ __entry->flags = flags;
660656 __entry->op = op;
661657 __entry->usage = usage;
662658 __entry->mod_count = mod_count;
663659 __entry->where = where;
664660 ),
665661
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",
667663 __entry->skb,
664+ __entry->flags & RXRPC_SKB_TX_BUFFER ? 'T' : 'R',
668665 __print_symbolic(__entry->op, rxrpc_skb_traces),
669666 __entry->usage,
670667 __entry->mod_count,