Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 130139
b: refs/heads/master
c: 8b9d372
h: refs/heads/master
i:
  130137: 0ca3db8
  130135: 7bac799
v: v3
  • Loading branch information
Jarek Poplawski authored and David S. Miller committed Jan 20, 2009
1 parent a8ab9ab commit 3f587ce
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 33 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: 9e9fd12dc0679643c191fc9795a3021807e77de4
refs/heads/master: 8b9d3728977760f6bd1317c4420890f73695354e
61 changes: 29 additions & 32 deletions trunk/net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,13 @@ static struct kmem_cache *skbuff_fclone_cache __read_mostly;
static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct sk_buff *skb = (struct sk_buff *) buf->private;

kfree_skb(skb);
put_page(buf->page);
}

static void sock_pipe_buf_get(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct sk_buff *skb = (struct sk_buff *) buf->private;

skb_get(skb);
get_page(buf->page);
}

static int sock_pipe_buf_steal(struct pipe_inode_info *pipe,
Expand Down Expand Up @@ -1334,26 +1330,43 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
*/
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
{
struct sk_buff *skb = (struct sk_buff *) spd->partial[i].private;
put_page(spd->pages[i]);
}

kfree_skb(skb);
static inline struct page *linear_to_page(struct page *page, unsigned int len,
unsigned int offset)
{
struct page *p = alloc_pages(GFP_KERNEL, 0);

if (!p)
return NULL;
memcpy(page_address(p) + offset, page_address(page) + offset, len);

return p;
}

/*
* Fill page/offset/length into spd, if it can hold more pages.
*/
static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,
unsigned int len, unsigned int offset,
struct sk_buff *skb)
struct sk_buff *skb, int linear)
{
if (unlikely(spd->nr_pages == PIPE_BUFFERS))
return 1;

if (linear) {
page = linear_to_page(page, len, offset);
if (!page)
return 1;
} else
get_page(page);

spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = len;
spd->partial[spd->nr_pages].offset = offset;
spd->partial[spd->nr_pages].private = (unsigned long) skb_get(skb);
spd->nr_pages++;

return 0;
}

Expand All @@ -1369,7 +1382,7 @@ static inline void __segment_seek(struct page **page, unsigned int *poff,
static inline int __splice_segment(struct page *page, unsigned int poff,
unsigned int plen, unsigned int *off,
unsigned int *len, struct sk_buff *skb,
struct splice_pipe_desc *spd)
struct splice_pipe_desc *spd, int linear)
{
if (!*len)
return 1;
Expand All @@ -1392,7 +1405,7 @@ static inline int __splice_segment(struct page *page, unsigned int poff,
/* the linear region may spread across several pages */
flen = min_t(unsigned int, flen, PAGE_SIZE - poff);

if (spd_fill_page(spd, page, flen, poff, skb))
if (spd_fill_page(spd, page, flen, poff, skb, linear))
return 1;

__segment_seek(&page, &poff, &plen, flen);
Expand All @@ -1419,7 +1432,7 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
if (__splice_segment(virt_to_page(skb->data),
(unsigned long) skb->data & (PAGE_SIZE - 1),
skb_headlen(skb),
offset, len, skb, spd))
offset, len, skb, spd, 1))
return 1;

/*
Expand All @@ -1429,7 +1442,7 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];

if (__splice_segment(f->page, f->page_offset, f->size,
offset, len, skb, spd))
offset, len, skb, spd, 0))
return 1;
}

Expand All @@ -1442,7 +1455,7 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
* the frag list, if such a thing exists. We'd probably need to recurse to
* handle that cleanly.
*/
int skb_splice_bits(struct sk_buff *__skb, unsigned int offset,
int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int tlen,
unsigned int flags)
{
Expand All @@ -1455,16 +1468,6 @@ int skb_splice_bits(struct sk_buff *__skb, unsigned int offset,
.ops = &sock_pipe_buf_ops,
.spd_release = sock_spd_release,
};
struct sk_buff *skb;

/*
* I'd love to avoid the clone here, but tcp_read_sock()
* ignores reference counts and unconditonally kills the sk_buff
* on return from the actor.
*/
skb = skb_clone(__skb, GFP_KERNEL);
if (unlikely(!skb))
return -ENOMEM;

/*
* __skb_splice_bits() only fails if the output has no room left,
Expand All @@ -1488,15 +1491,9 @@ int skb_splice_bits(struct sk_buff *__skb, unsigned int offset,
}

done:
/*
* drop our reference to the clone, the pipe consumption will
* drop the rest.
*/
kfree_skb(skb);

if (spd.nr_pages) {
struct sock *sk = skb->sk;
int ret;
struct sock *sk = __skb->sk;

/*
* Drop the socket lock, otherwise we have reverse
Expand Down

0 comments on commit 3f587ce

Please sign in to comment.