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) | |||
| 273 | * Check if we need to grow the arrays holding pages and partial page | 273 | * Check if we need to grow the arrays holding pages and partial page |
| 274 | * descriptions. | 274 | * descriptions. |
| 275 | */ | 275 | */ |
| 276 | int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) | 276 | int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) |
| 277 | { | 277 | { |
| 278 | if (pipe->buffers <= PIPE_DEF_BUFFERS) | 278 | unsigned int buffers = ACCESS_ONCE(pipe->buffers); |
| 279 | |||
| 280 | spd->nr_pages_max = buffers; | ||
| 281 | if (buffers <= PIPE_DEF_BUFFERS) | ||
| 279 | return 0; | 282 | return 0; |
| 280 | 283 | ||
| 281 | spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL); | 284 | spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL); |
| 282 | spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL); | 285 | spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL); |
| 283 | 286 | ||
| 284 | if (spd->pages && spd->partial) | 287 | if (spd->pages && spd->partial) |
| 285 | return 0; | 288 | return 0; |
| @@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) | |||
| 289 | return -ENOMEM; | 292 | return -ENOMEM; |
| 290 | } | 293 | } |
| 291 | 294 | ||
| 292 | void splice_shrink_spd(struct pipe_inode_info *pipe, | 295 | void splice_shrink_spd(struct splice_pipe_desc *spd) |
| 293 | struct splice_pipe_desc *spd) | ||
| 294 | { | 296 | { |
| 295 | if (pipe->buffers <= PIPE_DEF_BUFFERS) | 297 | if (spd->nr_pages_max <= PIPE_DEF_BUFFERS) |
| 296 | return; | 298 | return; |
| 297 | 299 | ||
| 298 | kfree(spd->pages); | 300 | kfree(spd->pages); |
| @@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 315 | struct splice_pipe_desc spd = { | 317 | struct splice_pipe_desc spd = { |
| 316 | .pages = pages, | 318 | .pages = pages, |
| 317 | .partial = partial, | 319 | .partial = partial, |
| 320 | .nr_pages_max = PIPE_DEF_BUFFERS, | ||
| 318 | .flags = flags, | 321 | .flags = flags, |
| 319 | .ops = &page_cache_pipe_buf_ops, | 322 | .ops = &page_cache_pipe_buf_ops, |
| 320 | .spd_release = spd_release_page, | 323 | .spd_release = spd_release_page, |
| @@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 326 | index = *ppos >> PAGE_CACHE_SHIFT; | 329 | index = *ppos >> PAGE_CACHE_SHIFT; |
| 327 | loff = *ppos & ~PAGE_CACHE_MASK; | 330 | loff = *ppos & ~PAGE_CACHE_MASK; |
| 328 | req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 331 | req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 329 | nr_pages = min(req_pages, pipe->buffers); | 332 | nr_pages = min(req_pages, spd.nr_pages_max); |
| 330 | 333 | ||
| 331 | /* | 334 | /* |
| 332 | * Lookup the (hopefully) full range of pages we need. | 335 | * Lookup the (hopefully) full range of pages we need. |
| @@ -497,7 +500,7 @@ fill_it: | |||
| 497 | if (spd.nr_pages) | 500 | if (spd.nr_pages) |
| 498 | error = splice_to_pipe(pipe, &spd); | 501 | error = splice_to_pipe(pipe, &spd); |
| 499 | 502 | ||
| 500 | splice_shrink_spd(pipe, &spd); | 503 | splice_shrink_spd(&spd); |
| 501 | return error; | 504 | return error; |
| 502 | } | 505 | } |
| 503 | 506 | ||
| @@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 598 | struct splice_pipe_desc spd = { | 601 | struct splice_pipe_desc spd = { |
| 599 | .pages = pages, | 602 | .pages = pages, |
| 600 | .partial = partial, | 603 | .partial = partial, |
| 604 | .nr_pages_max = PIPE_DEF_BUFFERS, | ||
| 601 | .flags = flags, | 605 | .flags = flags, |
| 602 | .ops = &default_pipe_buf_ops, | 606 | .ops = &default_pipe_buf_ops, |
| 603 | .spd_release = spd_release_page, | 607 | .spd_release = spd_release_page, |
| @@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 608 | 612 | ||
| 609 | res = -ENOMEM; | 613 | res = -ENOMEM; |
| 610 | vec = __vec; | 614 | vec = __vec; |
| 611 | if (pipe->buffers > PIPE_DEF_BUFFERS) { | 615 | if (spd.nr_pages_max > PIPE_DEF_BUFFERS) { |
| 612 | vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL); | 616 | vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL); |
| 613 | if (!vec) | 617 | if (!vec) |
| 614 | goto shrink_ret; | 618 | goto shrink_ret; |
| 615 | } | 619 | } |
| @@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 617 | offset = *ppos & ~PAGE_CACHE_MASK; | 621 | offset = *ppos & ~PAGE_CACHE_MASK; |
| 618 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 622 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 619 | 623 | ||
| 620 | for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) { | 624 | for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) { |
| 621 | struct page *page; | 625 | struct page *page; |
| 622 | 626 | ||
| 623 | page = alloc_page(GFP_USER); | 627 | page = alloc_page(GFP_USER); |
| @@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 665 | shrink_ret: | 669 | shrink_ret: |
| 666 | if (vec != __vec) | 670 | if (vec != __vec) |
| 667 | kfree(vec); | 671 | kfree(vec); |
| 668 | splice_shrink_spd(pipe, &spd); | 672 | splice_shrink_spd(&spd); |
| 669 | return res; | 673 | return res; |
| 670 | 674 | ||
| 671 | err: | 675 | err: |
| @@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, | |||
| 1614 | struct splice_pipe_desc spd = { | 1618 | struct splice_pipe_desc spd = { |
| 1615 | .pages = pages, | 1619 | .pages = pages, |
| 1616 | .partial = partial, | 1620 | .partial = partial, |
| 1621 | .nr_pages_max = PIPE_DEF_BUFFERS, | ||
| 1617 | .flags = flags, | 1622 | .flags = flags, |
| 1618 | .ops = &user_page_pipe_buf_ops, | 1623 | .ops = &user_page_pipe_buf_ops, |
| 1619 | .spd_release = spd_release_page, | 1624 | .spd_release = spd_release_page, |
| @@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, | |||
| 1629 | 1634 | ||
| 1630 | spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, | 1635 | spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, |
| 1631 | spd.partial, false, | 1636 | spd.partial, false, |
| 1632 | pipe->buffers); | 1637 | spd.nr_pages_max); |
| 1633 | if (spd.nr_pages <= 0) | 1638 | if (spd.nr_pages <= 0) |
| 1634 | ret = spd.nr_pages; | 1639 | ret = spd.nr_pages; |
| 1635 | else | 1640 | else |
| 1636 | ret = splice_to_pipe(pipe, &spd); | 1641 | ret = splice_to_pipe(pipe, &spd); |
| 1637 | 1642 | ||
| 1638 | splice_shrink_spd(pipe, &spd); | 1643 | splice_shrink_spd(&spd); |
| 1639 | return ret; | 1644 | return ret; |
| 1640 | } | 1645 | } |
| 1641 | 1646 | ||
