Commit ad4b3d5e authored by duanqiangwen's avatar duanqiangwen Committed by Duanqiang Wen
Browse files

net: libwx: fix memory leak on free page

mainline inclusion
from mainline-v6.7-rc1
commit 738b54b9b6236f573eed2453c4cbfa77326793e2
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I93QRU
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=738b54b9b6236f573eed2453c4cbfa77326793e2



---------------------------------------------------------

ifconfig ethx up, will set page->refcount larger than 1,
and then ifconfig ethx down, calling __page_frag_cache_drain()
to free pages, it is not compatible with page pool.
So deleting codes which changing page->refcount.

Fixes: 3c47e8ae ("net: libwx: Support to receive packets in NAPI")
Signed-off-by: default avatarduanqiangwen <duanqiangwen@net-swift.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9fd31de4
Loading
Loading
Loading
Loading
+6 −76
Original line number Diff line number Diff line
@@ -160,60 +160,6 @@ static __le32 wx_test_staterr(union wx_rx_desc *rx_desc,
	return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
}

static bool wx_can_reuse_rx_page(struct wx_rx_buffer *rx_buffer,
				 int rx_buffer_pgcnt)
{
	unsigned int pagecnt_bias = rx_buffer->pagecnt_bias;
	struct page *page = rx_buffer->page;

	/* avoid re-using remote and pfmemalloc pages */
	if (!dev_page_is_reusable(page))
		return false;

#if (PAGE_SIZE < 8192)
	/* if we are only owner of page we can reuse it */
	if (unlikely((rx_buffer_pgcnt - pagecnt_bias) > 1))
		return false;
#endif

	/* If we have drained the page fragment pool we need to update
	 * the pagecnt_bias and page count so that we fully restock the
	 * number of references the driver holds.
	 */
	if (unlikely(pagecnt_bias == 1)) {
		page_ref_add(page, USHRT_MAX - 1);
		rx_buffer->pagecnt_bias = USHRT_MAX;
	}

	return true;
}

/**
 * wx_reuse_rx_page - page flip buffer and store it back on the ring
 * @rx_ring: rx descriptor ring to store buffers on
 * @old_buff: donor buffer to have page reused
 *
 * Synchronizes page for reuse by the adapter
 **/
static void wx_reuse_rx_page(struct wx_ring *rx_ring,
			     struct wx_rx_buffer *old_buff)
{
	u16 nta = rx_ring->next_to_alloc;
	struct wx_rx_buffer *new_buff;

	new_buff = &rx_ring->rx_buffer_info[nta];

	/* update, and store next to alloc */
	nta++;
	rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;

	/* transfer page from old buffer to new buffer */
	new_buff->page = old_buff->page;
	new_buff->page_dma = old_buff->page_dma;
	new_buff->page_offset = old_buff->page_offset;
	new_buff->pagecnt_bias	= old_buff->pagecnt_bias;
}

static void wx_dma_sync_frag(struct wx_ring *rx_ring,
			     struct wx_rx_buffer *rx_buffer)
{
@@ -270,8 +216,6 @@ static struct wx_rx_buffer *wx_get_rx_buffer(struct wx_ring *rx_ring,
				      size,
				      DMA_FROM_DEVICE);
skip_sync:
	rx_buffer->pagecnt_bias--;

	return rx_buffer;
}

@@ -280,19 +224,9 @@ static void wx_put_rx_buffer(struct wx_ring *rx_ring,
			     struct sk_buff *skb,
			     int rx_buffer_pgcnt)
{
	if (wx_can_reuse_rx_page(rx_buffer, rx_buffer_pgcnt)) {
		/* hand second half of page back to the ring */
		wx_reuse_rx_page(rx_ring, rx_buffer);
	} else {
	if (!IS_ERR(skb) && WX_CB(skb)->dma == rx_buffer->dma)
		/* the page has been released from the ring */
		WX_CB(skb)->page_released = true;
		else
			page_pool_put_full_page(rx_ring->page_pool, rx_buffer->page, false);

		__page_frag_cache_drain(rx_buffer->page,
					rx_buffer->pagecnt_bias);
	}

	/* clear contents of rx_buffer */
	rx_buffer->page = NULL;
@@ -335,11 +269,12 @@ static struct sk_buff *wx_build_skb(struct wx_ring *rx_ring,
		if (size <= WX_RXBUFFER_256) {
			memcpy(__skb_put(skb, size), page_addr,
			       ALIGN(size, sizeof(long)));
			rx_buffer->pagecnt_bias++;

			page_pool_put_full_page(rx_ring->page_pool, rx_buffer->page, true);
			return skb;
		}

		skb_mark_for_recycle(skb);

		if (!wx_test_staterr(rx_desc, WX_RXD_STAT_EOP))
			WX_CB(skb)->dma = rx_buffer->dma;

@@ -382,8 +317,6 @@ static bool wx_alloc_mapped_page(struct wx_ring *rx_ring,
	bi->page_dma = dma;
	bi->page = page;
	bi->page_offset = 0;
	page_ref_add(page, USHRT_MAX - 1);
	bi->pagecnt_bias = USHRT_MAX;

	return true;
}
@@ -723,7 +656,6 @@ static int wx_clean_rx_irq(struct wx_q_vector *q_vector,
		/* exit if we failed to retrieve a buffer */
		if (!skb) {
			rx_ring->rx_stats.alloc_rx_buff_failed++;
			rx_buffer->pagecnt_bias++;
			break;
		}

@@ -2248,8 +2180,6 @@ static void wx_clean_rx_ring(struct wx_ring *rx_ring)

		/* free resources associated with mapping */
		page_pool_put_full_page(rx_ring->page_pool, rx_buffer->page, false);
		__page_frag_cache_drain(rx_buffer->page,
					rx_buffer->pagecnt_bias);

		i++;
		rx_buffer++;
+0 −1
Original line number Diff line number Diff line
@@ -786,7 +786,6 @@ struct wx_rx_buffer {
	dma_addr_t page_dma;
	struct page *page;
	unsigned int page_offset;
	u16 pagecnt_bias;
};

struct wx_queue_stats {