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

Commit 89fbf538 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'work.read_write' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull read/write updates from Al Viro:
 "Christoph's fs/read_write.c series - consolidation and cleanups"

* 'work.read_write' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  nfsd: remove nfsd_vfs_read
  nfsd: use vfs_iter_read/write
  fs: implement vfs_iter_write using do_iter_write
  fs: implement vfs_iter_read using do_iter_read
  fs: move more code into do_iter_read/do_iter_write
  fs: remove __do_readv_writev
  fs: remove do_compat_readv_writev
  fs: remove do_readv_writev
parents 4be95131 a4058c5b
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -273,7 +273,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
	iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len);
	iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len);


	file_start_write(file);
	file_start_write(file);
	bw = vfs_iter_write(file, &i, ppos);
	bw = vfs_iter_write(file, &i, ppos, 0);
	file_end_write(file);
	file_end_write(file);


	if (likely(bw ==  bvec->bv_len))
	if (likely(bw ==  bvec->bv_len))
@@ -349,7 +349,7 @@ static int lo_read_simple(struct loop_device *lo, struct request *rq,


	rq_for_each_segment(bvec, rq, iter) {
	rq_for_each_segment(bvec, rq, iter) {
		iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len);
		iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len);
		len = vfs_iter_read(lo->lo_backing_file, &i, &pos);
		len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
		if (len < 0)
		if (len < 0)
			return len;
			return len;


@@ -390,7 +390,7 @@ static int lo_read_transfer(struct loop_device *lo, struct request *rq,
		b.bv_len = bvec.bv_len;
		b.bv_len = bvec.bv_len;


		iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len);
		iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len);
		len = vfs_iter_read(lo->lo_backing_file, &i, &pos);
		len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0);
		if (len < 0) {
		if (len < 0) {
			ret = len;
			ret = len;
			goto out_free_page;
			goto out_free_page;
+3 −3
Original line number Original line Diff line number Diff line
@@ -273,9 +273,9 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,


	iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
	iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
	if (is_write)
	if (is_write)
		ret = vfs_iter_write(fd, &iter, &pos);
		ret = vfs_iter_write(fd, &iter, &pos, 0);
	else
	else
		ret = vfs_iter_read(fd, &iter, &pos);
		ret = vfs_iter_read(fd, &iter, &pos, 0);


	if (is_write) {
	if (is_write) {
		if (ret < 0 || ret != data_length) {
		if (ret < 0 || ret != data_length) {
@@ -409,7 +409,7 @@ fd_execute_write_same(struct se_cmd *cmd)
	}
	}


	iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
	iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
	ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos);
	ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);


	kfree(bvec);
	kfree(bvec);
	if (ret < 0 || ret != len) {
	if (ret < 0 || ret != len) {
+2 −2
Original line number Original line Diff line number Diff line
@@ -34,7 +34,7 @@ coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)


	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);


	return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos);
	return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0);
}
}


static ssize_t
static ssize_t
@@ -51,7 +51,7 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
	host_file = cfi->cfi_container;
	host_file = cfi->cfi_container;
	file_start_write(host_file);
	file_start_write(host_file);
	inode_lock(coda_inode);
	inode_lock(coda_inode);
	ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos);
	ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0);
	coda_inode->i_size = file_inode(host_file)->i_size;
	coda_inode->i_size = file_inode(host_file)->i_size;
	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
	coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
	coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
+13 −21
Original line number Original line Diff line number Diff line
@@ -911,24 +911,13 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp,
__be32 nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
__be32 nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
		unsigned long *count)
		unsigned long *count)
{
{
	mm_segment_t oldfs;
	struct iov_iter iter;
	int host_err;
	int host_err;


	oldfs = get_fs();
	iov_iter_kvec(&iter, READ | ITER_KVEC, vec, vlen, *count);
	set_fs(KERNEL_DS);
	host_err = vfs_iter_read(file, &iter, &offset, 0);
	host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset, 0);
	set_fs(oldfs);
	return nfsd_finish_read(file, count, host_err);
}


