aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-04-05 04:27:08 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-06-12 00:18:51 -0400
commit8d0207652cbe27d1f962050737848e5ad4671958 (patch)
tree2cd92ec3cfc66cdfd3cff1b4a46f1b5a4f4b8197
parent62a8067a7f35dba2de501c9cb00e4cf36da90bc0 (diff)
->splice_write() via ->write_iter()
iter_file_splice_write() - a ->splice_write() instance that gathers the pipe buffers, builds a bio_vec-based iov_iter covering those and feeds it to ->write_iter(). A bunch of simple cases coverted to that... [AV: fixed the braino spotted by Cyrill] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/block_dev.c2
-rw-r--r--fs/exofs/file.c2
-rw-r--r--fs/ext2/file.c2
-rw-r--r--fs/ext3/file.c2
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/f2fs/file.c2
-rw-r--r--fs/gfs2/file.c4
-rw-r--r--fs/jfs/file.c2
-rw-r--r--fs/ramfs/file-mmu.c2
-rw-r--r--fs/ramfs/file-nommu.c2
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/splice.c140
-rw-r--r--fs/ubifs/file.c2
-rw-r--r--fs/xfs/xfs_file.c43
-rw-r--r--fs/xfs/xfs_trace.h1
-rw-r--r--include/linux/fs.h2
16 files changed, 156 insertions, 56 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 4e36b8ea8aa4..e68e150b1b16 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1583,7 +1583,7 @@ const struct file_operations def_blk_fops = {
1583 .compat_ioctl = compat_blkdev_ioctl, 1583 .compat_ioctl = compat_blkdev_ioctl,
1584#endif 1584#endif
1585 .splice_read = generic_file_splice_read, 1585 .splice_read = generic_file_splice_read,
1586 .splice_write = generic_file_splice_write, 1586 .splice_write = iter_file_splice_write,
1587}; 1587};
1588 1588
1589int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) 1589int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
diff --git a/fs/exofs/file.c b/fs/exofs/file.c
index 5b7f6be5a2d5..71bf8e4fb5d4 100644
--- a/fs/exofs/file.c
+++ b/fs/exofs/file.c
@@ -77,7 +77,7 @@ const struct file_operations exofs_file_operations = {
77 .fsync = exofs_file_fsync, 77 .fsync = exofs_file_fsync,
78 .flush = exofs_flush, 78 .flush = exofs_flush,
79 .splice_read = generic_file_splice_read, 79 .splice_read = generic_file_splice_read,
80 .splice_write = generic_file_splice_write, 80 .splice_write = iter_file_splice_write,
81}; 81};
82 82
83const struct inode_operations exofs_file_inode_operations = { 83const struct inode_operations exofs_file_inode_operations = {
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 970c6aca15cc..7c87b22a7228 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -75,7 +75,7 @@ const struct file_operations ext2_file_operations = {
75 .release = ext2_release_file, 75 .release = ext2_release_file,
76 .fsync = ext2_fsync, 76 .fsync = ext2_fsync,
77 .splice_read = generic_file_splice_read, 77 .splice_read = generic_file_splice_read,
78 .splice_write = generic_file_splice_write, 78 .splice_write = iter_file_splice_write,
79}; 79};
80 80
81#ifdef CONFIG_EXT2_FS_XIP 81#ifdef CONFIG_EXT2_FS_XIP
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index c833b1226d4d..a062fa1e1b11 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -63,7 +63,7 @@ const struct file_operations ext3_file_operations = {
63 .release = ext3_release_file, 63 .release = ext3_release_file,
64 .fsync = ext3_sync_file, 64 .fsync = ext3_sync_file,
65 .splice_read = generic_file_splice_read, 65 .splice_read = generic_file_splice_read,
66 .splice_write = generic_file_splice_write, 66 .splice_write = iter_file_splice_write,
67}; 67};
68 68
69const struct inode_operations ext3_file_inode_operations = { 69const struct inode_operations ext3_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 48383a5f37a1..708aad768199 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -599,7 +599,7 @@ const struct file_operations ext4_file_operations = {
599 .release = ext4_release_file, 599 .release = ext4_release_file,
600 .fsync = ext4_sync_file, 600 .fsync = ext4_sync_file,
601 .splice_read = generic_file_splice_read, 601 .splice_read = generic_file_splice_read,
602 .splice_write = generic_file_splice_write, 602 .splice_write = iter_file_splice_write,
603 .fallocate = ext4_fallocate, 603 .fallocate = ext4_fallocate,
604}; 604};
605 605
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 22f4900dd8eb..e4ba4b93f96a 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -692,5 +692,5 @@ const struct file_operations f2fs_file_operations = {
692 .compat_ioctl = f2fs_compat_ioctl, 692 .compat_ioctl = f2fs_compat_ioctl,
693#endif 693#endif
694 .splice_read = generic_file_splice_read, 694 .splice_read = generic_file_splice_read,
695 .splice_write = generic_file_splice_write, 695 .splice_write = iter_file_splice_write,
696}; 696};
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index ca932cd358d3..01b4c5b1bff8 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -1068,7 +1068,7 @@ const struct file_operations gfs2_file_fops = {
1068 .lock = gfs2_lock, 1068 .lock = gfs2_lock,
1069 .flock = gfs2_flock, 1069 .flock = gfs2_flock,
1070 .splice_read = generic_file_splice_read, 1070 .splice_read = generic_file_splice_read,
1071 .splice_write = generic_file_splice_write, 1071 .splice_write = iter_file_splice_write,
1072 .setlease = gfs2_setlease, 1072 .setlease = gfs2_setlease,
1073 .fallocate = gfs2_fallocate, 1073 .fallocate = gfs2_fallocate,
1074}; 1074};
@@ -1098,7 +1098,7 @@ const struct file_operations gfs2_file_fops_nolock = {
1098 .release = gfs2_release, 1098 .release = gfs2_release,
1099 .fsync = gfs2_fsync, 1099 .fsync = gfs2_fsync,
1100 .splice_read = generic_file_splice_read, 1100 .splice_read = generic_file_splice_read,
1101 .splice_write = generic_file_splice_write, 1101 .splice_write = iter_file_splice_write,
1102 .setlease = generic_setlease, 1102 .setlease = generic_setlease,
1103 .fallocate = gfs2_fallocate, 1103 .fallocate = gfs2_fallocate,
1104}; 1104};
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index cc744ecaf51f..33aa0cc1f8b8 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -157,7 +157,7 @@ const struct file_operations jfs_file_operations = {
157 .write_iter = generic_file_write_iter, 157 .write_iter = generic_file_write_iter,
158 .mmap = generic_file_mmap, 158 .mmap = generic_file_mmap,
159 .splice_read = generic_file_splice_read, 159 .splice_read = generic_file_splice_read,
160 .splice_write = generic_file_splice_write, 160 .splice_write = iter_file_splice_write,
161 .fsync = jfs_fsync, 161 .fsync = jfs_fsync,
162 .release = jfs_release, 162 .release = jfs_release,
163 .unlocked_ioctl = jfs_ioctl, 163 .unlocked_ioctl = jfs_ioctl,
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 6ea0b9718a9d..4f56de822d2f 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -38,7 +38,7 @@ const struct file_operations ramfs_file_operations = {
38 .mmap = generic_file_mmap, 38 .mmap = generic_file_mmap,
39 .fsync = noop_fsync, 39 .fsync = noop_fsync,
40 .splice_read = generic_file_splice_read, 40 .splice_read = generic_file_splice_read,
41 .splice_write = generic_file_splice_write, 41 .splice_write = iter_file_splice_write,
42 .llseek = generic_file_llseek, 42 .llseek = generic_file_llseek,
43}; 43};
44 44
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 9ed420f8f3ca..dda012ad4208 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -43,7 +43,7 @@ const struct file_operations ramfs_file_operations = {
43 .write_iter = generic_file_write_iter, 43 .write_iter = generic_file_write_iter,
44 .fsync = noop_fsync, 44 .fsync = noop_fsync,
45 .splice_read = generic_file_splice_read, 45 .splice_read = generic_file_splice_read,
46 .splice_write = generic_file_splice_write, 46 .splice_write = iter_file_splice_write,
47 .llseek = generic_file_llseek, 47 .llseek = generic_file_llseek,
48}; 48};
49 49
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 7c8ecd6468db..f070cc827456 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -248,7 +248,7 @@ const struct file_operations reiserfs_file_operations = {
248 .read_iter = generic_file_read_iter, 248 .read_iter = generic_file_read_iter,
249 .write_iter = generic_file_write_iter, 249 .write_iter = generic_file_write_iter,
250 .splice_read = generic_file_splice_read, 250 .splice_read = generic_file_splice_read,
251 .splice_write = generic_file_splice_write, 251 .splice_write = iter_file_splice_write,
252 .llseek = generic_file_llseek, 252 .llseek = generic_file_llseek,
253}; 253};
254 254
diff --git a/fs/splice.c b/fs/splice.c
index f99e420744c7..f195a9b89fb2 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -32,6 +32,7 @@
32#include <linux/gfp.h> 32#include <linux/gfp.h>
33#include <linux/socket.h> 33#include <linux/socket.h>
34#include <linux/compat.h> 34#include <linux/compat.h>
35#include <linux/aio.h>
35#include "internal.h" 36#include "internal.h"
36 37
37/* 38/*
@@ -1052,6 +1053,145 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
1052 1053
1053EXPORT_SYMBOL(generic_file_splice_write); 1054EXPORT_SYMBOL(generic_file_splice_write);
1054 1055
1056/**
1057 * iter_file_splice_write - splice data from a pipe to a file
1058 * @pipe: pipe info
1059 * @out: file to write to
1060 * @ppos: position in @out
1061 * @len: number of bytes to splice
1062 * @flags: splice modifier flags
1063 *
1064 * Description:
1065 * Will either move or copy pages (determined by @flags options) from
1066 * the given pipe inode to the given file.
1067 * This one is ->write_iter-based.
1068 *
1069 */
1070ssize_t
1071iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
1072 loff_t *ppos, size_t len, unsigned int flags)
1073{
1074 struct splice_desc sd = {
1075 .total_len = len,
1076 .flags = flags,
1077 .pos = *ppos,
1078 .u.file = out,
1079 };
1080 int nbufs = pipe->buffers;
1081 struct bio_vec *array = kcalloc(nbufs, sizeof(struct bio_vec),
1082 GFP_KERNEL);
1083 ssize_t ret;
1084
1085 if (unlikely(!array))
1086 return -ENOMEM;
1087
1088 pipe_lock(pipe);
1089
1090 splice_from_pipe_begin(&sd);
1091 while (sd.total_len) {
1092 struct iov_iter from;
1093 struct kiocb kiocb;
1094 size_t left;
1095 int n, idx;
1096
1097 ret = splice_from_pipe_next(pipe, &sd);
1098 if (ret <= 0)
1099 break;
1100
1101 if (unlikely(nbufs < pipe->buffers)) {
1102 kfree(array);
1103 nbufs = pipe->buffers;
1104 array = kcalloc(nbufs, sizeof(struct bio_vec),
1105 GFP_KERNEL);
1106 if (!array) {
1107 ret = -ENOMEM;
1108 break;
1109 }
1110 }
1111
1112 /* build the vector */
1113 left = sd.total_len;
1114 for (n = 0, idx = pipe->curbuf; left && n < pipe->nrbufs; n++, idx++) {
1115 struct pipe_buffer *buf = pipe->bufs + idx;
1116 size_t this_len = buf->len;
1117
1118 if (this_len > left)
1119 this_len = left;
1120
1121 if (idx == pipe->buffers - 1)
1122 idx = -1;
1123
1124 ret = buf->ops->confirm(pipe, buf);
1125 if (unlikely(ret)) {
1126 if (ret == -ENODATA)
1127 ret = 0;
1128 goto done;
1129 }
1130
1131 array[n].bv_page = buf->page;
1132 array[n].bv_len = this_len;
1133 array[n].bv_offset = buf->offset;
1134 left -= this_len;
1135 }
1136
1137 /* ... iov_iter */
1138 from.type = ITER_BVEC | WRITE;
1139 from.bvec = array;
1140 from.nr_segs = n;
1141 from.count = sd.total_len - left;
1142 from.iov_offset = 0;
1143
1144 /* ... and iocb */
1145 init_sync_kiocb(&kiocb, out);
1146 kiocb.ki_pos = sd.pos;
1147 kiocb.ki_nbytes = sd.total_len - left;
1148
1149 /* now, send it */
1150 ret = out->f_op->write_iter(&kiocb, &from);
1151 if (-EIOCBQUEUED == ret)
1152 ret = wait_on_sync_kiocb(&kiocb);
1153
1154 if (ret <= 0)
1155 break;
1156
1157 sd.num_spliced += ret;
1158 sd.total_len -= ret;
1159 *ppos = sd.pos = kiocb.ki_pos;
1160
1161 /* dismiss the fully eaten buffers, adjust the partial one */
1162 while (ret) {
1163 struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
1164 if (ret >= buf->len) {
1165 const struct pipe_buf_operations *ops = buf->ops;
1166 ret -= buf->len;
1167 buf->len = 0;
1168 buf->ops = NULL;
1169 ops->release(pipe, buf);
1170 pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
1171 pipe->nrbufs--;
1172 if (pipe->files)
1173 sd.need_wakeup = true;
1174 } else {
1175 buf->offset += ret;
1176 buf->len -= ret;
1177 ret = 0;
1178 }
1179 }
1180 }
1181done:
1182 kfree(array);
1183 splice_from_pipe_end(pipe, &sd);
1184
1185 pipe_unlock(pipe);
1186
1187 if (sd.num_spliced)
1188 ret = sd.num_spliced;
1189
1190 return ret;
1191}
1192
1193EXPORT_SYMBOL(iter_file_splice_write);
1194
1055static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, 1195static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
1056 struct splice_desc *sd) 1196 struct splice_desc *sd)
1057{ 1197{
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 6bc4e8efbccf..0888502a6041 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1585,7 +1585,7 @@ const struct file_operations ubifs_file_operations = {
1585 .fsync = ubifs_fsync, 1585 .fsync = ubifs_fsync,
1586 .unlocked_ioctl = ubifs_ioctl, 1586 .unlocked_ioctl = ubifs_ioctl,
1587 .splice_read = generic_file_splice_read, 1587 .splice_read = generic_file_splice_read,
1588 .splice_write = generic_file_splice_write, 1588 .splice_write = iter_file_splice_write,
1589#ifdef CONFIG_COMPAT 1589#ifdef CONFIG_COMPAT
1590 .compat_ioctl = ubifs_compat_ioctl, 1590 .compat_ioctl = ubifs_compat_ioctl,
1591#endif 1591#endif
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 5446e86d3485..b1c489c1fb2e 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -343,47 +343,6 @@ xfs_file_splice_read(
343} 343}
344 344
345/* 345/*
346 * xfs_file_splice_write() does not use xfs_rw_ilock() because
347 * generic_file_splice_write() takes the i_mutex itself. This, in theory,
348 * couuld cause lock inversions between the aio_write path and the splice path
349 * if someone is doing concurrent splice(2) based writes and write(2) based
350 * writes to the same inode. The only real way to fix this is to re-implement
351 * the generic code here with correct locking orders.
352 */
353STATIC ssize_t
354xfs_file_splice_write(
355 struct pipe_inode_info *pipe,
356 struct file *outfilp,
357 loff_t *ppos,
358 size_t count,
359 unsigned int flags)
360{
361 struct inode *inode = outfilp->f_mapping->host;
362 struct xfs_inode *ip = XFS_I(inode);
363 int ioflags = 0;
364 ssize_t ret;
365
366 XFS_STATS_INC(xs_write_calls);
367
368 if (outfilp->f_mode & FMODE_NOCMTIME)
369 ioflags |= IO_INVIS;
370
371 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
372 return -EIO;
373
374 xfs_ilock(ip, XFS_IOLOCK_EXCL);
375
376 trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
377
378 ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
379 if (ret > 0)
380 XFS_STATS_ADD(xs_write_bytes, ret);
381
382 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
383 return ret;
384}
385
386/*
387 * This routine is called to handle zeroing any space in the last block of the 346 * This routine is called to handle zeroing any space in the last block of the
388 * file that is beyond the EOF. We do this since the size is being increased 347 * file that is beyond the EOF. We do this since the size is being increased
389 * without writing anything to that block and we don't want to read the 348 * without writing anything to that block and we don't want to read the
@@ -1442,7 +1401,7 @@ const struct file_operations xfs_file_operations = {
1442 .read_iter = xfs_file_read_iter, 1401 .read_iter = xfs_file_read_iter,
1443 .write_iter = xfs_file_write_iter, 1402 .write_iter = xfs_file_write_iter,
1444 .splice_read = xfs_file_splice_read, 1403 .splice_read = xfs_file_splice_read,
1445 .splice_write = xfs_file_splice_write, 1404 .splice_write = iter_file_splice_write,
1446 .unlocked_ioctl = xfs_file_ioctl, 1405 .unlocked_ioctl = xfs_file_ioctl,
1447#ifdef CONFIG_COMPAT 1406#ifdef CONFIG_COMPAT
1448 .compat_ioctl = xfs_file_compat_ioctl, 1407 .compat_ioctl = xfs_file_compat_ioctl,
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 65d8c793a25c..53182f97cf01 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1060,7 +1060,6 @@ DEFINE_RW_EVENT(xfs_file_read);
1060DEFINE_RW_EVENT(xfs_file_buffered_write); 1060DEFINE_RW_EVENT(xfs_file_buffered_write);
1061DEFINE_RW_EVENT(xfs_file_direct_write); 1061DEFINE_RW_EVENT(xfs_file_direct_write);
1062DEFINE_RW_EVENT(xfs_file_splice_read); 1062DEFINE_RW_EVENT(xfs_file_splice_read);
1063DEFINE_RW_EVENT(xfs_file_splice_write);
1064 1063
1065DECLARE_EVENT_CLASS(xfs_page_class, 1064DECLARE_EVENT_CLASS(xfs_page_class,
1066 TP_PROTO(struct inode *inode, struct page *page, unsigned long off, 1065 TP_PROTO(struct inode *inode, struct page *page, unsigned long off,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a6448849dbce..8bd8ed357c7b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2434,6 +2434,8 @@ extern ssize_t default_file_splice_read(struct file *, loff_t *,
2434 struct pipe_inode_info *, size_t, unsigned int); 2434 struct pipe_inode_info *, size_t, unsigned int);
2435extern ssize_t generic_file_splice_write(struct pipe_inode_info *, 2435extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
2436 struct file *, loff_t *, size_t, unsigned int); 2436 struct file *, loff_t *, size_t, unsigned int);
2437extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
2438 struct file *, loff_t *, size_t, unsigned int);
2437extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, 2439extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
2438 struct file *out, loff_t *, size_t len, unsigned int flags); 2440 struct file *out, loff_t *, size_t len, unsigned int flags);
2439 2441