Commit 7b7699c0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull iov_iter fixes from Al Viro:
 "Fixes for io-uring handling of iov_iter reexpands"

* 'work.iov_iter' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  io_uring: reexpand under-reexpanded iters
  iov_iter: track truncated size
parents 70868a18 89c2b3b7
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -3480,6 +3480,7 @@ static int io_read(struct io_kiocb *req, unsigned int issue_flags)
		if (req->flags & REQ_F_NOWAIT)
		if (req->flags & REQ_F_NOWAIT)
			goto done;
			goto done;
		/* some cases will consume bytes even on error returns */
		/* some cases will consume bytes even on error returns */
		iov_iter_reexpand(iter, iter->count + iter->truncated);
		iov_iter_revert(iter, io_size - iov_iter_count(iter));
		iov_iter_revert(iter, io_size - iov_iter_count(iter));
		ret = 0;
		ret = 0;
	} else if (ret == -EIOCBQUEUED) {
	} else if (ret == -EIOCBQUEUED) {
@@ -3619,6 +3620,7 @@ static int io_write(struct io_kiocb *req, unsigned int issue_flags)
	} else {
	} else {
copy_iov:
copy_iov:
		/* some cases will consume bytes even on error returns */
		/* some cases will consume bytes even on error returns */
		iov_iter_reexpand(iter, iter->count + iter->truncated);
		iov_iter_revert(iter, io_size - iov_iter_count(iter));
		iov_iter_revert(iter, io_size - iov_iter_count(iter));
		ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false);
		ret = io_setup_async_rw(req, iovec, inline_vecs, iter, false);
		return ret ?: -EAGAIN;
		return ret ?: -EAGAIN;
+5 −1
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ struct iov_iter {
		};
		};
		loff_t xarray_start;
		loff_t xarray_start;
	};
	};
	size_t truncated;
};
};


static inline enum iter_type iov_iter_type(const struct iov_iter *i)
static inline enum iter_type iov_iter_type(const struct iov_iter *i)
@@ -254,9 +255,11 @@ static inline void iov_iter_truncate(struct iov_iter *i, u64 count)
	 * conversion in assignement is by definition greater than all
	 * conversion in assignement is by definition greater than all
	 * values of size_t, including old i->count.
	 * values of size_t, including old i->count.
	 */
	 */
	if (i->count > count)
	if (i->count > count) {
		i->truncated += i->count - count;
		i->count = count;
		i->count = count;
	}
	}
}


/*
/*
 * reexpand a previously truncated iterator; count must be no more than how much
 * reexpand a previously truncated iterator; count must be no more than how much
@@ -264,6 +267,7 @@ static inline void iov_iter_truncate(struct iov_iter *i, u64 count)
 */
 */
static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
{
{
	i->truncated -= count - i->count;
	i->count = count;
	i->count = count;
}
}