Loading include/linux/uio.h +5 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,10 @@ struct iov_iter { }; union { unsigned long nr_segs; struct { int idx; int start_idx; }; }; }; Loading Loading @@ -81,6 +84,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to); size_t iov_iter_copy_from_user_atomic(struct page *page, struct iov_iter *i, unsigned long offset, size_t bytes); void iov_iter_advance(struct iov_iter *i, size_t bytes); void iov_iter_revert(struct iov_iter *i, size_t bytes); int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); size_t iov_iter_single_seg_count(const struct iov_iter *i); size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, Loading lib/iov_iter.c +63 −0 Original line number Diff line number Diff line Loading @@ -786,6 +786,68 @@ void iov_iter_advance(struct iov_iter *i, size_t size) } EXPORT_SYMBOL(iov_iter_advance); void iov_iter_revert(struct iov_iter *i, size_t unroll) { if (!unroll) return; i->count += unroll; if (unlikely(i->type & ITER_PIPE)) { struct pipe_inode_info *pipe = i->pipe; int idx = i->idx; size_t off = i->iov_offset; while (1) { size_t n = off - pipe->bufs[idx].offset; if (unroll < n) { off -= (n - unroll); break; } unroll -= n; if (!unroll && idx == i->start_idx) { off = 0; break; } if (!idx--) idx = pipe->buffers - 1; off = pipe->bufs[idx].offset + pipe->bufs[idx].len; } i->iov_offset = off; i->idx = idx; pipe_truncate(i); return; } if (unroll <= i->iov_offset) { i->iov_offset -= unroll; return; } unroll -= i->iov_offset; if (i->type & ITER_BVEC) { const struct bio_vec *bvec = i->bvec; while (1) { size_t n = (--bvec)->bv_len; i->nr_segs++; if (unroll <= n) { i->bvec = bvec; i->iov_offset = n - unroll; return; } unroll -= n; } } else { /* same logics for iovec and kvec */ const struct iovec *iov = i->iov; while (1) { size_t n = (--iov)->iov_len; i->nr_segs++; if (unroll <= n) { i->iov = iov; i->iov_offset = n - unroll; return; } unroll -= n; } } } EXPORT_SYMBOL(iov_iter_revert); /* * Return the count of just the current iov_iter segment. */ Loading Loading @@ -839,6 +901,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction, i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); i->iov_offset = 0; i->count = count; i->start_idx = i->idx; } EXPORT_SYMBOL(iov_iter_pipe); Loading net/core/datagram.c +14 −9 Original line number Diff line number Diff line Loading @@ -398,7 +398,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, struct iov_iter *to, int len) { int start = skb_headlen(skb); int i, copy = start - offset; int i, copy = start - offset, start_off = offset, n; struct sk_buff *frag_iter; trace_skb_copy_datagram_iovec(skb, len); Loading @@ -407,11 +407,12 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, if (copy > 0) { if (copy > len) copy = len; if (copy_to_iter(skb->data + offset, copy, to) != copy) n = copy_to_iter(skb->data + offset, copy, to); offset += n; if (n != copy) goto short_copy; if ((len -= copy) == 0) return 0; offset += copy; } /* Copy paged appendix. Hmm... why does this look so complicated? */ Loading @@ -425,13 +426,14 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, if ((copy = end - offset) > 0) { if (copy > len) copy = len; if (copy_page_to_iter(skb_frag_page(frag), n = copy_page_to_iter(skb_frag_page(frag), frag->page_offset + offset - start, copy, to) != copy) start, copy, to); offset += n; if (n != copy) goto short_copy; if (!(len -= copy)) return 0; offset += copy; } start = end; } Loading Loading @@ -463,6 +465,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, */ fault: iov_iter_revert(to, offset - start_off); return -EFAULT; short_copy: Loading Loading @@ -613,7 +616,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, __wsum *csump) { int start = skb_headlen(skb); int i, copy = start - offset; int i, copy = start - offset, start_off = offset; struct sk_buff *frag_iter; int pos = 0; int n; Loading @@ -623,11 +626,11 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, if (copy > len) copy = len; n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to); offset += n; if (n != copy) goto fault; if ((len -= copy) == 0) return 0; offset += copy; pos = copy; } Loading @@ -649,12 +652,12 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, offset - start, copy, &csum2, to); kunmap(page); offset += n; if (n != copy) goto fault; *csump = csum_block_add(*csump, csum2, pos); if (!(len -= copy)) return 0; offset += copy; pos += copy; } start = end; Loading Loading @@ -687,6 +690,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, return 0; fault: iov_iter_revert(to, offset - start_off); return -EFAULT; } Loading Loading @@ -771,6 +775,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, } return 0; csum_error: iov_iter_revert(&msg->msg_iter, chunk); return -EINVAL; fault: return -EFAULT; Loading Loading
include/linux/uio.h +5 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,10 @@ struct iov_iter { }; union { unsigned long nr_segs; struct { int idx; int start_idx; }; }; }; Loading Loading @@ -81,6 +84,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to); size_t iov_iter_copy_from_user_atomic(struct page *page, struct iov_iter *i, unsigned long offset, size_t bytes); void iov_iter_advance(struct iov_iter *i, size_t bytes); void iov_iter_revert(struct iov_iter *i, size_t bytes); int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); size_t iov_iter_single_seg_count(const struct iov_iter *i); size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, Loading
lib/iov_iter.c +63 −0 Original line number Diff line number Diff line Loading @@ -786,6 +786,68 @@ void iov_iter_advance(struct iov_iter *i, size_t size) } EXPORT_SYMBOL(iov_iter_advance); void iov_iter_revert(struct iov_iter *i, size_t unroll) { if (!unroll) return; i->count += unroll; if (unlikely(i->type & ITER_PIPE)) { struct pipe_inode_info *pipe = i->pipe; int idx = i->idx; size_t off = i->iov_offset; while (1) { size_t n = off - pipe->bufs[idx].offset; if (unroll < n) { off -= (n - unroll); break; } unroll -= n; if (!unroll && idx == i->start_idx) { off = 0; break; } if (!idx--) idx = pipe->buffers - 1; off = pipe->bufs[idx].offset + pipe->bufs[idx].len; } i->iov_offset = off; i->idx = idx; pipe_truncate(i); return; } if (unroll <= i->iov_offset) { i->iov_offset -= unroll; return; } unroll -= i->iov_offset; if (i->type & ITER_BVEC) { const struct bio_vec *bvec = i->bvec; while (1) { size_t n = (--bvec)->bv_len; i->nr_segs++; if (unroll <= n) { i->bvec = bvec; i->iov_offset = n - unroll; return; } unroll -= n; } } else { /* same logics for iovec and kvec */ const struct iovec *iov = i->iov; while (1) { size_t n = (--iov)->iov_len; i->nr_segs++; if (unroll <= n) { i->iov = iov; i->iov_offset = n - unroll; return; } unroll -= n; } } } EXPORT_SYMBOL(iov_iter_revert); /* * Return the count of just the current iov_iter segment. */ Loading Loading @@ -839,6 +901,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction, i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); i->iov_offset = 0; i->count = count; i->start_idx = i->idx; } EXPORT_SYMBOL(iov_iter_pipe); Loading
net/core/datagram.c +14 −9 Original line number Diff line number Diff line Loading @@ -398,7 +398,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, struct iov_iter *to, int len) { int start = skb_headlen(skb); int i, copy = start - offset; int i, copy = start - offset, start_off = offset, n; struct sk_buff *frag_iter; trace_skb_copy_datagram_iovec(skb, len); Loading @@ -407,11 +407,12 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, if (copy > 0) { if (copy > len) copy = len; if (copy_to_iter(skb->data + offset, copy, to) != copy) n = copy_to_iter(skb->data + offset, copy, to); offset += n; if (n != copy) goto short_copy; if ((len -= copy) == 0) return 0; offset += copy; } /* Copy paged appendix. Hmm... why does this look so complicated? */ Loading @@ -425,13 +426,14 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, if ((copy = end - offset) > 0) { if (copy > len) copy = len; if (copy_page_to_iter(skb_frag_page(frag), n = copy_page_to_iter(skb_frag_page(frag), frag->page_offset + offset - start, copy, to) != copy) start, copy, to); offset += n; if (n != copy) goto short_copy; if (!(len -= copy)) return 0; offset += copy; } start = end; } Loading Loading @@ -463,6 +465,7 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, */ fault: iov_iter_revert(to, offset - start_off); return -EFAULT; short_copy: Loading Loading @@ -613,7 +616,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, __wsum *csump) { int start = skb_headlen(skb); int i, copy = start - offset; int i, copy = start - offset, start_off = offset; struct sk_buff *frag_iter; int pos = 0; int n; Loading @@ -623,11 +626,11 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, if (copy > len) copy = len; n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to); offset += n; if (n != copy) goto fault; if ((len -= copy) == 0) return 0; offset += copy; pos = copy; } Loading @@ -649,12 +652,12 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, offset - start, copy, &csum2, to); kunmap(page); offset += n; if (n != copy) goto fault; *csump = csum_block_add(*csump, csum2, pos); if (!(len -= copy)) return 0; offset += copy; pos += copy; } start = end; Loading Loading @@ -687,6 +690,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, return 0; fault: iov_iter_revert(to, offset - start_off); return -EFAULT; } Loading Loading @@ -771,6 +775,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, } return 0; csum_error: iov_iter_revert(&msg->msg_iter, chunk); return -EINVAL; fault: return -EFAULT; Loading