Commit f30adc0d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'pull-work.iov_iter-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull more iov_iter updates from Al Viro:

 - more new_sync_{read,write}() speedups - ITER_UBUF introduction

 - ITER_PIPE cleanups

 - unification of iov_iter_get_pages/iov_iter_get_pages_alloc and
   switching them to advancing semantics

 - making ITER_PIPE take high-order pages without splitting them

 - handling copy_page_from_iter() for high-order pages properly

* tag 'pull-work.iov_iter-rebased' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (32 commits)
  fix copy_page_from_iter() for compound destinations
  hugetlbfs: copy_page_to_iter() can deal with compound pages
  copy_page_to_iter(): don't split high-order page in case of ITER_PIPE
  expand those iov_iter_advance()...
  pipe_get_pages(): switch to append_pipe()
  get rid of non-advancing variants
  ceph: switch the last caller of iov_iter_get_pages_alloc()
  9p: convert to advancing variant of iov_iter_get_pages_alloc()
  af_alg_make_sg(): switch to advancing variant of iov_iter_get_pages()
  iter_to_pipe(): switch to advancing variant of iov_iter_get_pages()
  block: convert to advancing variants of iov_iter_get_pages{,_alloc}()
  iov_iter: advancing variants of iov_iter_get_pages{,_alloc}()
  iov_iter: saner helper for page array allocation
  fold __pipe_get_pages() into pipe_get_pages()
  ITER_XARRAY: don't open-code DIV_ROUND_UP()
  unify the rest of iov_iter_get_pages()/iov_iter_get_pages_alloc() guts
  unify xarray_get_pages() and xarray_get_pages_alloc()
  unify pipe_get_pages() and pipe_get_pages_alloc()
  iov_iter_get_pages(): sanity-check arguments
  iov_iter_get_pages_alloc(): lift freeing pages array on failure exits into wrapper
  ...
parents 5d5d353b c03f05f1
Loading
Loading
Loading
Loading
+14 −11
Original line number Original line Diff line number Diff line
@@ -1200,7 +1200,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
	struct page **pages = (struct page **)bv;
	struct page **pages = (struct page **)bv;
	ssize_t size, left;
	ssize_t size, left;
	unsigned len, i = 0;
	unsigned len, i = 0;
	size_t offset;
	size_t offset, trim;
	int ret = 0;
	int ret = 0;


	/*
	/*
@@ -1218,16 +1218,19 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
	 * result to ensure the bio's total size is correct. The remainder of
	 * result to ensure the bio's total size is correct. The remainder of
	 * the iov data will be picked up in the next bio iteration.
	 * the iov data will be picked up in the next bio iteration.
	 */
	 */
	size = iov_iter_get_pages(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
	size = iov_iter_get_pages2(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
				  nr_pages, &offset);
				  nr_pages, &offset);
	if (size > 0) {
	if (unlikely(size <= 0))
		return size ? size : -EFAULT;

	nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
	nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
		size = ALIGN_DOWN(size, bdev_logical_block_size(bio->bi_bdev));
	} else
		nr_pages = 0;


	if (unlikely(size <= 0)) {
	trim = size & (bdev_logical_block_size(bio->bi_bdev) - 1);
		ret = size ? size : -EFAULT;
	iov_iter_revert(iter, trim);

	size -= trim;
	if (unlikely(!size)) {
		ret = -EFAULT;
		goto out;
		goto out;
	}
	}


@@ -1246,7 +1249,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
		offset = 0;
		offset = 0;
	}
	}


	iov_iter_advance(iter, size - left);
	iov_iter_revert(iter, left);
out:
out:
	while (i < nr_pages)
	while (i < nr_pages)
		put_page(pages[i++]);
		put_page(pages[i++]);
