Commit a285c1fa authored by David S. Miller's avatar David S. Miller

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.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3b25528e d0d5c0cd
...@@ -23,20 +23,17 @@ ...@@ -23,20 +23,17 @@
#define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY #define __RXRPC_DECLARE_TRACE_ENUMS_ONCE_ONLY
enum rxrpc_skb_trace { enum rxrpc_skb_trace {
rxrpc_skb_rx_cleaned, rxrpc_skb_cleaned,
rxrpc_skb_rx_freed, rxrpc_skb_freed,
rxrpc_skb_rx_got, rxrpc_skb_got,
rxrpc_skb_rx_lost, rxrpc_skb_lost,
rxrpc_skb_rx_purged, rxrpc_skb_new,
rxrpc_skb_rx_received, rxrpc_skb_purged,
rxrpc_skb_rx_rotated, rxrpc_skb_received,
rxrpc_skb_rx_seen, rxrpc_skb_rotated,
rxrpc_skb_tx_cleaned, rxrpc_skb_seen,
rxrpc_skb_tx_freed, rxrpc_skb_unshared,
rxrpc_skb_tx_got, rxrpc_skb_unshared_nomem,
rxrpc_skb_tx_new,
rxrpc_skb_tx_rotated,
rxrpc_skb_tx_seen,
}; };
enum rxrpc_local_trace { enum rxrpc_local_trace {
...@@ -228,20 +225,17 @@ enum rxrpc_tx_point { ...@@ -228,20 +225,17 @@ enum rxrpc_tx_point {
* Declare tracing information enums and their string mappings for display. * Declare tracing information enums and their string mappings for display.
*/ */
#define rxrpc_skb_traces \ #define rxrpc_skb_traces \
EM(rxrpc_skb_rx_cleaned, "Rx CLN") \ EM(rxrpc_skb_cleaned, "CLN") \
EM(rxrpc_skb_rx_freed, "Rx FRE") \ EM(rxrpc_skb_freed, "FRE") \
EM(rxrpc_skb_rx_got, "Rx GOT") \ EM(rxrpc_skb_got, "GOT") \
EM(rxrpc_skb_rx_lost, "Rx *L*") \ EM(rxrpc_skb_lost, "*L*") \
EM(rxrpc_skb_rx_purged, "Rx PUR") \ EM(rxrpc_skb_new, "NEW") \
EM(rxrpc_skb_rx_received, "Rx RCV") \ EM(rxrpc_skb_purged, "PUR") \
EM(rxrpc_skb_rx_rotated, "Rx ROT") \ EM(rxrpc_skb_received, "RCV") \
EM(rxrpc_skb_rx_seen, "Rx SEE") \ EM(rxrpc_skb_rotated, "ROT") \
EM(rxrpc_skb_tx_cleaned, "Tx CLN") \ EM(rxrpc_skb_seen, "SEE") \
EM(rxrpc_skb_tx_freed, "Tx FRE") \ EM(rxrpc_skb_unshared, "UNS") \
EM(rxrpc_skb_tx_got, "Tx GOT") \ E_(rxrpc_skb_unshared_nomem, "US0")
EM(rxrpc_skb_tx_new, "Tx NEW") \
EM(rxrpc_skb_tx_rotated, "Tx ROT") \
E_(rxrpc_skb_tx_seen, "Tx SEE")
#define rxrpc_local_traces \ #define rxrpc_local_traces \
EM(rxrpc_local_got, "GOT") \ EM(rxrpc_local_got, "GOT") \
...@@ -643,13 +637,14 @@ TRACE_EVENT(rxrpc_call, ...@@ -643,13 +637,14 @@ TRACE_EVENT(rxrpc_call,
TRACE_EVENT(rxrpc_skb, TRACE_EVENT(rxrpc_skb,
TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op, TP_PROTO(struct sk_buff *skb, enum rxrpc_skb_trace op,
int usage, int mod_count, const void *where), int usage, int mod_count, u8 flags, const void *where),
TP_ARGS(skb, op, usage, mod_count, where), TP_ARGS(skb, op, usage, mod_count, flags, where),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(struct sk_buff *, skb ) __field(struct sk_buff *, skb )
__field(enum rxrpc_skb_trace, op ) __field(enum rxrpc_skb_trace, op )
__field(u8, flags )
__field(int, usage ) __field(int, usage )
__field(int, mod_count ) __field(int, mod_count )
__field(const void *, where ) __field(const void *, where )
...@@ -657,14 +652,16 @@ TRACE_EVENT(rxrpc_skb, ...@@ -657,14 +652,16 @@ TRACE_EVENT(rxrpc_skb,
TP_fast_assign( TP_fast_assign(
__entry->skb = skb; __entry->skb = skb;
__entry->flags = flags;
__entry->op = op; __entry->op = op;
__entry->usage = usage; __entry->usage = usage;
__entry->mod_count = mod_count; __entry->mod_count = mod_count;
__entry->where = where; __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->skb,
__entry->flags & RXRPC_SKB_TX_BUFFER ? 'T' : 'R',
__print_symbolic(__entry->op, rxrpc_skb_traces), __print_symbolic(__entry->op, rxrpc_skb_traces),
__entry->usage, __entry->usage,
__entry->mod_count, __entry->mod_count,
......
...@@ -185,11 +185,17 @@ struct rxrpc_host_header { ...@@ -185,11 +185,17 @@ struct rxrpc_host_header {
* - max 48 bytes (struct sk_buff::cb) * - max 48 bytes (struct sk_buff::cb)
*/ */
struct rxrpc_skb_priv { struct rxrpc_skb_priv {
union { atomic_t nr_ring_pins; /* Number of rxtx ring pins */
u8 nr_jumbo; /* Number of jumbo subpackets */ u8 nr_subpackets; /* Number of subpackets */
}; u8 rx_flags; /* Received packet flags */
#define RXRPC_SKB_INCL_LAST 0x01 /* - Includes last packet */
#define RXRPC_SKB_TX_BUFFER 0x02 /* - Is transmit buffer */
union { union {
int remain; /* amount of space remaining for next write */ int remain; /* amount of space remaining for next write */
/* List of requested ACKs on subpackets */
unsigned long rx_req_ack[(RXRPC_MAX_NR_JUMBO + BITS_PER_LONG - 1) /
BITS_PER_LONG];
}; };
struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */ struct rxrpc_host_header hdr; /* RxRPC packet header from this packet */
...@@ -613,8 +619,7 @@ struct rxrpc_call { ...@@ -613,8 +619,7 @@ struct rxrpc_call {
#define RXRPC_TX_ANNO_LAST 0x04 #define RXRPC_TX_ANNO_LAST 0x04
#define RXRPC_TX_ANNO_RESENT 0x08 #define RXRPC_TX_ANNO_RESENT 0x08
#define RXRPC_RX_ANNO_JUMBO 0x3f /* Jumbo subpacket number + 1 if not zero */ #define RXRPC_RX_ANNO_SUBPACKET 0x3f /* Subpacket number in jumbogram */
#define RXRPC_RX_ANNO_JLAST 0x40 /* Set if last element of a jumbo packet */
#define RXRPC_RX_ANNO_VERIFIED 0x80 /* Set if verified and decrypted */ #define RXRPC_RX_ANNO_VERIFIED 0x80 /* Set if verified and decrypted */
rxrpc_seq_t tx_hard_ack; /* Dead slot in buffer; the first transmitted but rxrpc_seq_t tx_hard_ack; /* Dead slot in buffer; the first transmitted but
* not hard-ACK'd packet follows this. * not hard-ACK'd packet follows this.
...@@ -1105,6 +1110,7 @@ void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *); ...@@ -1105,6 +1110,7 @@ void rxrpc_kernel_data_consumed(struct rxrpc_call *, struct sk_buff *);
void rxrpc_packet_destructor(struct sk_buff *); void rxrpc_packet_destructor(struct sk_buff *);
void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_new_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_see_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_eaten_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_get_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace); void rxrpc_free_skb(struct sk_buff *, enum rxrpc_skb_trace);
void rxrpc_purge_queue(struct sk_buff_head *); void rxrpc_purge_queue(struct sk_buff_head *);
......
...@@ -199,7 +199,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j) ...@@ -199,7 +199,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
continue; continue;
skb = call->rxtx_buffer[ix]; 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 (anno_type == RXRPC_TX_ANNO_UNACK) {
if (ktime_after(skb->tstamp, max_age)) { if (ktime_after(skb->tstamp, max_age)) {
...@@ -255,18 +255,18 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j) ...@@ -255,18 +255,18 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
continue; continue;
skb = call->rxtx_buffer[ix]; 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); spin_unlock_bh(&call->lock);
if (rxrpc_send_data_packet(call, skb, true) < 0) { 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; return;
} }
if (rxrpc_is_client_call(call)) if (rxrpc_is_client_call(call))
rxrpc_expose_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); spin_lock_bh(&call->lock);
/* We need to clear the retransmit state, but there are two /* We need to clear the retransmit state, but there are two
......
...@@ -421,6 +421,19 @@ void rxrpc_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) ...@@ -421,6 +421,19 @@ void rxrpc_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
trace_rxrpc_call(call, op, n, here, NULL); trace_rxrpc_call(call, op, n, here, NULL);
} }
/*
* Clean up the RxTx skb ring.
*/
static void rxrpc_cleanup_ring(struct rxrpc_call *call)
{
int i;
for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
rxrpc_free_skb(call->rxtx_buffer[i], rxrpc_skb_cleaned);
call->rxtx_buffer[i] = NULL;
}
}
/* /*
* Detach a call from its owning socket. * Detach a call from its owning socket.
*/ */
...@@ -429,7 +442,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) ...@@ -429,7 +442,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
struct rxrpc_connection *conn = call->conn; struct rxrpc_connection *conn = call->conn;
bool put = false; bool put = false;
int i;
_enter("{%d,%d}", call->debug_id, atomic_read(&call->usage)); _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage));
...@@ -479,13 +491,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) ...@@ -479,13 +491,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
if (conn) if (conn)
rxrpc_disconnect_call(call); rxrpc_disconnect_call(call);
for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) { rxrpc_cleanup_ring(call);
rxrpc_free_skb(call->rxtx_buffer[i],
(call->tx_phase ? rxrpc_skb_tx_cleaned :
rxrpc_skb_rx_cleaned));
call->rxtx_buffer[i] = NULL;
}
_leave(""); _leave("");
} }
...@@ -568,8 +574,6 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu) ...@@ -568,8 +574,6 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu)
*/ */
void rxrpc_cleanup_call(struct rxrpc_call *call) void rxrpc_cleanup_call(struct rxrpc_call *call)
{ {
int i;
_net("DESTROY CALL %d", call->debug_id); _net("DESTROY CALL %d", call->debug_id);
memset(&call->sock_node, 0xcd, sizeof(call->sock_node)); memset(&call->sock_node, 0xcd, sizeof(call->sock_node));
...@@ -580,13 +584,8 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) ...@@ -580,13 +584,8 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
ASSERTCMP(call->conn, ==, NULL); ASSERTCMP(call->conn, ==, NULL);
/* Clean up the Rx/Tx buffer */ rxrpc_cleanup_ring(call);
for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) rxrpc_free_skb(call->tx_pending, rxrpc_skb_cleaned);
rxrpc_free_skb(call->rxtx_buffer[i],
(call->tx_phase ? rxrpc_skb_tx_cleaned :
rxrpc_skb_rx_cleaned));
rxrpc_free_skb(call->tx_pending, rxrpc_skb_tx_cleaned);
call_rcu(&call->rcu, rxrpc_rcu_destroy_call); call_rcu(&call->rcu, rxrpc_rcu_destroy_call);
} }
......
...@@ -472,7 +472,7 @@ void rxrpc_process_connection(struct work_struct *work) ...@@ -472,7 +472,7 @@ void rxrpc_process_connection(struct work_struct *work)
/* go through the conn-level event packets, releasing the ref on this /* go through the conn-level event packets, releasing the ref on this
* connection that each one has when we've finished with it */ * connection that each one has when we've finished with it */
while ((skb = skb_dequeue(&conn->rx_queue))) { 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); ret = rxrpc_process_event(conn, skb, &abort_code);
switch (ret) { switch (ret) {
case -EPROTO: case -EPROTO:
...@@ -484,7 +484,7 @@ void rxrpc_process_connection(struct work_struct *work) ...@@ -484,7 +484,7 @@ void rxrpc_process_connection(struct work_struct *work)
goto requeue_and_leave; goto requeue_and_leave;
case -ECONNABORTED: case -ECONNABORTED:
default: default:
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
break; break;
} }
} }
...@@ -501,6 +501,6 @@ void rxrpc_process_connection(struct work_struct *work) ...@@ -501,6 +501,6 @@ void rxrpc_process_connection(struct work_struct *work)
protocol_error: protocol_error:
if (rxrpc_abort_connection(conn, ret, abort_code) < 0) if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
goto requeue_and_leave; goto requeue_and_leave;
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
goto out; goto out;
} }
This diff is collapsed.
...@@ -90,7 +90,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local) ...@@ -90,7 +90,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
if (skb) { if (skb) {
struct rxrpc_skb_priv *sp = rxrpc_skb(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); _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
switch (sp->hdr.type) { switch (sp->hdr.type) {
...@@ -108,7 +108,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local) ...@@ -108,7 +108,7 @@ void rxrpc_process_local_events(struct rxrpc_local *local)
break; break;
} }
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
} }
_leave(""); _leave("");
......
...@@ -565,7 +565,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local) ...@@ -565,7 +565,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
memset(&whdr, 0, sizeof(whdr)); memset(&whdr, 0, sizeof(whdr));
while ((skb = skb_dequeue(&local->reject_queue))) { 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); sp = rxrpc_skb(skb);
switch (skb->mark) { switch (skb->mark) {
...@@ -581,7 +581,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local) ...@@ -581,7 +581,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
ioc = 2; ioc = 2;
break; break;
default: default:
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
continue; continue;
} }
...@@ -606,7 +606,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local) ...@@ -606,7 +606,7 @@ void rxrpc_reject_packets(struct rxrpc_local *local)
rxrpc_tx_point_reject); rxrpc_tx_point_reject);
} }
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
} }
_leave(""); _leave("");
......
...@@ -163,11 +163,11 @@ void rxrpc_error_report(struct sock *sk) ...@@ -163,11 +163,11 @@ void rxrpc_error_report(struct sock *sk)
_leave("UDP socket errqueue empty"); _leave("UDP socket errqueue empty");
return; return;
} }
rxrpc_new_skb(skb, rxrpc_skb_rx_received); rxrpc_new_skb(skb, rxrpc_skb_received);
serr = SKB_EXT_ERR(skb); serr = SKB_EXT_ERR(skb);
if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
_leave("UDP empty message"); _leave("UDP empty message");
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
return; return;
} }
...@@ -177,7 +177,7 @@ void rxrpc_error_report(struct sock *sk) ...@@ -177,7 +177,7 @@ void rxrpc_error_report(struct sock *sk)
peer = NULL; peer = NULL;
if (!peer) { if (!peer) {
rcu_read_unlock(); rcu_read_unlock();
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
_leave(" [no peer]"); _leave(" [no peer]");
return; return;
} }
...@@ -189,7 +189,7 @@ void rxrpc_error_report(struct sock *sk) ...@@ -189,7 +189,7 @@ void rxrpc_error_report(struct sock *sk)
serr->ee.ee_code == ICMP_FRAG_NEEDED)) { serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
rxrpc_adjust_mtu(peer, serr); rxrpc_adjust_mtu(peer, serr);
rcu_read_unlock(); rcu_read_unlock();
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
rxrpc_put_peer(peer); rxrpc_put_peer(peer);
_leave(" [MTU update]"); _leave(" [MTU update]");
return; return;
...@@ -197,7 +197,7 @@ void rxrpc_error_report(struct sock *sk) ...@@ -197,7 +197,7 @@ void rxrpc_error_report(struct sock *sk)
rxrpc_store_error(peer, serr); rxrpc_store_error(peer, serr);
rcu_read_unlock(); rcu_read_unlock();
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
rxrpc_put_peer(peer); rxrpc_put_peer(peer);
_leave(""); _leave("");
......
...@@ -89,6 +89,15 @@ struct rxrpc_jumbo_header { ...@@ -89,6 +89,15 @@ struct rxrpc_jumbo_header {
#define RXRPC_JUMBO_DATALEN 1412 /* non-terminal jumbo packet data length */ #define RXRPC_JUMBO_DATALEN 1412 /* non-terminal jumbo packet data length */
#define RXRPC_JUMBO_SUBPKTLEN (RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header)) #define RXRPC_JUMBO_SUBPKTLEN (RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header))
/*
* The maximum number of subpackets that can possibly fit in a UDP packet is:
*
* ((max_IP - IP_hdr - UDP_hdr) / RXRPC_JUMBO_SUBPKTLEN) + 1
* = ((65535 - 28 - 28) / 1416) + 1
* = 46 non-terminal packets and 1 terminal packet.
*/
#define RXRPC_MAX_NR_JUMBO 47
/*****************************************************************************/ /*****************************************************************************/
/* /*
* on-the-wire Rx ACK packet data payload * on-the-wire Rx ACK packet data payload
......
...@@ -177,7 +177,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) ...@@ -177,7 +177,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
struct sk_buff *skb; struct sk_buff *skb;
rxrpc_serial_t serial; rxrpc_serial_t serial;
rxrpc_seq_t hard_ack, top; rxrpc_seq_t hard_ack, top;
u8 flags; bool last = false;
u8 subpacket;
int ix; int ix;
_enter("%d", call->debug_id); _enter("%d", call->debug_id);
...@@ -189,23 +190,25 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) ...@@ -189,23 +190,25 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
hard_ack++; hard_ack++;
ix = hard_ack & RXRPC_RXTX_BUFF_MASK; ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
skb = call->rxtx_buffer[ix]; skb = call->rxtx_buffer[ix];
rxrpc_see_skb(skb, rxrpc_skb_rx_rotated); rxrpc_see_skb(skb, rxrpc_skb_rotated);
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
flags = sp->hdr.flags;
serial = sp->hdr.serial; subpacket = call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
if (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO) serial = sp->hdr.serial + subpacket;
serial += (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO) - 1;
if (subpacket == sp->nr_subpackets - 1 &&
sp->rx_flags & RXRPC_SKB_INCL_LAST)
last = true;
call->rxtx_buffer[ix] = NULL; call->rxtx_buffer[ix] = NULL;
call->rxtx_annotations[ix] = 0; call->rxtx_annotations[ix] = 0;
/* Barrier against rxrpc_input_data(). */ /* Barrier against rxrpc_input_data(). */
smp_store_release(&call->rx_hard_ack, hard_ack); smp_store_release(&call->rx_hard_ack, hard_ack);
rxrpc_free_skb(skb, rxrpc_skb_rx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
_debug("%u,%u,%02x", hard_ack, top, flags);
trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack); trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
if (flags & RXRPC_LAST_PACKET) { if (last) {
rxrpc_end_rx_phase(call, serial); rxrpc_end_rx_phase(call, serial);
} else { } else {
/* Check to see if there's an ACK that needs sending. */ /* Check to see if there's an ACK that needs sending. */
...@@ -233,18 +236,19 @@ static int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -233,18 +236,19 @@ static int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
rxrpc_seq_t seq = sp->hdr.seq; rxrpc_seq_t seq = sp->hdr.seq;
u16 cksum = sp->hdr.cksum; u16 cksum = sp->hdr.cksum;
u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
_enter(""); _enter("");
/* For all but the head jumbo subpacket, the security checksum is in a /* For all but the head jumbo subpacket, the security checksum is in a
* jumbo header immediately prior to the data. * jumbo header immediately prior to the data.
*/ */
if ((annotation & RXRPC_RX_ANNO_JUMBO) > 1) { if (subpacket > 0) {
__be16 tmp; __be16 tmp;
if (skb_copy_bits(skb, offset - 2, &tmp, 2) < 0) if (skb_copy_bits(skb, offset - 2, &tmp, 2) < 0)
BUG(); BUG();
cksum = ntohs(tmp); cksum = ntohs(tmp);
seq += (annotation & RXRPC_RX_ANNO_JUMBO) - 1; seq += subpacket;
} }
return call->conn->security->verify_packet(call, skb, offset, len, return call->conn->security->verify_packet(call, skb, offset, len,
...@@ -265,19 +269,18 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -265,19 +269,18 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
u8 *_annotation, u8 *_annotation,
unsigned int *_offset, unsigned int *_len) unsigned int *_offset, unsigned int *_len)
{ {
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
unsigned int offset = sizeof(struct rxrpc_wire_header); unsigned int offset = sizeof(struct rxrpc_wire_header);
unsigned int len; unsigned int len;
int ret; int ret;
u8 annotation = *_annotation; u8 annotation = *_annotation;
u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
/* Locate the subpacket */ /* Locate the subpacket */
offset += subpacket * RXRPC_JUMBO_SUBPKTLEN;
len = skb->len - offset; len = skb->len - offset;
if ((annotation & RXRPC_RX_ANNO_JUMBO) > 0) { if (subpacket < sp->nr_subpackets - 1)
offset += (((annotation & RXRPC_RX_ANNO_JUMBO) - 1) * len = RXRPC_JUMBO_DATALEN;
RXRPC_JUMBO_SUBPKTLEN);
len = (annotation & RXRPC_RX_ANNO_JLAST) ?
skb->len - offset : RXRPC_JUMBO_SUBPKTLEN;
}
if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) { if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) {
ret = rxrpc_verify_packet(call, skb, annotation, offset, len); ret = rxrpc_verify_packet(call, skb, annotation, offset, len);
...@@ -303,6 +306,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -303,6 +306,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
{ {
struct rxrpc_skb_priv *sp; struct rxrpc_skb_priv *sp;
struct sk_buff *skb; struct sk_buff *skb;
rxrpc_serial_t serial;
rxrpc_seq_t hard_ack, top, seq; rxrpc_seq_t hard_ack, top, seq;
size_t remain; size_t remain;
bool last; bool last;
...@@ -336,12 +340,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -336,12 +340,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
break; break;
} }
smp_rmb(); smp_rmb();
rxrpc_see_skb(skb, rxrpc_skb_rx_seen); rxrpc_see_skb(skb, rxrpc_skb_seen);
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK)) {
serial = sp->hdr.serial;
serial += call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
trace_rxrpc_receive(call, rxrpc_receive_front, trace_rxrpc_receive(call, rxrpc_receive_front,
sp->hdr.serial, seq); serial, seq);
}
if (msg) if (msg)
sock_recv_timestamp(msg, sock->sk, skb); sock_recv_timestamp(msg, sock->sk, skb);
......
...@@ -187,10 +187,8 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, ...@@ -187,10 +187,8 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
struct rxrpc_skb_priv *sp; struct rxrpc_skb_priv *sp;
struct rxrpc_crypt iv; struct rxrpc_crypt iv;
struct scatterlist sg[16]; struct scatterlist sg[16];
struct sk_buff *trailer;
unsigned int len; unsigned int len;
u16 check; u16 check;
int nsg;
int err; int err;
sp = rxrpc_skb(skb); sp = rxrpc_skb(skb);
...@@ -214,15 +212,14 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, ...@@ -214,15 +212,14 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
crypto_skcipher_encrypt(req); crypto_skcipher_encrypt(req);
/* we want to encrypt the skbuff in-place */ /* we want to encrypt the skbuff in-place */
nsg = skb_cow_data(skb, 0, &trailer); err = -EMSGSIZE;
err = -ENOMEM; if (skb_shinfo(skb)->nr_frags > 16)
if (nsg < 0 || nsg > 16)
goto out; goto out;
len = data_size + call->conn->size_align - 1; len = data_size + call->conn->size_align - 1;
len &= ~(call->conn->size_align - 1); len &= ~(call->conn->size_align - 1);
sg_init_table(sg, nsg); sg_init_table(sg, ARRAY_SIZE(sg));
err = skb_to_sgvec(skb, sg, 0, len); err = skb_to_sgvec(skb, sg, 0, len);
if (unlikely(err < 0)) if (unlikely(err < 0))
goto out; goto out;
...@@ -319,11 +316,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -319,11 +316,10 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
struct rxkad_level1_hdr sechdr; struct rxkad_level1_hdr sechdr;
struct rxrpc_crypt iv; struct rxrpc_crypt iv;
struct scatterlist sg[16]; struct scatterlist sg[16];
struct sk_buff *trailer;
bool aborted; bool aborted;
u32 data_size, buf; u32 data_size, buf;
u16 check; u16 check;
int nsg, ret; int ret;
_enter(""); _enter("");
...@@ -336,11 +332,7 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -336,11 +332,7 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
/* Decrypt the skbuff in-place. TODO: We really want to decrypt /* Decrypt the skbuff in-place. TODO: We really want to decrypt
* directly into the target buffer. * directly into the target buffer.
*/ */
nsg = skb_cow_data(skb, 0, &trailer); sg_init_table(sg, ARRAY_SIZE(sg));
if (nsg < 0 || nsg > 16)
goto nomem;
sg_init_table(sg, nsg);
ret = skb_to_sgvec(skb, sg, offset, 8); ret = skb_to_sgvec(skb, sg, offset, 8);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
...@@ -388,10 +380,6 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -388,10 +380,6 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
if (aborted) if (aborted)
rxrpc_send_abort_packet(call); rxrpc_send_abort_packet(call);
return -EPROTO; return -EPROTO;
nomem:
_leave(" = -ENOMEM");
return -ENOMEM;
} }
/* /*
...@@ -406,7 +394,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -406,7 +394,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
struct rxkad_level2_hdr sechdr; struct rxkad_level2_hdr sechdr;
struct rxrpc_crypt iv; struct rxrpc_crypt iv;
struct scatterlist _sg[4], *sg; struct scatterlist _sg[4], *sg;
struct sk_buff *trailer;
bool aborted; bool aborted;
u32 data_size, buf; u32 data_size, buf;
u16 check; u16 check;
...@@ -423,12 +410,11 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, ...@@ -423,12 +410,11 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
/* Decrypt the skbuff in-place. TODO: We really want to decrypt /* Decrypt the skbuff in-place. TODO: We really want to decrypt
* directly into the target buffer. * directly into the target buffer.
*/ */
nsg = skb_cow_data(skb, 0, &trailer);
if (nsg < 0)
goto nomem;
sg = _sg; sg = _sg;
if (unlikely(nsg > 4)) { nsg = skb_shinfo(skb)->nr_frags;
if (nsg <= 4) {
nsg = 4;
} else {
sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO); sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
if (!sg) if (!sg)
goto nomem; goto nomem;
......
...@@ -176,7 +176,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, ...@@ -176,7 +176,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
skb->tstamp = ktime_get_real(); skb->tstamp = ktime_get_real();
ix = seq & RXRPC_RXTX_BUFF_MASK; 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; call->rxtx_annotations[ix] = annotation;
smp_wmb(); smp_wmb();
call->rxtx_buffer[ix] = skb; call->rxtx_buffer[ix] = skb;
...@@ -248,7 +248,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, ...@@ -248,7 +248,7 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
} }
out: out:
rxrpc_free_skb(skb, rxrpc_skb_tx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;
} }
...@@ -289,7 +289,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, ...@@ -289,7 +289,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
skb = call->tx_pending; skb = call->tx_pending;
call->tx_pending = NULL; call->tx_pending = NULL;
rxrpc_see_skb(skb, rxrpc_skb_tx_seen); rxrpc_see_skb(skb, rxrpc_skb_seen);
copied = 0; copied = 0;
do { do {
...@@ -336,7 +336,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, ...@@ -336,7 +336,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
if (!skb) if (!skb)
goto maybe_error; goto maybe_error;
rxrpc_new_skb(skb, rxrpc_skb_tx_new); sp = rxrpc_skb(skb);
sp->rx_flags |= RXRPC_SKB_TX_BUFFER;
rxrpc_new_skb(skb, rxrpc_skb_new);
_debug("ALLOC SEND %p", skb); _debug("ALLOC SEND %p", skb);
...@@ -346,7 +348,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, ...@@ -346,7 +348,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
skb_reserve(skb, call->conn->security_size); skb_reserve(skb, call->conn->security_size);
skb->len += call->conn->security_size; skb->len += call->conn->security_size;
sp = rxrpc_skb(skb);
sp->remain = chunk; sp->remain = chunk;
if (sp->remain > skb_tailroom(skb)) if (sp->remain > skb_tailroom(skb))
sp->remain = skb_tailroom(skb); sp->remain = skb_tailroom(skb);
...@@ -439,7 +440,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, ...@@ -439,7 +440,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
return ret; return ret;
call_terminated: call_terminated:
rxrpc_free_skb(skb, rxrpc_skb_tx_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
_leave(" = %d", call->error); _leave(" = %d", call->error);
return call->error; return call->error;
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
#include <net/af_rxrpc.h> #include <net/af_rxrpc.h>
#include "ar-internal.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. * Note the allocation or reception of a socket buffer.
...@@ -22,8 +23,9 @@ ...@@ -22,8 +23,9 @@
void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{ {
const void *here = __builtin_return_address(0); 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); trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
rxrpc_skb(skb)->rx_flags, here);
} }
/* /*
...@@ -33,8 +35,9 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) ...@@ -33,8 +35,9 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
if (skb) { 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); trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
rxrpc_skb(skb)->rx_flags, here);
} }
} }
...@@ -44,11 +47,22 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) ...@@ -44,11 +47,22 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{ {
const void *here = __builtin_return_address(0); 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); trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
rxrpc_skb(skb)->rx_flags, here);
skb_get(skb); skb_get(skb);
} }
/*
* Note the dropping of a ref on a socket buffer by the core.
*/
void rxrpc_eaten_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{
const void *here = __builtin_return_address(0);
int n = atomic_inc_return(&rxrpc_n_rx_skbs);
trace_rxrpc_skb(skb, op, 0, n, 0, here);
}
/* /*
* Note the destruction of a socket buffer. * Note the destruction of a socket buffer.
*/ */
...@@ -58,8 +72,9 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) ...@@ -58,8 +72,9 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
if (skb) { if (skb) {
int n; int n;
CHECK_SLAB_OKAY(&skb->users); 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); trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n,
rxrpc_skb(skb)->rx_flags, here);
kfree_skb(skb); kfree_skb(skb);
} }
} }
...@@ -72,9 +87,10 @@ void rxrpc_purge_queue(struct sk_buff_head *list) ...@@ -72,9 +87,10 @@ void rxrpc_purge_queue(struct sk_buff_head *list)
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue((list))) != NULL) { while ((skb = skb_dequeue((list))) != NULL) {
int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged)); int n = atomic_dec_return(select_skb_count(skb));
trace_rxrpc_skb(skb, rxrpc_skb_rx_purged, trace_rxrpc_skb(skb, rxrpc_skb_purged,
refcount_read(&skb->users), n, here); refcount_read(&skb->users), n,
rxrpc_skb(skb)->rx_flags, here);
kfree_skb(skb); kfree_skb(skb);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment