|
@@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
|
|
|
* Check if we need to grow the arrays holding pages and partial page
|
|
|
* descriptions.
|
|
|
*/
|
|
|
-int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
|
|
|
+int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
|
|
|
{
|
|
|
- if (pipe->buffers <= PIPE_DEF_BUFFERS)
|
|
|
+ unsigned int buffers = ACCESS_ONCE(pipe->buffers);
|
|
|
+
|
|
|
+ spd->nr_pages_max = buffers;
|
|
|
+ if (buffers <= PIPE_DEF_BUFFERS)
|
|
|
return 0;
|
|
|
|
|
|
- spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);
|
|
|
- spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL);
|
|
|
+ spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL);
|
|
|
+ spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL);
|
|
|
|
|
|
if (spd->pages && spd->partial)
|
|
|
return 0;
|
|
@@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
-void splice_shrink_spd(struct pipe_inode_info *pipe,
|
|
|
- struct splice_pipe_desc *spd)
|
|
|
+void splice_shrink_spd(struct splice_pipe_desc *spd)
|
|
|
{
|
|
|
- if (pipe->buffers <= PIPE_DEF_BUFFERS)
|
|
|
+ if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
|
|
|
return;
|
|
|
|
|
|
kfree(spd->pages);
|
|
@@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
struct splice_pipe_desc spd = {
|
|
|
.pages = pages,
|
|
|
.partial = partial,
|
|
|
+ .nr_pages_max = PIPE_DEF_BUFFERS,
|
|
|
.flags = flags,
|
|
|
.ops = &page_cache_pipe_buf_ops,
|
|
|
.spd_release = spd_release_page,
|
|
@@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
index = *ppos >> PAGE_CACHE_SHIFT;
|
|
|
loff = *ppos & ~PAGE_CACHE_MASK;
|
|
|
req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
|
- nr_pages = min(req_pages, pipe->buffers);
|
|
|
+ nr_pages = min(req_pages, spd.nr_pages_max);
|
|
|
|
|
|
/*
|
|
|
* Lookup the (hopefully) full range of pages we need.
|
|
@@ -497,7 +500,7 @@ fill_it:
|
|
|
if (spd.nr_pages)
|
|
|
error = splice_to_pipe(pipe, &spd);
|
|
|
|
|
|
- splice_shrink_spd(pipe, &spd);
|
|
|
+ splice_shrink_spd(&spd);
|
|
|
return error;
|
|
|
}
|
|
|
|
|
@@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
struct splice_pipe_desc spd = {
|
|
|
.pages = pages,
|
|
|
.partial = partial,
|
|
|
+ .nr_pages_max = PIPE_DEF_BUFFERS,
|
|
|
.flags = flags,
|
|
|
.ops = &default_pipe_buf_ops,
|
|
|
.spd_release = spd_release_page,
|
|
@@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
|
|
|
res = -ENOMEM;
|
|
|
vec = __vec;
|
|
|
- if (pipe->buffers > PIPE_DEF_BUFFERS) {
|
|
|
- vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL);
|
|
|
+ if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
|
|
|
+ vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
|
|
|
if (!vec)
|
|
|
goto shrink_ret;
|
|
|
}
|
|
@@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
offset = *ppos & ~PAGE_CACHE_MASK;
|
|
|
nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
|
|
- for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) {
|
|
|
+ for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
|
|
|
struct page *page;
|
|
|
|
|
|
page = alloc_page(GFP_USER);
|
|
@@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
shrink_ret:
|
|
|
if (vec != __vec)
|
|
|
kfree(vec);
|
|
|
- splice_shrink_spd(pipe, &spd);
|
|
|
+ splice_shrink_spd(&spd);
|
|
|
return res;
|
|
|
|
|
|
err:
|
|
@@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
|
|
|
struct splice_pipe_desc spd = {
|
|
|
.pages = pages,
|
|
|
.partial = partial,
|
|
|
+ .nr_pages_max = PIPE_DEF_BUFFERS,
|
|
|
.flags = flags,
|
|
|
.ops = &user_page_pipe_buf_ops,
|
|
|
.spd_release = spd_release_page,
|
|
@@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
|
|
|
|
|
|
spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
|
|
|
spd.partial, false,
|
|
|
- pipe->buffers);
|
|
|
+ spd.nr_pages_max);
|
|
|
if (spd.nr_pages <= 0)
|
|
|
ret = spd.nr_pages;
|
|
|
else
|
|
|
ret = splice_to_pipe(pipe, &spd);
|
|
|
|
|
|
- splice_shrink_spd(pipe, &spd);
|
|
|
+ splice_shrink_spd(&spd);
|
|
|
return ret;
|
|
|
}
|
|
|
|