Skip to content

Commit 3a7ad06

Browse files
Eric Dumazetdavem330
authored andcommitted
Revert "packet: switch kvzalloc to allocate memory"
This reverts commit 71e4128. 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: 71e4128 ("packet: switch kvzalloc to allocate memory") Signed-off-by: Eric Dumazet <[email protected]> Reported-by: John Sperbeck <[email protected]> Bisected-by: John Sperbeck <[email protected]> Cc: Zhang Yu <[email protected]> Cc: Li RongQing <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dc64179 commit 3a7ad06

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

net/packet/af_packet.c

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,36 +4137,52 @@ static const struct vm_operations_struct packet_mmap_ops = {
41374137
.close = packet_mm_close,
41384138
};
41394139

4140-
static void free_pg_vec(struct pgv *pg_vec, unsigned int len)
4140+
static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
4141+
unsigned int len)
41414142
{
41424143
int i;
41434144

41444145
for (i = 0; i < len; i++) {
41454146
if (likely(pg_vec[i].buffer)) {
4146-
kvfree(pg_vec[i].buffer);
4147+
if (is_vmalloc_addr(pg_vec[i].buffer))
4148+
vfree(pg_vec[i].buffer);
4149+
else
4150+
free_pages((unsigned long)pg_vec[i].buffer,
4151+
order);
41474152
pg_vec[i].buffer = NULL;
41484153
}
41494154
}
41504155
kfree(pg_vec);
41514156
}
41524157

4153-
static char *alloc_one_pg_vec_page(unsigned long size)
4158+
static char *alloc_one_pg_vec_page(unsigned long order)
41544159
{
41554160
char *buffer;
4161+
gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
4162+
__GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY;
41564163

4157-
buffer = kvzalloc(size, GFP_KERNEL);
4164+
buffer = (char *) __get_free_pages(gfp_flags, order);
41584165
if (buffer)
41594166
return buffer;
41604167

4161-
buffer = kvzalloc(size, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
4168+
/* __get_free_pages failed, fall back to vmalloc */
4169+
buffer = vzalloc(array_size((1 << order), PAGE_SIZE));
4170+
if (buffer)
4171+
return buffer;
41624172

4163-
return buffer;
4173+
/* vmalloc failed, lets dig into swap here */
4174+
gfp_flags &= ~__GFP_NORETRY;
4175+
buffer = (char *) __get_free_pages(gfp_flags, order);
4176+
if (buffer)
4177+
return buffer;
4178+
4179+
/* complete and utter failure */
4180+
return NULL;
41644181
}
41654182

4166-
static struct pgv *alloc_pg_vec(struct tpacket_req *req)
4183+
static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order)
41674184
{
41684185
unsigned int block_nr = req->tp_block_nr;
4169-
unsigned long size = req->tp_block_size;
41704186
struct pgv *pg_vec;
41714187
int i;
41724188

@@ -4175,7 +4191,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
41754191
goto out;
41764192

41774193
for (i = 0; i < block_nr; i++) {
4178-
pg_vec[i].buffer = alloc_one_pg_vec_page(size);
4194+
pg_vec[i].buffer = alloc_one_pg_vec_page(order);
41794195
if (unlikely(!pg_vec[i].buffer))
41804196
goto out_free_pgvec;
41814197
}
@@ -4184,7 +4200,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
41844200
return pg_vec;
41854201

41864202
out_free_pgvec:
4187-
free_pg_vec(pg_vec, block_nr);
4203+
free_pg_vec(pg_vec, order, block_nr);
41884204
pg_vec = NULL;
41894205
goto out;
41904206
}
@@ -4194,9 +4210,9 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
41944210
{
41954211
struct pgv *pg_vec = NULL;
41964212
struct packet_sock *po = pkt_sk(sk);
4213+
int was_running, order = 0;
41974214
struct packet_ring_buffer *rb;
41984215
struct sk_buff_head *rb_queue;
4199-
int was_running;
42004216
__be16 num;
42014217
int err = -EINVAL;
42024218
/* Added to avoid minimal code churn */
@@ -4258,7 +4274,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
42584274
goto out;
42594275

42604276
err = -ENOMEM;
4261-
pg_vec = alloc_pg_vec(req);
4277+
order = get_order(req->tp_block_size);
4278+
pg_vec = alloc_pg_vec(req, order);
42624279
if (unlikely(!pg_vec))
42634280
goto out;
42644281
switch (po->tp_version) {
@@ -4312,6 +4329,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
43124329
rb->frame_size = req->tp_frame_size;
43134330
spin_unlock_bh(&rb_queue->lock);
43144331

4332+
swap(rb->pg_vec_order, order);
43154333
swap(rb->pg_vec_len, req->tp_block_nr);
43164334

43174335
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,
43374355
}
43384356

43394357
if (pg_vec)
4340-
free_pg_vec(pg_vec, req->tp_block_nr);
4358+
free_pg_vec(pg_vec, order, req->tp_block_nr);
43414359
out:
43424360
return err;
43434361
}

net/packet/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct packet_ring_buffer {
6464
unsigned int frame_size;
6565
unsigned int frame_max;
6666

67+
unsigned int pg_vec_order;
6768
unsigned int pg_vec_pages;
6869
unsigned int pg_vec_len;
6970

0 commit comments

Comments
 (0)