pipe: add support for shrinking and growing pipes
This patch adds F_GETPIPE_SZ and F_SETPIPE_SZ fcntl() actions for growing and shrinking the size of a pipe and adjusts pipe.c and splice.c (and relay and network splice) usage to work with these larger (or smaller) pipes. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
@@ -1417,12 +1417,13 @@ new_page:
|
||||
/*
|
||||
* 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,
|
||||
static inline int spd_fill_page(struct splice_pipe_desc *spd,
|
||||
struct pipe_inode_info *pipe, struct page *page,
|
||||
unsigned int *len, unsigned int offset,
|
||||
struct sk_buff *skb, int linear,
|
||||
struct sock *sk)
|
||||
{
|
||||
if (unlikely(spd->nr_pages == PIPE_BUFFERS))
|
||||
if (unlikely(spd->nr_pages == pipe->buffers))
|
||||
return 1;
|
||||
|
||||
if (linear) {
|
||||
@@ -1458,7 +1459,8 @@ 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, int linear,
|
||||
struct sock *sk)
|
||||
struct sock *sk,
|
||||
struct pipe_inode_info *pipe)
|
||||
{
|
||||
if (!*len)
|
||||
return 1;
|
||||
@@ -1481,7 +1483,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, linear, sk))
|
||||
if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk))
|
||||
return 1;
|
||||
|
||||
__segment_seek(&page, &poff, &plen, flen);
|
||||
@@ -1496,9 +1498,9 @@ static inline int __splice_segment(struct page *page, unsigned int poff,
|
||||
* Map linear and fragment data from the skb to spd. It reports failure if the
|
||||
* pipe is full or if we already spliced the requested length.
|
||||
*/
|
||||
static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
|
||||
unsigned int *len, struct splice_pipe_desc *spd,
|
||||
struct sock *sk)
|
||||
static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
|
||||
unsigned int *offset, unsigned int *len,
|
||||
struct splice_pipe_desc *spd, struct sock *sk)
|
||||
{
|
||||
int seg;
|
||||
|
||||
@@ -1508,7 +1510,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, 1, sk))
|
||||
offset, len, skb, spd, 1, sk, pipe))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
@@ -1518,7 +1520,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, 0, sk))
|
||||
offset, len, skb, spd, 0, sk, pipe))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1535,8 +1537,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
|
||||
struct pipe_inode_info *pipe, unsigned int tlen,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct partial_page partial[PIPE_BUFFERS];
|
||||
struct page *pages[PIPE_BUFFERS];
|
||||
struct partial_page partial[PIPE_DEF_BUFFERS];
|
||||
struct page *pages[PIPE_DEF_BUFFERS];
|
||||
struct splice_pipe_desc spd = {
|
||||
.pages = pages,
|
||||
.partial = partial,
|
||||
@@ -1546,12 +1548,16 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
|
||||
};
|
||||
struct sk_buff *frag_iter;
|
||||
struct sock *sk = skb->sk;
|
||||
int ret = 0;
|
||||
|
||||
if (splice_grow_spd(pipe, &spd))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* __skb_splice_bits() only fails if the output has no room left,
|
||||
* so no point in going over the frag_list for the error case.
|
||||
*/
|
||||
if (__skb_splice_bits(skb, &offset, &tlen, &spd, sk))
|
||||
if (__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk))
|
||||
goto done;
|
||||
else if (!tlen)
|
||||
goto done;
|
||||
@@ -1562,14 +1568,12 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
|
||||
skb_walk_frags(skb, frag_iter) {
|
||||
if (!tlen)
|
||||
break;
|
||||
if (__skb_splice_bits(frag_iter, &offset, &tlen, &spd, sk))
|
||||
if (__skb_splice_bits(frag_iter, pipe, &offset, &tlen, &spd, sk))
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (spd.nr_pages) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Drop the socket lock, otherwise we have reverse
|
||||
* locking dependencies between sk_lock and i_mutex
|
||||
@@ -1582,10 +1586,10 @@ done:
|
||||
release_sock(sk);
|
||||
ret = splice_to_pipe(pipe, &spd);
|
||||
lock_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
splice_shrink_spd(pipe, &spd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user