aboutsummaryrefslogtreecommitdiffstats
path: root/lib/iov_iter.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-02-17 18:42:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-21 03:31:21 -0400
commitff76ab9e03a50a4df26329e547e75f865a2bfa9f (patch)
tree6111fb43d038f57b12e2ebf02aa237cf18fcfed2 /lib/iov_iter.c
parente485875dff38c79479ba42f80f0230d181a77a56 (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.c63
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}
735EXPORT_SYMBOL(iov_iter_advance); 735EXPORT_SYMBOL(iov_iter_advance);
736 736
737void 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}
797EXPORT_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}
791EXPORT_SYMBOL(iov_iter_pipe); 854EXPORT_SYMBOL(iov_iter_pipe);
792 855