static __be32
	return nfsd_finish_read(file, count, host_err);
nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file,
	      loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{
	if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
		return nfsd_splice_read(rqstp, file, offset, count);
	else
		return nfsd_readv(file, offset, vec, vlen, count);
}
}


/*
/*
@@ -974,7 +963,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
				unsigned long *cnt, int stable)
				unsigned long *cnt, int stable)
{
{
	struct svc_export	*exp;
	struct svc_export	*exp;
	mm_segment_t		oldfs;
	struct iov_iter		iter;
	__be32			err = 0;
	__be32			err = 0;
	int			host_err;
	int			host_err;
	int			use_wgather;
	int			use_wgather;
@@ -1000,10 +989,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
	if (stable && !use_wgather)
	if (stable && !use_wgather)
		flags |= RWF_SYNC;
		flags |= RWF_SYNC;


	/* Write the data. */
	iov_iter_kvec(&iter, WRITE | ITER_KVEC, vec, vlen, *cnt);
	oldfs = get_fs(); set_fs(KERNEL_DS);
	host_err = vfs_iter_write(file, &iter, &pos, flags);
	host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &pos, flags);
	set_fs(oldfs);
	if (host_err < 0)
	if (host_err < 0)
		goto out_nfserr;
		goto out_nfserr;
	*cnt = host_err;
	*cnt = host_err;
@@ -1044,7 +1031,12 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
	ra = nfsd_init_raparms(file);
	ra = nfsd_init_raparms(file);


	trace_read_opened(rqstp, fhp, offset, vlen);
	trace_read_opened(rqstp, fhp, offset, vlen);
	err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count);

	if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
		err = nfsd_splice_read(rqstp, file, offset, count);
	else
		err = nfsd_readv(file, offset, vec, vlen, count);

	trace_read_io_done(rqstp, fhp, offset, vlen);
	trace_read_io_done(rqstp, fhp, offset, vlen);


	if (ra)
	if (ra)
+91 −129
Original line number Original line Diff line number Diff line
@@ -356,46 +356,6 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
}
}
#endif
#endif


ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos)
{
	struct kiocb kiocb;
	ssize_t ret;

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

	init_sync_kiocb(&kiocb, file);
	kiocb.ki_pos = *ppos;

	iter->type |= READ;
	ret = call_read_iter(file, &kiocb, iter);
	BUG_ON(ret == -EIOCBQUEUED);
	if (ret > 0)
		*ppos = kiocb.ki_pos;
	return ret;
}
EXPORT_SYMBOL(vfs_iter_read);

ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos)
{
	struct kiocb kiocb;
	ssize_t ret;

	if (!file->f_op->write_iter)
		return -EINVAL;

	init_sync_kiocb(&kiocb, file);
	kiocb.ki_pos = *ppos;

	iter->type |= WRITE;
	ret = call_write_iter(file, &kiocb, iter);
	BUG_ON(ret == -EIOCBQUEUED);
	if (ret > 0)
		*ppos = kiocb.ki_pos;
	return ret;
}
EXPORT_SYMBOL(vfs_iter_write);

