thunderx: eliminate extra calls to put_page() for pages held for recycling
For the non-XDP case, commit773225388d
("net: thunderx: Optimize page recycling for XDP") added code to nicvf_free_rbdr() that, when releasing the additional receive buffer page reference held for recycling, repeatedly calls put_page() until the page's _refcount goes to zero. Which results in the page being freed. This is not okay if the page's _refcount was greater than 1 (in the non-XDP case), because nicvf_free_rbdr() should not be subtracting more than what nicvf_alloc_page() had previously added to the page's _refcount, which was only 1 (in the non-XDP case). This can arise if a received packet is still being processed and the receive buffer (i.e., skb->head) has not yet been freed via skb_free_head() when nicvf_free_rbdr() is spinning through the aforementioned put_page() loop. If this should occur, when the received packet finishes processing and skb_free_head() is called, various problems can ensue. Exactly what, depends on whether the page has already been reallocated or not, anything from "BUG: Bad page state ... ", to "Unable to handle kernel NULL pointer dereference ..." or "Unable to handle kernel paging request...". So this patch changes nicvf_free_rbdr() to only call put_page() once for pages held for recycling (in the non-XDP case). Fixes:773225388d
("net: thunderx: Optimize page recycling for XDP") Signed-off-by: Dean Nelson <dnelson@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
b3e2080694
Коммит
cd35ef9149
|
@ -364,11 +364,10 @@ static void nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr)
|
|||
while (head < rbdr->pgcnt) {
|
||||
pgcache = &rbdr->pgcache[head];
|
||||
if (pgcache->page && page_ref_count(pgcache->page) != 0) {
|
||||
if (!rbdr->is_xdp) {
|
||||
put_page(pgcache->page);
|
||||
continue;
|
||||
if (rbdr->is_xdp) {
|
||||
page_ref_sub(pgcache->page,
|
||||
pgcache->ref_count - 1);
|
||||
}
|
||||
page_ref_sub(pgcache->page, pgcache->ref_count - 1);
|
||||
put_page(pgcache->page);
|
||||
}
|
||||
head++;
|
||||
|
|
Загрузка…
Ссылка в новой задаче