Skip to content

Commit

Permalink
splice: don't pass the address of ->f_pos to methods
Browse files Browse the repository at this point in the history
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed Jun 20, 2013
1 parent c9036e9 commit 7995bd2
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 23 deletions.
6 changes: 6 additions & 0 deletions fs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
*/
extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);

/*
* splice.c
*/
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
loff_t *opos, size_t len, unsigned int flags);

/*
* pipe.c
*/
Expand Down
24 changes: 16 additions & 8 deletions fs/read_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
struct fd in, out;
struct inode *in_inode, *out_inode;
loff_t pos;
loff_t out_pos;
ssize_t retval;
int fl;

Expand All @@ -1077,12 +1078,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
if (!(in.file->f_mode & FMODE_READ))
goto fput_in;
retval = -ESPIPE;
if (!ppos)
ppos = &in.file->f_pos;
else
if (!ppos) {
pos = in.file->f_pos;
} else {
pos = *ppos;
if (!(in.file->f_mode & FMODE_PREAD))
goto fput_in;
retval = rw_verify_area(READ, in.file, ppos, count);
}
retval = rw_verify_area(READ, in.file, &pos, count);
if (retval < 0)
goto fput_in;
count = retval;
Expand All @@ -1099,15 +1102,15 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
retval = -EINVAL;
in_inode = file_inode(in.file);
out_inode = file_inode(out.file);
retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count);
out_pos = out.file->f_pos;
retval = rw_verify_area(WRITE, out.file, &out_pos, count);
if (retval < 0)
goto fput_out;
count = retval;

if (!max)
max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);

pos = *ppos;
if (unlikely(pos + count > max)) {
retval = -EOVERFLOW;
if (pos >= max)
Expand All @@ -1126,18 +1129,23 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
if (in.file->f_flags & O_NONBLOCK)
fl = SPLICE_F_NONBLOCK;
#endif
retval = do_splice_direct(in.file, ppos, out.file, count, fl);
retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);

if (retval > 0) {
add_rchar(current, retval);
add_wchar(current, retval);
fsnotify_access(in.file);
fsnotify_modify(out.file);
out.file->f_pos = out_pos;
if (ppos)
*ppos = pos;
else
in.file->f_pos = pos;
}

inc_syscr(current);
inc_syscw(current);
if (*ppos > max)
if (pos > max)
retval = -EOVERFLOW;

fput_out:
Expand Down
31 changes: 18 additions & 13 deletions fs/splice.c
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
{
struct file *file = sd->u.file;

return do_splice_from(pipe, file, &file->f_pos, sd->total_len,
return do_splice_from(pipe, file, sd->opos, sd->total_len,
sd->flags);
}

Expand All @@ -1294,14 +1294,15 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
*
*/
long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
size_t len, unsigned int flags)
loff_t *opos, size_t len, unsigned int flags)
{
struct splice_desc sd = {
.len = len,
.total_len = len,
.flags = flags,
.pos = *ppos,
.u.file = out,
.opos = opos,
};
long ret;

Expand All @@ -1325,7 +1326,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset, *off;
loff_t offset;
long ret;

ipipe = get_pipe_info(in);
Expand Down Expand Up @@ -1356,13 +1357,15 @@ static long do_splice(struct file *in, loff_t __user *off_in,
return -EINVAL;
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
return -EFAULT;
off = &offset;
} else
off = &out->f_pos;
} else {
offset = out->f_pos;
}

ret = do_splice_from(ipipe, out, off, len, flags);
ret = do_splice_from(ipipe, out, &offset, len, flags);

if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
if (!off_out)
out->f_pos = offset;
else if (copy_to_user(off_out, &offset, sizeof(loff_t)))
ret = -EFAULT;

return ret;
Expand All @@ -1376,13 +1379,15 @@ static long do_splice(struct file *in, loff_t __user *off_in,
return -EINVAL;
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
return -EFAULT;
off = &offset;
} else
off = &in->f_pos;
} else {
offset = in->f_pos;
}

ret = do_splice_to(in, off, opipe, len, flags);
ret = do_splice_to(in, &offset, opipe, len, flags);

if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
if (!off_in)
in->f_pos = offset;
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
ret = -EFAULT;

return ret;
Expand Down
2 changes: 0 additions & 2 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2414,8 +2414,6 @@ extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
struct file *, loff_t *, size_t, unsigned int);
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
struct file *out, loff_t *, size_t len, unsigned int flags);
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
size_t len, unsigned int flags);

extern void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
Expand Down
1 change: 1 addition & 0 deletions include/linux/splice.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct splice_desc {
void *data; /* cookie */
} u;
loff_t pos; /* file position */
loff_t *opos; /* sendfile: output position */
size_t num_spliced; /* number of bytes already spliced */
bool need_wakeup; /* need to wake up writer */
};
Expand Down

0 comments on commit 7995bd2

Please sign in to comment.