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

Commit c5e4ca6d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull VFS fixes from Al Viro:
 "Christoph's and Jan's aio fixes, fixup for generic_file_splice_read
  (removal of pointless detritus that actually breaks it when used for
  gfs2 ->splice_read()) and fixup for generic_file_read_iter()
  interaction with ITER_PIPE destinations."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  splice: remove detritus from generic_file_splice_read()
  mm/filemap: don't allow partially uptodate page for pipes
  aio: fix freeze protection of aio writes
  fs: remove aio_run_iocb
  fs: remove the never implemented aio_fsync file operation
  aio: hold an extra file reference over AIO read/write operations
parents ef091b3c e519e777
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -447,7 +447,6 @@ prototypes:
	int (*flush) (struct file *);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t start, loff_t end, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
+0 −1
Original line number Diff line number Diff line
@@ -828,7 +828,6 @@ struct file_operations {
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*aio_fsync) (struct kiocb *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
+109 −98
Original line number Diff line number Diff line
@@ -1078,6 +1078,17 @@ static void aio_complete(struct kiocb *kiocb, long res, long res2)
	unsigned tail, pos, head;
	unsigned long	flags;

	if (kiocb->ki_flags & IOCB_WRITE) {
		struct file *file = kiocb->ki_filp;

		/*
		 * Tell lockdep we inherited freeze protection from submission
		 * thread.
		 */
		__sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
		file_end_write(file);
	}

	/*
	 * Special case handling for sync iocbs:
	 *  - events go directly into the iocb for fast handling
@@ -1392,122 +1403,106 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
	return -EINVAL;
}

typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *);

static int aio_setup_vectored_rw(int rw, char __user *buf, size_t len,
				 struct iovec **iovec,
				 bool compat,
				 struct iov_iter *iter)
static int aio_setup_rw(int rw, struct iocb *iocb, struct iovec **iovec,
		bool vectored, bool compat, struct iov_iter *iter)
{
	void __user *buf = (void __user *)(uintptr_t)iocb->aio_buf;
	size_t len = iocb->aio_nbytes;

	if (!vectored) {
		ssize_t ret = import_single_range(rw, buf, len, *iovec, iter);
		*iovec = NULL;
		return ret;
	}
#ifdef CONFIG_COMPAT
	if (compat)
		return compat_import_iovec(rw,
				(struct compat_iovec __user *)buf,
				len, UIO_FASTIOV, iovec, iter);
		return compat_import_iovec(rw, buf, len, UIO_FASTIOV, iovec,
				iter);
#endif
	return import_iovec(rw, (struct iovec __user *)buf,
				len, UIO_FASTIOV, iovec, iter);
	return import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter);
}

static inline ssize_t aio_ret(struct kiocb *req, ssize_t ret)
{
	switch (ret) {
	case -EIOCBQUEUED:
		return ret;
	case -ERESTARTSYS:
	case -ERESTARTNOINTR:
	case -ERESTARTNOHAND:
	case -ERESTART_RESTARTBLOCK:
		/*
 * aio_run_iocb:
 *	Performs the initial checks and io submission.
		 * There's no easy way to restart the syscall since other AIO's
		 * may be already running. Just fail this IO with EINTR.
		 */
static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
			    char __user *buf, size_t len, bool compat)
		ret = -EINTR;
		/*FALLTHRU*/
	default:
		aio_complete(req, ret, 0);
		return 0;
	}
}