int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
{
{
	struct inode *inode;
	struct inode *inode;
@@ -910,86 +870,114 @@ ssize_t compat_rw_copy_check_uvector(int type,
}
}
#endif
#endif


static ssize_t __do_readv_writev(int type, struct file *file,
static ssize_t do_iter_read(struct file *file, struct iov_iter *iter,
				 struct iov_iter *iter, loff_t *pos, int flags)
		loff_t *pos, int flags)
{
{
	size_t tot_len;
	size_t tot_len;
	ssize_t ret = 0;
	ssize_t ret = 0;


	if (!(file->f_mode & FMODE_READ))
		return -EBADF;
	if (!(file->f_mode & FMODE_CAN_READ))
		return -EINVAL;

	tot_len = iov_iter_count(iter);
	tot_len = iov_iter_count(iter);
	if (!tot_len)
	if (!tot_len)
		goto out;
		goto out;
	ret = rw_verify_area(type, file, pos, tot_len);
	ret = rw_verify_area(READ, file, pos, tot_len);
	if (ret < 0)
	if (ret < 0)
		goto out;
		return ret;

	if (type != READ)
		file_start_write(file);


	if ((type == READ && file->f_op->read_iter) ||
	if (file->f_op->read_iter)
	    (type == WRITE && file->f_op->write_iter))
		ret = do_iter_readv_writev(file, iter, pos, READ, flags);
		ret = do_iter_readv_writev(file, iter, pos, type, flags);
	else
	else
		ret = do_loop_readv_writev(file, iter, pos, type, flags);
		ret = do_loop_readv_writev(file, iter, pos, READ, flags);

	if (type != READ)
		file_end_write(file);

out:
out:
	if ((ret + (type == READ)) > 0) {
	if (ret >= 0)
		if (type == READ)
		fsnotify_access(file);
		fsnotify_access(file);
		else
			fsnotify_modify(file);
	}
	return ret;
	return ret;
}
}


static ssize_t do_readv_writev(int type, struct file *file,
ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos,
			       const struct iovec __user *uvector,
			       unsigned long nr_segs, loff_t *pos,
		int flags)
		int flags)
{
{
	struct iovec iovstack[UIO_FASTIOV];
	if (!file->f_op->read_iter)
	struct iovec *iov = iovstack;
		return -EINVAL;
	struct iov_iter iter;
	return do_iter_read(file, iter, ppos, flags);
	ssize_t ret;
}
EXPORT_SYMBOL(vfs_iter_read);

static ssize_t do_iter_write(struct file *file, struct iov_iter *iter,
		loff_t *pos, int flags)
{
	size_t tot_len;
	ssize_t ret = 0;

	if (!(file->f_mode & FMODE_WRITE))
		return -EBADF;
	if (!(file->f_mode & FMODE_CAN_WRITE))
		return -EINVAL;


	ret = import_iovec(type, uvector, nr_segs,
	tot_len = iov_iter_count(iter);
			   ARRAY_SIZE(iovstack), &iov, &iter);
	if (!tot_len)
		return 0;
	ret = rw_verify_area(WRITE, file, pos, tot_len);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	ret = __do_readv_writev(type, file, &iter, pos, flags);
	file_start_write(file);
	kfree(iov);
	if (file->f_op->write_iter)

		ret = do_iter_readv_writev(file, iter, pos, WRITE, flags);
	else
		ret = do_loop_readv_writev(file, iter, pos, WRITE, flags);
	file_end_write(file);
	if (ret > 0)
		fsnotify_modify(file);
	return ret;
	return ret;
}
}


ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos,
		int flags)
{
	if (!file->f_op->write_iter)
		return -EINVAL;
	return do_iter_write(file, iter, ppos, flags);
}
EXPORT_SYMBOL(vfs_iter_write);

ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
		  unsigned long vlen, loff_t *pos, int flags)
		  unsigned long vlen, loff_t *pos, int flags)
{
{
	if (!(file->f_mode & FMODE_READ))
	struct iovec iovstack[UIO_FASTIOV];
		return -EBADF;
	struct iovec *iov = iovstack;
	if (!(file->f_mode & FMODE_CAN_READ))
	struct iov_iter iter;
		return -EINVAL;
	ssize_t ret;


	return do_readv_writev(READ, file, vec, vlen, pos, flags);
	ret = import_iovec(READ, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
	if (ret >= 0) {
		ret = do_iter_read(file, &iter, pos, flags);
		kfree(iov);
	}
	}


	return ret;
}
EXPORT_SYMBOL(vfs_readv);
EXPORT_SYMBOL(vfs_readv);


ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
		   unsigned long vlen, loff_t *pos, int flags)
		   unsigned long vlen, loff_t *pos, int flags)
{
{
	if (!(file->f_mode & FMODE_WRITE))
	struct iovec iovstack[UIO_FASTIOV];
		return -EBADF;
	struct iovec *iov = iovstack;
	if (!(file->f_mode & FMODE_CAN_WRITE))
	struct iov_iter iter;
		return -EINVAL;
	ssize_t ret;


	return do_readv_writev(WRITE, file, vec, vlen, pos, flags);
	ret = import_iovec(WRITE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
	if (ret >= 0) {
		ret = do_iter_write(file, &iter, pos, flags);
		kfree(iov);
	}
	return ret;
}
}

EXPORT_SYMBOL(vfs_writev);
EXPORT_SYMBOL(vfs_writev);


static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
@@ -1137,44 +1125,20 @@ SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
}
}


