Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 224348
b: refs/heads/master
c: 0e3125c
h: refs/heads/master
v: v3
  • Loading branch information
Neil Horman authored and David S. Miller committed Nov 16, 2010
1 parent 3f4aea1 commit 00f1db1
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 17 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 020f01ebd04f3429c32586d90598c9f59e54ca7d
refs/heads/master: 0e3125c755445664f00ad036e4fc2cd32fd52877
85 changes: 69 additions & 16 deletions trunk/net/packet/af_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/protocol.h>
Expand Down Expand Up @@ -163,8 +164,14 @@ struct packet_mreq_max {
static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
int closing, int tx_ring);

#define PGV_FROM_VMALLOC 1
struct pgv {
char *buffer;
unsigned char flags;
};

struct packet_ring_buffer {
char **pg_vec;
struct pgv *pg_vec;
unsigned int head;
unsigned int frames_per_block;
unsigned int frame_size;
Expand Down Expand Up @@ -283,7 +290,8 @@ static void *packet_lookup_frame(struct packet_sock *po,
pg_vec_pos = position / rb->frames_per_block;
frame_offset = position % rb->frames_per_block;

h.raw = rb->pg_vec[pg_vec_pos] + (frame_offset * rb->frame_size);
h.raw = rb->pg_vec[pg_vec_pos].buffer +
(frame_offset * rb->frame_size);

if (status != __packet_get_status(po, h.raw))
return NULL;
Expand Down Expand Up @@ -2325,37 +2333,74 @@ static const struct vm_operations_struct packet_mmap_ops = {
.close = packet_mm_close,
};

static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len)
static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
unsigned int len)
{
int i;

for (i = 0; i < len; i++) {
if (likely(pg_vec[i]))
free_pages((unsigned long) pg_vec[i], order);
if (likely(pg_vec[i].buffer)) {
if (pg_vec[i].flags & PGV_FROM_VMALLOC)
vfree(pg_vec[i].buffer);
else
free_pages((unsigned long)pg_vec[i].buffer,
order);
pg_vec[i].buffer = NULL;
}
}
kfree(pg_vec);
}

static inline char *alloc_one_pg_vec_page(unsigned long order)
static inline char *alloc_one_pg_vec_page(unsigned long order,
unsigned char *flags)
{
gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN;
char *buffer = NULL;
gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
__GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY;

buffer = (char *) __get_free_pages(gfp_flags, order);

if (buffer)
return buffer;

/*
* __get_free_pages failed, fall back to vmalloc
*/
*flags |= PGV_FROM_VMALLOC;
buffer = vmalloc((1 << order) * PAGE_SIZE);

return (char *) __get_free_pages(gfp_flags, order);
if (buffer)
return buffer;

/*
* vmalloc failed, lets dig into swap here
*/
*flags = 0;
gfp_flags &= ~__GFP_NORETRY;
buffer = (char *)__get_free_pages(gfp_flags, order);
if (buffer)
return buffer;

/*
* complete and utter failure
*/
return NULL;
}

static char **alloc_pg_vec(struct tpacket_req *req, int order)
static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order)
{
unsigned int block_nr = req->tp_block_nr;
char **pg_vec;
struct pgv *pg_vec;
int i;

pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL);
pg_vec = kcalloc(block_nr, sizeof(struct pgv), GFP_KERNEL);
if (unlikely(!pg_vec))
goto out;

for (i = 0; i < block_nr; i++) {
pg_vec[i] = alloc_one_pg_vec_page(order);
if (unlikely(!pg_vec[i]))
pg_vec[i].buffer = alloc_one_pg_vec_page(order,
&pg_vec[i].flags);
if (unlikely(!pg_vec[i].buffer))
goto out_free_pgvec;
}

Expand All @@ -2364,14 +2409,15 @@ static char **alloc_pg_vec(struct tpacket_req *req, int order)

out_free_pgvec:
free_pg_vec(pg_vec, order, block_nr);
kfree(pg_vec);
pg_vec = NULL;
goto out;
}

static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
int closing, int tx_ring)
{
char **pg_vec = NULL;
struct pgv *pg_vec = NULL;
struct packet_sock *po = pkt_sk(sk);
int was_running, order = 0;
struct packet_ring_buffer *rb;
Expand Down Expand Up @@ -2533,15 +2579,22 @@ static int packet_mmap(struct file *file, struct socket *sock,
continue;

for (i = 0; i < rb->pg_vec_len; i++) {
struct page *page = virt_to_page(rb->pg_vec[i]);
struct page *page;
void *kaddr = rb->pg_vec[i].buffer;
int pg_num;

for (pg_num = 0; pg_num < rb->pg_vec_pages;
pg_num++, page++) {
pg_num++) {
if (rb->pg_vec[i].flags & PGV_FROM_VMALLOC)
page = vmalloc_to_page(kaddr);
else
page = virt_to_page(kaddr);

err = vm_insert_page(vma, start, page);
if (unlikely(err))
goto out;
start += PAGE_SIZE;
kaddr += PAGE_SIZE;
}
}
}
Expand Down

0 comments on commit 00f1db1

Please sign in to comment.