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

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
...@@ -273,7 +273,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -273,9 +273,9 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, ...@@ -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) ...@@ -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) {
......
...@@ -34,7 +34,7 @@ coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -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) ...@@ -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);
......
...@@ -911,24 +911,13 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)
......
...@@ -356,46 +356,6 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, ...@@ -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, ...@@ -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);
ret = import_iovec(type, uvector, nr_segs, static ssize_t do_iter_write(struct file *file, struct iov_iter *iter,
ARRAY_SIZE(iovstack), &iov, &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;
tot_len = iov_iter_count(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, ...@@ -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, ...@@ -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);
......
...@@ -762,7 +762,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, ...@@ -762,7 +762,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n, iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n,
sd.total_len - left); sd.total_len - left);
ret = vfs_iter_write(out, &from, &sd.pos); ret = vfs_iter_write(out, &from, &sd.pos, 0);
if (ret <= 0) if (ret <= 0)
break; break;
......
...@@ -2819,8 +2819,10 @@ extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); ...@@ -2819,8 +2819,10 @@ extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *); extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *);
extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t); extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t);
ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos); ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos,
ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos); int flags);
ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos,
int flags);
/* fs/block_dev.c */ /* fs/block_dev.c */
extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to); extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment