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 | ||
