summaryrefslogtreecommitdiff
path: root/fs/read_write.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 14:35:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-05 14:35:57 -0700
commit89fbf5384ddf666a595eb6562dc63fcbfeb8f6a5 (patch)
treefc2de270b1dae61f850e9aff0784a672667e2acc /fs/read_write.c
parent4be95131bf3bca97b6a7db9c6fb63db2cb94da06 (diff)
parenta4058c5bce8aded1a12a59990e84e481a96fb490 (diff)
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
Diffstat (limited to 'fs/read_write.c')
-rw-r--r--fs/read_write.c220
1 files changed, 91 insertions, 129 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index d591eeed061f..a2cbc8303dae 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -356,46 +356,6 @@ out_putf:
}
#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)
{
struct inode *inode;
@@ -910,86 +870,114 @@ out:
}
#endif
-static ssize_t __do_readv_writev(int type, struct file *file,
- struct iov_iter *iter, loff_t *pos, int flags)
+static ssize_t do_iter_read(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_READ))
+ return -EBADF;
+ if (!(file->f_mode & FMODE_CAN_READ))
+ return -EINVAL;
+
tot_len = iov_iter_count(iter);
if (!tot_len)
goto out;
- ret = rw_verify_area(type, file, pos, tot_len);
+ ret = rw_verify_area(READ, file, pos, tot_len);
if (ret < 0)
- goto out;
-
- if (type != READ)
- file_start_write(file);
+ return ret;
- if ((type == READ && file->f_op->read_iter) ||
- (type == WRITE && file->f_op->write_iter))
- ret = do_iter_readv_writev(file, iter, pos, type, flags);
+ if (file->f_op->read_iter)
+ ret = do_iter_readv_writev(file, iter, pos, READ, flags);
else
- ret = do_loop_readv_writev(file, iter, pos, type, flags);
-
- if (type != READ)
- file_end_write(file);
-
+ ret = do_loop_readv_writev(file, iter, pos, READ, flags);
out:
- if ((ret + (type == READ)) > 0) {
- if (type == READ)
- fsnotify_access(file);
- else
- fsnotify_modify(file);
- }
+ if (ret >= 0)
+ fsnotify_access(file);
return ret;
}
-static ssize_t do_readv_writev(int type, struct file *file,
- const struct iovec __user *uvector,
- unsigned long nr_segs, loff_t *pos,
- int flags)
+ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos,
+ int flags)
{
- struct iovec iovstack[UIO_FASTIOV];
- struct iovec *iov = iovstack;
- struct iov_iter iter;
- ssize_t ret;
+ if (!file->f_op->read_iter)
+ return -EINVAL;
+ return do_iter_read(file, iter, ppos, flags);
+}
+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,
- ARRAY_SIZE(iovstack), &iov, &iter);
+ tot_len = iov_iter_count(iter);
+ if (!tot_len)
+ return 0;
+ ret = rw_verify_area(WRITE, file, pos, tot_len);
if (ret < 0)
return ret;
- ret = __do_readv_writev(type, file, &iter, pos, flags);
- kfree(iov);
-
+ file_start_write(file);
+ 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;
}
+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,
unsigned long vlen, loff_t *pos, int flags)
{
- if (!(file->f_mode & FMODE_READ))
- return -EBADF;
- if (!(file->f_mode & FMODE_CAN_READ))
- return -EINVAL;
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov = iovstack;
+ struct iov_iter iter;
+ 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);
ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
unsigned long vlen, loff_t *pos, int flags)
{
- if (!(file->f_mode & FMODE_WRITE))
- return -EBADF;
- if (!(file->f_mode & FMODE_CAN_WRITE))
- return -EINVAL;
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov = iovstack;
+ struct iov_iter iter;
+ 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);
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
-
-static ssize_t compat_do_readv_writev(int type, struct file *file,
- const struct compat_iovec __user *uvector,
- unsigned long nr_segs, loff_t *pos,
- int flags)
+static size_t compat_readv(struct file *file,
+ const struct compat_iovec __user *vec,
+ unsigned long vlen, loff_t *pos, int flags)
{
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
struct iov_iter iter;
ssize_t ret;
- ret = compat_import_iovec(type, uvector, nr_segs,
- UIO_FASTIOV, &iov, &iter);
- if (ret < 0)
- return ret;
-
- ret = __do_readv_writev(type, file, &iter, pos, flags);
- 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:
+ ret = compat_import_iovec(READ, vec, vlen, UIO_FASTIOV, &iov, &iter);
+ if (ret >= 0) {
+ ret = do_iter_read(file, &iter, pos, flags);
+ kfree(iov);
+ }
if (ret > 0)
add_rchar(current, ret);
inc_syscr(current);
@@ -1270,18 +1234,16 @@ static size_t compat_writev(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_WRITE))
- goto out;
-
- ret = -EINVAL;
- if (!(file->f_mode & FMODE_CAN_WRITE))
- goto out;
-
- ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos, flags);
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov = iovstack;
+ struct iov_iter iter;
+ ssize_t ret;
-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)
add_wchar(current, ret);
inc_syscw(current);