diff options
Diffstat (limited to 'fs/splice.c')
| -rw-r--r-- | fs/splice.c | 35 | 
1 files changed, 20 insertions, 15 deletions
| diff --git a/fs/splice.c b/fs/splice.c index c9f1318a3b82..7bf08fa22ec9 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -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;  } | 
