aboutsummaryrefslogtreecommitdiffstats
path: root/mm/iov_iter.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-11-27 14:14:31 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-11-27 18:44:12 -0500
commit1b17f1f2e56a091deb99a068a6f1e82b5bb76b09 (patch)
tree064b5d30603cb316e6dd2ca820ae09c33cd4a7a8 /mm/iov_iter.c
parente5393fae3b49e80179f04afdc0916fcb6846ef17 (diff)
iov_iter.c: convert iov_iter_get_pages_alloc() to iterate_all_kinds
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm/iov_iter.c')
-rw-r--r--mm/iov_iter.c107
1 files changed, 45 insertions, 62 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index 75e29ef59b0e..3214b9b493ae 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -428,43 +428,6 @@ void iov_iter_init(struct iov_iter *i, int direction,
428} 428}
429EXPORT_SYMBOL(iov_iter_init); 429EXPORT_SYMBOL(iov_iter_init);
430 430
431static ssize_t get_pages_alloc_iovec(struct iov_iter *i,
432 struct page ***pages, size_t maxsize,
433 size_t *start)
434{
435 size_t offset = i->iov_offset;
436 const struct iovec *iov = i->iov;
437 size_t len;
438 unsigned long addr;
439 void *p;
440 int n;
441 int res;
442
443 len = iov->iov_len - offset;
444 if (len > i->count)
445 len = i->count;
446 if (len > maxsize)
447 len = maxsize;
448 addr = (unsigned long)iov->iov_base + offset;
449 len += *start = addr & (PAGE_SIZE - 1);
450 addr &= ~(PAGE_SIZE - 1);
451 n = (len + PAGE_SIZE - 1) / PAGE_SIZE;
452
453 p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
454 if (!p)
455 p = vmalloc(n * sizeof(struct page *));
456 if (!p)
457 return -ENOMEM;
458
459 res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
460 if (unlikely(res < 0)) {
461 kvfree(p);
462 return res;
463 }
464 *pages = p;
465 return (res == n ? len : res * PAGE_SIZE) - *start;
466}
467
468static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len) 431static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
469{ 432{
470 char *from = kmap_atomic(page); 433 char *from = kmap_atomic(page);
@@ -622,27 +585,6 @@ static size_t zero_bvec(size_t bytes, struct iov_iter *i)
622 return wanted - bytes; 585 return wanted - bytes;
623} 586}
624 587
625static ssize_t get_pages_alloc_bvec(struct iov_iter *i,
626 struct page ***pages, size_t maxsize,
627 size_t *start)
628{
629 const struct bio_vec *bvec = i->bvec;
630 size_t len = bvec->bv_len - i->iov_offset;
631 if (len > i->count)
632 len = i->count;
633 if (len > maxsize)
634 len = maxsize;
635 *start = bvec->bv_offset + i->iov_offset;
636
637 *pages = kmalloc(sizeof(struct page *), GFP_KERNEL);
638 if (!*pages)
639 return -ENOMEM;
640
641 get_page(**pages = bvec->bv_page);
642
643 return len;
644}
645
646size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, 588size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
647 struct iov_iter *i) 589 struct iov_iter *i)
648{ 590{
@@ -777,14 +719,55 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
777} 719}
778EXPORT_SYMBOL(iov_iter_get_pages); 720EXPORT_SYMBOL(iov_iter_get_pages);
779 721
722static struct page **get_pages_array(size_t n)
723{
724 struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL);
725 if (!p)
726 p = vmalloc(n * sizeof(struct page *));
727 return p;
728}
729
780ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, 730ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
781 struct page ***pages, size_t maxsize, 731 struct page ***pages, size_t maxsize,
782 size_t *start) 732 size_t *start)
783{ 733{
784 if (i->type & ITER_BVEC) 734 struct page **p;
785 return get_pages_alloc_bvec(i, pages, maxsize, start); 735
786 else 736 if (maxsize > i->count)
787 return get_pages_alloc_iovec(i, pages, maxsize, start); 737 maxsize = i->count;
738
739 if (!maxsize)
740 return 0;
741
742 iterate_all_kinds(i, maxsize, v, ({
743 unsigned long addr = (unsigned long)v.iov_base;
744 size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
745 int n;
746 int res;
747
748 addr &= ~(PAGE_SIZE - 1);
749 n = DIV_ROUND_UP(len, PAGE_SIZE);
750 p = get_pages_array(n);
751 if (!p)
752 return -ENOMEM;
753 res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p);
754 if (unlikely(res < 0)) {
755 kvfree(p);
756 return res;
757 }
758 *pages = p;
759 return (res == n ? len : res * PAGE_SIZE) - *start;
760 0;}),({
761 /* can't be more than PAGE_SIZE */
762 *start = v.bv_offset;
763 *pages = p = get_pages_array(1);
764 if (!p)
765 return -ENOMEM;
766 get_page(*p = v.bv_page);
767 return v.bv_len;
768 })
769 )
770 return 0;
788} 771}
789EXPORT_SYMBOL(iov_iter_get_pages_alloc); 772EXPORT_SYMBOL(iov_iter_get_pages_alloc);
790 773