diff options
Diffstat (limited to 'lib/iov_iter.c')
-rw-r--r-- | lib/iov_iter.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index e68604ae3ced..60abc44385b7 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -786,6 +786,68 @@ void iov_iter_advance(struct iov_iter *i, size_t size) | |||
786 | } | 786 | } |
787 | EXPORT_SYMBOL(iov_iter_advance); | 787 | EXPORT_SYMBOL(iov_iter_advance); |
788 | 788 | ||
789 | void iov_iter_revert(struct iov_iter *i, size_t unroll) | ||
790 | { | ||
791 | if (!unroll) | ||
792 | return; | ||
793 | i->count += unroll; | ||
794 | if (unlikely(i->type & ITER_PIPE)) { | ||
795 | struct pipe_inode_info *pipe = i->pipe; | ||
796 | int idx = i->idx; | ||
797 | size_t off = i->iov_offset; | ||
798 | while (1) { | ||
799 | size_t n = off - pipe->bufs[idx].offset; | ||
800 | if (unroll < n) { | ||
801 | off -= (n - unroll); | ||
802 | break; | ||
803 | } | ||
804 | unroll -= n; | ||
805 | if (!unroll && idx == i->start_idx) { | ||
806 | off = 0; | ||
807 | break; | ||
808 | } | ||
809 | if (!idx--) | ||
810 | idx = pipe->buffers - 1; | ||
811 | off = pipe->bufs[idx].offset + pipe->bufs[idx].len; | ||
812 | } | ||
813 | i->iov_offset = off; | ||
814 | i->idx = idx; | ||
815 | pipe_truncate(i); | ||
816 | return; | ||
817 | } | ||
818 | if (unroll <= i->iov_offset) { | ||
819 | i->iov_offset -= unroll; | ||
820 | return; | ||
821 | } | ||
822 | unroll -= i->iov_offset; | ||
823 | if (i->type & ITER_BVEC) { | ||
824 | const struct bio_vec *bvec = i->bvec; | ||
825 | while (1) { | ||
826 | size_t n = (--bvec)->bv_len; | ||
827 | i->nr_segs++; | ||
828 | if (unroll <= n) { | ||
829 | i->bvec = bvec; | ||
830 | i->iov_offset = n - unroll; | ||
831 | return; | ||
832 | } | ||
833 | unroll -= n; | ||
834 | } | ||
835 | } else { /* same logics for iovec and kvec */ | ||
836 | const struct iovec *iov = i->iov; | ||
837 | while (1) { | ||
838 | size_t n = (--iov)->iov_len; | ||
839 | i->nr_segs++; | ||
840 | if (unroll <= n) { | ||
841 | i->iov = iov; | ||
842 | i->iov_offset = n - unroll; | ||
843 | return; | ||
844 | } | ||
845 | unroll -= n; | ||
846 | } | ||
847 | } | ||
848 | } | ||
849 | EXPORT_SYMBOL(iov_iter_revert); | ||
850 | |||
789 | /* | 851 | /* |
790 | * Return the count of just the current iov_iter segment. | 852 | * Return the count of just the current iov_iter segment. |
791 | */ | 853 | */ |
@@ -839,6 +901,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction, | |||
839 | i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); | 901 | i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); |
840 | i->iov_offset = 0; | 902 | i->iov_offset = 0; |
841 | i->count = count; | 903 | i->count = count; |
904 | i->start_idx = i->idx; | ||
842 | } | 905 | } |
843 | EXPORT_SYMBOL(iov_iter_pipe); | 906 | EXPORT_SYMBOL(iov_iter_pipe); |
844 | 907 | ||