file->f_flags & O_APPEND is checked twice -> do_splice_direct or do_splice: return EINVAL if O_APPEND enabled -> generic_write_checks: seek to end in case of O_APPEND This is obviously whong and result in unpredictable behaviour if raced with fcntl. It is reasonable to recheck append flag after kiocb was constructed (where ->ki_flags is stable), for that reason we should use special analog of vfs_write_iter() which asserts non-append behaviour. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- fs/splice.c | 23 ++++++++++++++++++++++- 1 files changed, 22 insertions(+), 1 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 41cbb16..d49615d 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -922,6 +922,27 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, return ret; } +ssize_t splice_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); + if (kiocb.ki_flags & IOCB_APPEND) + return -EINVAL; + + kiocb.ki_pos = *ppos; + iter->type |= WRITE; + ret = file->f_op->write_iter(&kiocb, iter); + BUG_ON(ret == -EIOCBQUEUED); + if (ret > 0) + *ppos = kiocb.ki_pos; + return ret; +} + /** * iter_file_splice_write - splice data from a pipe to a file @@ -1005,7 +1026,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n, sd.total_len - left); - ret = vfs_iter_write(out, &from, &sd.pos); + ret = splice_iter_write(out, &from, &sd.pos); if (ret <= 0) break; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html