aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/iov_iter.c104
1 files changed, 28 insertions, 76 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index 798fcb4294e7..e91bf0accc47 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -70,6 +70,33 @@
70 } \ 70 } \
71} 71}
72 72
73#define iterate_and_advance(i, n, v, I, B) { \
74 size_t skip = i->iov_offset; \
75 if (unlikely(i->type & ITER_BVEC)) { \
76 const struct bio_vec *bvec; \
77 struct bio_vec v; \
78 iterate_bvec(i, n, v, bvec, skip, (B)) \
79 if (skip == bvec->bv_len) { \
80 bvec++; \
81 skip = 0; \
82 } \
83 i->nr_segs -= bvec - i->bvec; \
84 i->bvec = bvec; \
85 } else { \
86 const struct iovec *iov; \
87 struct iovec v; \
88 iterate_iovec(i, n, v, iov, skip, (I)) \
89 if (skip == iov->iov_len) { \
90 iov++; \
91 skip = 0; \
92 } \
93 i->nr_segs -= iov - i->iov; \
94 i->iov = iov; \
95 } \
96 i->count -= n; \
97 i->iov_offset = skip; \
98}
99
73static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i) 100static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i)
74{ 101{
75 size_t skip, copy, left, wanted; 102 size_t skip, copy, left, wanted;
@@ -366,42 +393,6 @@ static size_t zero_iovec(size_t bytes, struct iov_iter *i)
366 return wanted - bytes; 393 return wanted - bytes;
367} 394}
368 395
369static void advance_iovec(struct iov_iter *i, size_t bytes)
370{
371 BUG_ON(i->count < bytes);
372
373 if (likely(i->nr_segs == 1)) {
374 i->iov_offset += bytes;
375 i->count -= bytes;
376 } else {
377 const struct iovec *iov = i->iov;
378 size_t base = i->iov_offset;
379 unsigned long nr_segs = i->nr_segs;
380
381 /*
382 * The !iov->iov_len check ensures we skip over unlikely
383 * zero-length segments (without overruning the iovec).
384 */
385 while (bytes || unlikely(i->count && !iov->iov_len)) {
386 int copy;
387
388 copy = min(bytes, iov->iov_len - base);
389 BUG_ON(!i->count || i->count < copy);
390 i->count -= copy;
391 bytes -= copy;
392 base += copy;
393 if (iov->iov_len == base) {
394 iov++;
395 nr_segs--;
396 base = 0;
397 }
398 }
399 i->iov = iov;
400 i->iov_offset = base;
401 i->nr_segs = nr_segs;
402 }
403}
404
405/* 396/*
406 * Fault in the first iovec of the given iov_iter, to a maximum length 397 * Fault in the first iovec of the given iov_iter, to a maximum length
407 * of bytes. Returns 0 on success, or non-zero if the memory could not be 398 * of bytes. Returns 0 on success, or non-zero if the memory could not be
@@ -685,42 +676,6 @@ static size_t zero_bvec(size_t bytes, struct iov_iter *i)
685 return wanted - bytes; 676 return wanted - bytes;
686} 677}
687 678
688static void advance_bvec(struct iov_iter *i, size_t bytes)
689{
690 BUG_ON(i->count < bytes);
691
692 if (likely(i->nr_segs == 1)) {
693 i->iov_offset += bytes;
694 i->count -= bytes;
695 } else {
696 const struct bio_vec *bvec = i->bvec;
697 size_t base = i->iov_offset;
698 unsigned long nr_segs = i->nr_segs;
699
700 /*
701 * The !iov->iov_len check ensures we skip over unlikely
702 * zero-length segments (without overruning the iovec).
703 */
704 while (bytes || unlikely(i->count && !bvec->bv_len)) {
705 int copy;
706
707 copy = min(bytes, bvec->bv_len - base);
708 BUG_ON(!i->count || i->count < copy);
709 i->count -= copy;
710 bytes -= copy;
711 base += copy;
712 if (bvec->bv_len == base) {
713 bvec++;
714 nr_segs--;
715 base = 0;
716 }
717 }
718 i->bvec = bvec;
719 i->iov_offset = base;
720 i->nr_segs = nr_segs;
721 }
722}
723
724static ssize_t get_pages_bvec(struct iov_iter *i, 679static ssize_t get_pages_bvec(struct iov_iter *i,
725 struct page **pages, size_t maxsize, unsigned maxpages, 680 struct page **pages, size_t maxsize, unsigned maxpages,
726 size_t *start) 681 size_t *start)
@@ -849,10 +804,7 @@ EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
849 804
850void iov_iter_advance(struct iov_iter *i, size_t size) 805void iov_iter_advance(struct iov_iter *i, size_t size)
851{ 806{
852 if (i->type & ITER_BVEC) 807 iterate_and_advance(i, size, v, 0, 0)
853 advance_bvec(i, size);
854 else
855 advance_iovec(i, size);
856} 808}
857EXPORT_SYMBOL(iov_iter_advance); 809EXPORT_SYMBOL(iov_iter_advance);
858 810