diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-02-17 18:42:24 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-21 03:31:21 -0400 |
commit | ff76ab9e03a50a4df26329e547e75f865a2bfa9f (patch) | |
tree | 6111fb43d038f57b12e2ebf02aa237cf18fcfed2 /lib/iov_iter.c | |
parent | e485875dff38c79479ba42f80f0230d181a77a56 (diff) |
new privimitive: iov_iter_revert()
commit 27c0e3748e41ca79171ffa3e97415a20af6facd0 upstream.
opposite to iov_iter_advance(); the caller is responsible for never
using it to move back past the initial position.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 efb0b4d267a1..a75ea633b5c4 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -734,6 +734,68 @@ void iov_iter_advance(struct iov_iter *i, size_t size) | |||
734 | } | 734 | } |
735 | EXPORT_SYMBOL(iov_iter_advance); | 735 | EXPORT_SYMBOL(iov_iter_advance); |
736 | 736 | ||
737 | void iov_iter_revert(struct iov_iter *i, size_t unroll) | ||
738 | { | ||
739 | if (!unroll) | ||
740 | return; | ||
741 | i->count += unroll; | ||
742 | if (unlikely(i->type & ITER_PIPE)) { | ||
743 | struct pipe_inode_info *pipe = i->pipe; | ||
744 | int idx = i->idx; | ||
745 | size_t off = i->iov_offset; | ||
746 | while (1) { | ||
747 | size_t n = off - pipe->bufs[idx].offset; | ||
748 | if (unroll < n) { | ||
749 | off -= (n - unroll); | ||
750 | break; | ||
751 | } | ||
752 | unroll -= n; | ||
753 | if (!unroll && idx == i->start_idx) { | ||
754 | off = 0; | ||
755 | break; | ||
756 | } | ||
757 | if (!idx--) | ||
758 | idx = pipe->buffers - 1; | ||
759 | off = pipe->bufs[idx].offset + pipe->bufs[idx].len; | ||
760 | } | ||
761 | i->iov_offset = off; | ||
762 | i->idx = idx; | ||
763 | pipe_truncate(i); | ||
764 | return; | ||
765 | } | ||
766 | if (unroll <= i->iov_offset) { | ||
767 | i->iov_offset -= unroll; | ||
768 | return; | ||
769 | } | ||
770 | unroll -= i->iov_offset; | ||
771 | if (i->type & ITER_BVEC) { | ||
772 | const struct bio_vec *bvec = i->bvec; | ||
773 | while (1) { | ||
774 | size_t n = (--bvec)->bv_len; | ||
775 | i->nr_segs++; | ||
776 | if (unroll <= n) { | ||
777 | i->bvec = bvec; | ||
778 | i->iov_offset = n - unroll; | ||
779 | return; | ||
780 | } | ||
781 | unroll -= n; | ||
782 | } | ||
783 | } else { /* same logics for iovec and kvec */ | ||
784 | const struct iovec *iov = i->iov; | ||
785 | while (1) { | ||
786 | size_t n = (--iov)->iov_len; | ||
787 | i->nr_segs++; | ||
788 | if (unroll <= n) { | ||
789 | i->iov = iov; | ||
790 | i->iov_offset = n - unroll; | ||
791 | return; | ||
792 | } | ||
793 | unroll -= n; | ||
794 | } | ||
795 | } | ||
796 | } | ||
797 | EXPORT_SYMBOL(iov_iter_revert); | ||
798 | |||
737 | /* | 799 | /* |
738 | * Return the count of just the current iov_iter segment. | 800 | * Return the count of just the current iov_iter segment. |
739 | */ | 801 | */ |
@@ -787,6 +849,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction, | |||
787 | i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); | 849 | i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); |
788 | i->iov_offset = 0; | 850 | i->iov_offset = 0; |
789 | i->count = count; | 851 | i->count = count; |
852 | i->start_idx = i->idx; | ||
790 | } | 853 | } |
791 | EXPORT_SYMBOL(iov_iter_pipe); | 854 | EXPORT_SYMBOL(iov_iter_pipe); |
792 | 855 | ||