diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2009-05-13 02:35:35 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-05-13 02:35:35 -0400 |
commit | 4f23122858a27ba97444b9b37a066d83edebd4c8 (patch) | |
tree | 7ccfea2b6d606318c9812f0dc9c3aa39411ac456 /fs | |
parent | 2b1ccc0ee918a653d0483fdad9dd6112ce8e9043 (diff) |
splice: fix repeated kmap()'s in default_file_splice_read()
We cannot reliably map more than one page at the time, or we risk
deadlocking. Just allocate the pages from low mem instead.
Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 10 |
1 files changed, 4 insertions, 6 deletions
diff --git a/fs/splice.c b/fs/splice.c index eefd96b1d7fb..c5e3c79b95a8 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -580,13 +580,13 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
580 | for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) { | 580 | for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) { |
581 | struct page *page; | 581 | struct page *page; |
582 | 582 | ||
583 | page = alloc_page(GFP_HIGHUSER); | 583 | page = alloc_page(GFP_USER); |
584 | error = -ENOMEM; | 584 | error = -ENOMEM; |
585 | if (!page) | 585 | if (!page) |
586 | goto err; | 586 | goto err; |
587 | 587 | ||
588 | this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset); | 588 | this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset); |
589 | vec[i].iov_base = (void __user *) kmap(page); | 589 | vec[i].iov_base = (void __user *) page_address(page); |
590 | vec[i].iov_len = this_len; | 590 | vec[i].iov_len = this_len; |
591 | pages[i] = page; | 591 | pages[i] = page; |
592 | spd.nr_pages++; | 592 | spd.nr_pages++; |
@@ -604,7 +604,6 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
604 | 604 | ||
605 | nr_freed = 0; | 605 | nr_freed = 0; |
606 | for (i = 0; i < spd.nr_pages; i++) { | 606 | for (i = 0; i < spd.nr_pages; i++) { |
607 | kunmap(pages[i]); | ||
608 | this_len = min_t(size_t, vec[i].iov_len, res); | 607 | this_len = min_t(size_t, vec[i].iov_len, res); |
609 | partial[i].offset = 0; | 608 | partial[i].offset = 0; |
610 | partial[i].len = this_len; | 609 | partial[i].len = this_len; |
@@ -624,10 +623,9 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
624 | return res; | 623 | return res; |
625 | 624 | ||
626 | err: | 625 | err: |
627 | for (i = 0; i < spd.nr_pages; i++) { | 626 | for (i = 0; i < spd.nr_pages; i++) |
628 | kunmap(pages[i]); | ||
629 | __free_page(pages[i]); | 627 | __free_page(pages[i]); |
630 | } | 628 | |
631 | return error; | 629 | return error; |
632 | } | 630 | } |
633 | EXPORT_SYMBOL(default_file_splice_read); | 631 | EXPORT_SYMBOL(default_file_splice_read); |