static ssize_t aio_read(struct kiocb *req, struct iocb *iocb, bool vectored,
		bool compat)
{
	struct file *file = req->ki_filp;
	ssize_t ret;
	int rw;
	fmode_t mode;
	rw_iter_op *iter_op;
	struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
	struct iov_iter iter;
	ssize_t ret;

	switch (opcode) {
	case IOCB_CMD_PREAD:
	case IOCB_CMD_PREADV:
		mode	= FMODE_READ;
		rw	= READ;
		iter_op	= file->f_op->read_iter;
		goto rw_common;

	case IOCB_CMD_PWRITE:
	case IOCB_CMD_PWRITEV:
		mode	= FMODE_WRITE;
		rw	= WRITE;
		iter_op	= file->f_op->write_iter;
		goto rw_common;
rw_common:
		if (unlikely(!(file->f_mode & mode)))
	if (unlikely(!(file->f_mode & FMODE_READ)))
		return -EBADF;

		if (!iter_op)
	if (unlikely(!file->f_op->read_iter))
		return -EINVAL;

		if (opcode == IOCB_CMD_PREADV || opcode == IOCB_CMD_PWRITEV)
			ret = aio_setup_vectored_rw(rw, buf, len,
						&iovec, compat, &iter);
		else {
			ret = import_single_range(rw, buf, len, iovec, &iter);
			iovec = NULL;
		}
	ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
	if (ret)
		return ret;
	ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
	if (!ret)
			ret = rw_verify_area(rw, file, &req->ki_pos,
					     iov_iter_count(&iter));
		if (ret < 0) {
		ret = aio_ret(req, file->f_op->read_iter(req, &iter));
	kfree(iovec);
	return ret;
}

		if (rw == WRITE)
			file_start_write(file);

		ret = iter_op(req, &iter);

		if (rw == WRITE)
			file_end_write(file);
		kfree(iovec);
		break;

	case IOCB_CMD_FDSYNC:
		if (!file->f_op->aio_fsync)
			return -EINVAL;

		ret = file->f_op->aio_fsync(req, 1);
		break;

	case IOCB_CMD_FSYNC:
		if (!file->f_op->aio_fsync)
			return -EINVAL;

		ret = file->f_op->aio_fsync(req, 0);
		break;
static ssize_t aio_write(struct kiocb *req, struct iocb *iocb, bool vectored,
		bool compat)
{
	struct file *file = req->ki_filp;
	struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
	struct iov_iter iter;
	ssize_t ret;

	default:
		pr_debug("EINVAL: no operation provided\n");
	if (unlikely(!(file->f_mode & FMODE_WRITE)))
		return -EBADF;
	if (unlikely(!file->f_op->write_iter))
		return -EINVAL;
	}

	if (ret != -EIOCBQUEUED) {
	ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
	if (ret)
		return ret;
	ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
	if (!ret) {
		req->ki_flags |= IOCB_WRITE;
		file_start_write(file);
		ret = aio_ret(req, file->f_op->write_iter(req, &iter));
		/*
		 * There's no easy way to restart the syscall since other AIO's
		 * may be already running. Just fail this IO with EINTR.
		 * We release freeze protection in aio_complete().  Fool lockdep
		 * by telling it the lock got released so that it doesn't
		 * complain about held lock when we return to userspace.
		 */
		if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR ||
			     ret == -ERESTARTNOHAND ||
			     ret == -ERESTART_RESTARTBLOCK))
			ret = -EINTR;
		aio_complete(req, ret, 0);
		__sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
	}

	return 0;
	kfree(iovec);
	return ret;
}

static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
			 struct iocb *iocb, bool compat)
{
	struct aio_kiocb *req;
	struct file *file;
	ssize_t ret;

	/* enforce forwards compatibility on users */
@@ -1530,7 +1525,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
	if (unlikely(!req))
		return -EAGAIN;

	req->common.ki_filp = fget(iocb->aio_fildes);
	req->common.ki_filp = file = fget(iocb->aio_fildes);
	if (unlikely(!req->common.ki_filp)) {
		ret = -EBADF;
		goto out_put_req;
@@ -1565,13 +1560,29 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
	req->ki_user_iocb = user_iocb;
	req->ki_user_data = iocb->aio_data;

	ret = aio_run_iocb(&req->common, iocb->aio_lio_opcode,
			   (char __user *)(unsigned long)iocb->aio_buf,
			   iocb->aio_nbytes,
			   compat);
	if (ret)
		goto out_put_req;
	get_file(file);
	switch (iocb->aio_lio_opcode) {
	case IOCB_CMD_PREAD:
		ret = aio_read(&req->common, iocb, false, compat);
		break;
	case IOCB_CMD_PWRITE:
		ret = aio_write(&req->common, iocb, false, compat);
		break;
	case IOCB_CMD_PREADV:
		ret = aio_read(&req->common, iocb, true, compat);
		break;
	case IOCB_CMD_PWRITEV:
		ret = aio_write(&req->common, iocb, true, compat);
		break;
	default:
		pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode);
		ret = -EINVAL;
		break;
	}
	fput(file);

	if (ret && ret != -EIOCBQUEUED)
		goto out_put_req;
	return 0;
out_put_req:
	put_reqs_available(ctx, 1);
+0 −2
Original line number Diff line number Diff line
@@ -1544,8 +1544,6 @@ const struct file_operations ntfs_dir_ops = {
	.iterate	= ntfs_readdir,		/* Read directory contents. */
#ifdef NTFS_RW
	.fsync		= ntfs_dir_fsync,	/* Sync a directory to disk. */
	/*.aio_fsync	= ,*/			/* Sync all outstanding async
						   i/o operations on a kiocb. */
#endif /* NTFS_RW */
	/*.ioctl	= ,*/			/* Perform function on the
						   mounted filesystem. */
+0 −5
Original line number Diff line number Diff line
@@ -299,13 +299,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
{
	struct iov_iter to;
	struct kiocb kiocb;
	loff_t isize;
	int idx, ret;

	isize = i_size_read(in->f_mapping->host);
	if (unlikely(*ppos >= isize))
		return 0;

	iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len);
	idx = to.idx;
	init_sync_kiocb(&kiocb, in);
Loading