Skip to content

Commit 06ae43f

Browse files
author
Al Viro
committed
Don't bother with redoing rw_verify_area() from default_file_splice_from()
default_file_splice_from() ends up calling vfs_write() (via very convoluted callchain). It's an overkill, since we already have done rw_verify_area() in the caller by the time we call vfs_write() we are under set_fs(KERNEL_DS), so access_ok() is also pointless. Add a new helper (__kernel_write()), use it instead of kernel_write() in there. Signed-off-by: Al Viro <[email protected]>
1 parent f6161aa commit 06ae43f

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

fs/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool);
125125
* dcache.c
126126
*/
127127
extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
128+
129+
/*
130+
* read_write.c
131+
*/
132+
extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);

fs/read_write.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/splice.h>
1818
#include <linux/compat.h>
1919
#include "read_write.h"
20+
#include "internal.h"
2021

2122
#include <asm/uaccess.h>
2223
#include <asm/unistd.h>
@@ -417,6 +418,30 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
417418

418419
EXPORT_SYMBOL(do_sync_write);
419420

421+
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
422+
{
423+
mm_segment_t old_fs;
424+
const char __user *p;
425+
ssize_t ret;
426+
427+
old_fs = get_fs();
428+
set_fs(get_ds());
429+
p = (__force const char __user *)buf;
430+
if (count > MAX_RW_COUNT)
431+
count = MAX_RW_COUNT;
432+
if (file->f_op->write)
433+
ret = file->f_op->write(file, p, count, pos);
434+
else
435+
ret = do_sync_write(file, p, count, pos);
436+
set_fs(old_fs);
437+
if (ret > 0) {
438+
fsnotify_modify(file);
439+
add_wchar(current, ret);
440+
}
441+
inc_syscw(current);
442+
return ret;
443+
}
444+
420445
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
421446
{
422447
ssize_t ret;

fs/splice.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/security.h>
3232
#include <linux/gfp.h>
3333
#include <linux/socket.h>
34+
#include "internal.h"
3435

3536
/*
3637
* Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -1048,9 +1049,10 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
10481049
{
10491050
int ret;
10501051
void *data;
1052+
loff_t tmp = sd->pos;
10511053

10521054
data = buf->ops->map(pipe, buf, 0);
1053-
ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
1055+
ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp);
10541056
buf->ops->unmap(pipe, buf, data);
10551057

10561058
return ret;

0 commit comments

Comments
 (0)