Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e4c0ee5 authored by David S. Miller's avatar David S. Miller
Browse files
parents ea6b1720 32786821
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -39,7 +39,10 @@ struct iov_iter {
	};
	union {
		unsigned long nr_segs;
		struct {
			int idx;
			int start_idx;
		};
	};
};

@@ -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,
+63 −0
Original line number Diff line number Diff line
@@ -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.
 */
@@ -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);

+14 −9
Original line number Diff line number Diff line
@@ -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);
@@ -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? */
@@ -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;
	}
@@ -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:
@@ -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;
@@ -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;
	}

@@ -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;
@@ -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;
}

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