diff options
-rw-r--r-- | mm/iov_iter.c | 104 |
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 | |||
73 | static size_t copy_to_iter_iovec(void *from, size_t bytes, struct iov_iter *i) | 100 | static 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 | ||
369 | static 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 | ||
688 | static 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 | |||
724 | static ssize_t get_pages_bvec(struct iov_iter *i, | 679 | static 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 | ||
850 | void iov_iter_advance(struct iov_iter *i, size_t size) | 805 | void 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 | } |
857 | EXPORT_SYMBOL(iov_iter_advance); | 809 | EXPORT_SYMBOL(iov_iter_advance); |
858 | 810 | ||