#ifdef CONFIG_COMPAT
#ifdef CONFIG_COMPAT

static size_t compat_readv(struct file *file,
static ssize_t compat_do_readv_writev(int type, struct file *file,
			   const struct compat_iovec __user *vec,
			       const struct compat_iovec __user *uvector,
			   unsigned long vlen, loff_t *pos, int flags)
			       unsigned long nr_segs, loff_t *pos,
			       int flags)
{
{
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec *iov = iovstack;
	struct iovec *iov = iovstack;
	struct iov_iter iter;
	struct iov_iter iter;
	ssize_t ret;
	ssize_t ret;


	ret = compat_import_iovec(type, uvector, nr_segs,
	ret = compat_import_iovec(READ, vec, vlen, UIO_FASTIOV, &iov, &iter);
				  UIO_FASTIOV, &iov, &iter);
	if (ret >= 0) {
	if (ret < 0)
		ret = do_iter_read(file, &iter, pos, flags);
		return ret;

	ret = __do_readv_writev(type, file, &iter, pos, flags);
		kfree(iov);
		kfree(iov);

	return ret;
	}
	}

static size_t compat_readv(struct file *file,
			   const struct compat_iovec __user *vec,
			   unsigned long vlen, loff_t *pos, int flags)
{
	ssize_t ret = -EBADF;

	if (!(file->f_mode & FMODE_READ))
		goto out;

	ret = -EINVAL;
	if (!(file->f_mode & FMODE_CAN_READ))
		goto out;

	ret = compat_do_readv_writev(READ, file, vec, vlen, pos, flags);

out:
	if (ret > 0)
	if (ret > 0)
		add_rchar(current, ret);
		add_rchar(current, ret);
	inc_syscr(current);
	inc_syscr(current);
@@ -1270,18 +1234,16 @@ static size_t compat_writev(struct file *file,
			    const struct compat_iovec __user *vec,
			    const struct compat_iovec __user *vec,
			    unsigned long vlen, loff_t *pos, int flags)
			    unsigned long vlen, loff_t *pos, int flags)
{
{
	ssize_t ret = -EBADF;
	struct iovec iovstack[UIO_FASTIOV];

	struct iovec *iov = iovstack;
	if (!(file->f_mode & FMODE_WRITE))
	struct iov_iter iter;
		goto out;
	ssize_t ret;

	ret = -EINVAL;
	if (!(file->f_mode & FMODE_CAN_WRITE))
		goto out;

	ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos, flags);


out:
	ret = compat_import_iovec(WRITE, vec, vlen, UIO_FASTIOV, &iov, &iter);
	if (ret >= 0) {
		ret = do_iter_write(file, &iter, pos, flags);
		kfree(iov);
	}
	if (ret > 0)
	if (ret > 0)
		add_wchar(current, ret);
		add_wchar(current, ret);
	inc_syscw(current);
	inc_syscw(current);
Loading