Skip to content

Commit

Permalink
sfc: free multiple Rx buffers when required
Browse files Browse the repository at this point in the history
When Rx packet data must be dropped, all the buffers
associated with that Rx packet must be freed. Extend
and rename efx_free_rx_buffer() to efx_free_rx_buffers()
and loop through all the fragments.
By doing so this patch fixes a possible memory leak.

Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Daniel Pieczko authored and David S. Miller committed Jun 1, 2015
1 parent fdf7c64 commit 9eb0a5d
Showing 1 changed file with 25 additions and 17 deletions.
42 changes: 25 additions & 17 deletions drivers/net/ethernet/sfc/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,17 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,
}
}

static void efx_free_rx_buffer(struct efx_rx_buffer *rx_buf)
static void efx_free_rx_buffers(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf,
unsigned int num_bufs)
{
if (rx_buf->page) {
put_page(rx_buf->page);
rx_buf->page = NULL;
}
do {
if (rx_buf->page) {
put_page(rx_buf->page);
rx_buf->page = NULL;
}
rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
} while (--num_bufs);
}

/* Attempt to recycle the page if there is an RX recycle ring; the page can
Expand Down Expand Up @@ -278,7 +283,7 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
/* If this is the last buffer in a page, unmap and free it. */
if (rx_buf->flags & EFX_RX_BUF_LAST_IN_PAGE) {
efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
efx_free_rx_buffer(rx_buf);
efx_free_rx_buffers(rx_queue, rx_buf, 1);
}
rx_buf->page = NULL;
}
Expand All @@ -304,10 +309,7 @@ static void efx_discard_rx_packet(struct efx_channel *channel,

efx_recycle_rx_pages(channel, rx_buf, n_frags);

do {
efx_free_rx_buffer(rx_buf);
rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
} while (--n_frags);
efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
}

/**
Expand Down Expand Up @@ -431,11 +433,10 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,

skb = napi_get_frags(napi);
if (unlikely(!skb)) {
while (n_frags--) {
put_page(rx_buf->page);
rx_buf->page = NULL;
rx_buf = efx_rx_buf_next(&channel->rx_queue, rx_buf);
}
struct efx_rx_queue *rx_queue;

rx_queue = efx_channel_get_rx_queue(channel);
efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
return;
}

Expand Down Expand Up @@ -622,7 +623,10 @@ static void efx_rx_deliver(struct efx_channel *channel, u8 *eh,

skb = efx_rx_mk_skb(channel, rx_buf, n_frags, eh, hdr_len);
if (unlikely(skb == NULL)) {
efx_free_rx_buffer(rx_buf);
struct efx_rx_queue *rx_queue;

rx_queue = efx_channel_get_rx_queue(channel);
efx_free_rx_buffers(rx_queue, rx_buf, n_frags);
return;
}
skb_record_rx_queue(skb, channel->rx_queue.core_index);
Expand Down Expand Up @@ -661,8 +665,12 @@ void __efx_rx_packet(struct efx_channel *channel)
* loopback layer, and free the rx_buf here
*/
if (unlikely(efx->loopback_selftest)) {
struct efx_rx_queue *rx_queue;

efx_loopback_rx_packet(efx, eh, rx_buf->len);
efx_free_rx_buffer(rx_buf);
rx_queue = efx_channel_get_rx_queue(channel);
efx_free_rx_buffers(rx_queue, rx_buf,
channel->rx_pkt_n_frags);
goto out;
}

Expand Down

0 comments on commit 9eb0a5d

Please sign in to comment.