Commit 3a7ad063 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

Revert "packet: switch kvzalloc to allocate memory"

This reverts commit 71e41286.

mmap()/munmap() can not be backed by kmalloced pages :

We fault in :

    VM_BUG_ON_PAGE(PageSlab(page), page);

    unmap_single_vma+0x8a/0x110
    unmap_vmas+0x4b/0x90
    unmap_region+0xc9/0x140
    do_munmap+0x274/0x360
    vm_munmap+0x81/0xc0
    SyS_munmap+0x2b/0x40
    do_syscall_64+0x13e/0x1c0
    entry_SYSCALL_64_after_hwframe+0x42/0xb7

Fixes: 71e41286 ("packet: switch kvzalloc to allocate memory")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarJohn Sperbeck <jsperbeck@google.com>
Bisected-by: default avatarJohn Sperbeck <jsperbeck@google.com>
Cc: Zhang Yu <zhangyu31@baidu.com>
Cc: Li RongQing <lirongqing@baidu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dc641794
...@@ -4137,36 +4137,52 @@ static const struct vm_operations_struct packet_mmap_ops = { ...@@ -4137,36 +4137,52 @@ static const struct vm_operations_struct packet_mmap_ops = {
.close = packet_mm_close, .close = packet_mm_close,
}; };
static void free_pg_vec(struct pgv *pg_vec, unsigned int len) static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
unsigned int len)
{ {
int i; int i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (likely(pg_vec[i].buffer)) { if (likely(pg_vec[i].buffer)) {
kvfree(pg_vec[i].buffer); if (is_vmalloc_addr(pg_vec[i].buffer))
vfree(pg_vec[i].buffer);
else
free_pages((unsigned long)pg_vec[i].buffer,
order);
pg_vec[i].buffer = NULL; pg_vec[i].buffer = NULL;
} }
} }
kfree(pg_vec); kfree(pg_vec);
} }
static char *alloc_one_pg_vec_page(unsigned long size) static char *alloc_one_pg_vec_page(unsigned long order)
{ {
char *buffer; char *buffer;
gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
__GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY;
buffer = kvzalloc(size, GFP_KERNEL); buffer = (char *) __get_free_pages(gfp_flags, order);
if (buffer) if (buffer)
return buffer; return buffer;
buffer = kvzalloc(size, GFP_KERNEL | __GFP_RETRY_MAYFAIL); /* __get_free_pages failed, fall back to vmalloc */
buffer = vzalloc(array_size((1 << order), PAGE_SIZE));
if (buffer)
return buffer;
/* vmalloc failed, lets dig into swap here */
gfp_flags &= ~__GFP_NORETRY;
buffer = (char *) __get_free_pages(gfp_flags, order);
if (buffer)
return buffer; return buffer;
/* complete and utter failure */
return NULL;
} }
static struct pgv *alloc_pg_vec(struct tpacket_req *req) static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order)
{ {
unsigned int block_nr = req->tp_block_nr; unsigned int block_nr = req->tp_block_nr;
unsigned long size = req->tp_block_size;
struct pgv *pg_vec; struct pgv *pg_vec;
int i; int i;
...@@ -4175,7 +4191,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req) ...@@ -4175,7 +4191,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
goto out; goto out;
for (i = 0; i < block_nr; i++) { for (i = 0; i < block_nr; i++) {
pg_vec[i].buffer = alloc_one_pg_vec_page(size); pg_vec[i].buffer = alloc_one_pg_vec_page(order);
if (unlikely(!pg_vec[i].buffer)) if (unlikely(!pg_vec[i].buffer))
goto out_free_pgvec; goto out_free_pgvec;
} }
...@@ -4184,7 +4200,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req) ...@@ -4184,7 +4200,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
return pg_vec; return pg_vec;
out_free_pgvec: out_free_pgvec:
free_pg_vec(pg_vec, block_nr); free_pg_vec(pg_vec, order, block_nr);
pg_vec = NULL; pg_vec = NULL;
goto out; goto out;
} }
...@@ -4194,9 +4210,9 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, ...@@ -4194,9 +4210,9 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
{ {
struct pgv *pg_vec = NULL; struct pgv *pg_vec = NULL;
struct packet_sock *po = pkt_sk(sk); struct packet_sock *po = pkt_sk(sk);
int was_running, order = 0;
struct packet_ring_buffer *rb; struct packet_ring_buffer *rb;
struct sk_buff_head *rb_queue; struct sk_buff_head *rb_queue;
int was_running;
__be16 num; __be16 num;
int err = -EINVAL; int err = -EINVAL;
/* Added to avoid minimal code churn */ /* Added to avoid minimal code churn */
...@@ -4258,7 +4274,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, ...@@ -4258,7 +4274,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
goto out; goto out;
err = -ENOMEM; err = -ENOMEM;
pg_vec = alloc_pg_vec(req); order = get_order(req->tp_block_size);
pg_vec = alloc_pg_vec(req, order);
if (unlikely(!pg_vec)) if (unlikely(!pg_vec))
goto out; goto out;
switch (po->tp_version) { switch (po->tp_version) {
...@@ -4312,6 +4329,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, ...@@ -4312,6 +4329,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
rb->frame_size = req->tp_frame_size; rb->frame_size = req->tp_frame_size;
spin_unlock_bh(&rb_queue->lock); spin_unlock_bh(&rb_queue->lock);
swap(rb->pg_vec_order, order);
swap(rb->pg_vec_len, req->tp_block_nr); swap(rb->pg_vec_len, req->tp_block_nr);
rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE; rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE;
...@@ -4337,7 +4355,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, ...@@ -4337,7 +4355,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
} }
if (pg_vec) if (pg_vec)
free_pg_vec(pg_vec, req->tp_block_nr); free_pg_vec(pg_vec, order, req->tp_block_nr);
out: out:
return err; return err;
} }
......
...@@ -64,6 +64,7 @@ struct packet_ring_buffer { ...@@ -64,6 +64,7 @@ struct packet_ring_buffer {
unsigned int frame_size; unsigned int frame_size;
unsigned int frame_max; unsigned int frame_max;
unsigned int pg_vec_order;
unsigned int pg_vec_pages; unsigned int pg_vec_pages;
unsigned int pg_vec_len; unsigned int pg_vec_len;
......
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