aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/uio.h6
-rw-r--r--lib/iov_iter.c63
2 files changed, 68 insertions, 1 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 6e22b544d039..c146ebc69c53 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -39,7 +39,10 @@ struct iov_iter {
39 }; 39 };
40 union { 40 union {
41 unsigned long nr_segs; 41 unsigned long nr_segs;
42 int idx; 42 struct {
43 int idx;
44 int start_idx;
45 };
43 }; 46 };
44}; 47};
45 48
@@ -81,6 +84,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to);
81size_t iov_iter_copy_from_user_atomic(struct page *page, 84size_t iov_iter_copy_from_user_atomic(struct page *page,
82 struct iov_iter *i, unsigned long offset, size_t bytes); 85 struct iov_iter *i, unsigned long offset, size_t bytes);
83void iov_iter_advance(struct iov_iter *i, size_t bytes); 86void iov_iter_advance(struct iov_iter *i, size_t bytes);
87void iov_iter_revert(struct iov_iter *i, size_t bytes);
84int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); 88int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
85size_t iov_iter_single_seg_count(const struct iov_iter *i); 89size_t iov_iter_single_seg_count(const struct iov_iter *i);
86size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, 90size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
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