+4 −3
Original line number Original line Diff line number Diff line
@@ -254,7 +254,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
		size_t offs, added = 0;
		size_t offs, added = 0;
		int npages;
		int npages;


		bytes = iov_iter_get_pages_alloc(iter, &pages, LONG_MAX, &offs);
		bytes = iov_iter_get_pages_alloc2(iter, &pages, LONG_MAX, &offs);
		if (unlikely(bytes <= 0)) {
		if (unlikely(bytes <= 0)) {
			ret = bytes ? bytes : -EFAULT;
			ret = bytes ? bytes : -EFAULT;
			goto out_unmap;
			goto out_unmap;
@@ -284,7 +284,6 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
				bytes -= n;
				bytes -= n;
				offs = 0;
				offs = 0;
			}
			}
			iov_iter_advance(iter, added);
		}
		}
		/*
		/*
		 * release the pages we didn't map into the bio, if any
		 * release the pages we didn't map into the bio, if any
@@ -293,9 +292,11 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
			put_page(pages[j++]);
			put_page(pages[j++]);
		kvfree(pages);
		kvfree(pages);
		/* couldn't stuff something into bio? */
		/* couldn't stuff something into bio? */
		if (bytes)
		if (bytes) {
			iov_iter_revert(iter, bytes);
			break;
			break;
		}
		}
	}


	ret = blk_rq_append_bio(rq, bio);
	ret = blk_rq_append_bio(rq, bio);
	if (ret)
	if (ret)
+3 −3
Original line number Original line Diff line number Diff line
@@ -75,7 +75,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,


	if (iov_iter_rw(iter) == READ) {
	if (iov_iter_rw(iter) == READ) {
		bio_init(&bio, bdev, vecs, nr_pages, REQ_OP_READ);
		bio_init(&bio, bdev, vecs, nr_pages, REQ_OP_READ);
		if (iter_is_iovec(iter))
		if (user_backed_iter(iter))
			should_dirty = true;
			should_dirty = true;
	} else {
	} else {
		bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
		bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
@@ -204,7 +204,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
	}
	}


	dio->size = 0;
	dio->size = 0;
	if (is_read && iter_is_iovec(iter))
	if (is_read && user_backed_iter(iter))
		dio->flags |= DIO_SHOULD_DIRTY;
		dio->flags |= DIO_SHOULD_DIRTY;


	blk_start_plug(&plug);
	blk_start_plug(&plug);
@@ -335,7 +335,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
	dio->size = bio->bi_iter.bi_size;
	dio->size = bio->bi_iter.bi_size;


	if (is_read) {
	if (is_read) {
		if (iter_is_iovec(iter)) {
		if (user_backed_iter(iter)) {
			dio->flags |= DIO_SHOULD_DIRTY;
			dio->flags |= DIO_SHOULD_DIRTY;
			bio_set_pages_dirty(bio);
			bio_set_pages_dirty(bio);
		}
		}
+1 −2
Original line number Original line Diff line number Diff line
@@ -404,7 +404,7 @@ int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
	ssize_t n;
	ssize_t n;
	int npages, i;
	int npages, i;


	n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
	n = iov_iter_get_pages2(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
	if (n < 0)
	if (n < 0)
		return n;
		return n;


@@ -1191,7 +1191,6 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
		len += err;
		len += err;
		atomic_add(err, &ctx->rcvused);
		atomic_add(err, &ctx->rcvused);
		rsgl->sg_num_bytes = err;
		rsgl->sg_num_bytes = err;
		iov_iter_advance(&msg->msg_iter, err);
	}
	}


	*outlen = len;
	*outlen = len;
+3 −2
Original line number Original line Diff line number Diff line
@@ -102,11 +102,12 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
		err = crypto_wait_req(crypto_ahash_update(&ctx->req),
		err = crypto_wait_req(crypto_ahash_update(&ctx->req),
				      &ctx->wait);
				      &ctx->wait);
		af_alg_free_sg(&ctx->sgl);
		af_alg_free_sg(&ctx->sgl);
		if (err)
		if (err) {
			iov_iter_revert(&msg->msg_iter, len);
			goto unlock;
			goto unlock;
		}


		copied += len;
		copied += len;
		iov_iter_advance(&msg->msg_iter, len);
	}
	}


	err = 0;
	err = 0;
Loading