Commit 254a1a2b authored by David S. Miller's avatar David S. Miller

Merge branch 'netdev-page_frag_alloc-fixes'

Alexander Duyck says:

====================
Address recent issues found in netdev page_frag_alloc usage

This patch set addresses a couple of issues that I had pointed out to Jann
Horn in response to a recent patch submission.

The first issue is that I wanted to avoid the need to read/modify/write the
size value in order to generate the value for pagecnt_bias. Instead we can
just use a fixed constant which reduces the need for memory read operations
and the overall number of instructions to update the pagecnt bias values.

The other, and more important issue is, that apparently we were letting tun
access the napi_alloc_cache indirectly through netdev_alloc_frag and as a
result letting it create unaligned accesses via unaligned allocations. In
order to prevent this I have added a call to SKB_DATA_ALIGN for the fragsz
field so that we will keep the offset in the napi_alloc_cache
SMP_CACHE_BYTES aligned.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e09c6a4e 3bed3cc4
...@@ -4675,11 +4675,11 @@ void *page_frag_alloc(struct page_frag_cache *nc, ...@@ -4675,11 +4675,11 @@ void *page_frag_alloc(struct page_frag_cache *nc,
/* Even if we own the page, we do not use atomic_set(). /* Even if we own the page, we do not use atomic_set().
* This would break get_page_unless_zero() users. * This would break get_page_unless_zero() users.
*/ */
page_ref_add(page, size); page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE);
/* reset page count bias and offset to start of new frag */ /* reset page count bias and offset to start of new frag */
nc->pfmemalloc = page_is_pfmemalloc(page); nc->pfmemalloc = page_is_pfmemalloc(page);
nc->pagecnt_bias = size + 1; nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
nc->offset = size; nc->offset = size;
} }
...@@ -4695,10 +4695,10 @@ void *page_frag_alloc(struct page_frag_cache *nc, ...@@ -4695,10 +4695,10 @@ void *page_frag_alloc(struct page_frag_cache *nc,
size = nc->size; size = nc->size;
#endif #endif
/* OK, page count is 0, we can safely set it */ /* OK, page count is 0, we can safely set it */
set_page_count(page, size + 1); set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
/* reset page count bias and offset to start of new frag */ /* reset page count bias and offset to start of new frag */
nc->pagecnt_bias = size + 1; nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
offset = size - fragsz; offset = size - fragsz;
} }
......
...@@ -356,6 +356,8 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) ...@@ -356,6 +356,8 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
*/ */
void *netdev_alloc_frag(unsigned int fragsz) void *netdev_alloc_frag(unsigned int fragsz)
{ {
fragsz = SKB_DATA_ALIGN(fragsz);
return __netdev_alloc_frag(fragsz, GFP_ATOMIC); return __netdev_alloc_frag(fragsz, GFP_ATOMIC);
} }
EXPORT_SYMBOL(netdev_alloc_frag); EXPORT_SYMBOL(netdev_alloc_frag);
...@@ -369,6 +371,8 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) ...@@ -369,6 +371,8 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
void *napi_alloc_frag(unsigned int fragsz) void *napi_alloc_frag(unsigned int fragsz)
{ {
fragsz = SKB_DATA_ALIGN(fragsz);
return __napi_alloc_frag(fragsz, GFP_ATOMIC); return __napi_alloc_frag(fragsz, GFP_ATOMIC);
} }
EXPORT_SYMBOL(napi_alloc_frag); EXPORT_SYMBOL(napi_alloc_frag);
......
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