diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/internal.h | 6 | ||||
| -rw-r--r-- | fs/read_write.c | 24 | ||||
| -rw-r--r-- | fs/splice.c | 31 |
3 files changed, 40 insertions, 21 deletions
diff --git a/fs/internal.h b/fs/internal.h index eaa75f75b625..68121584ae37 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -132,6 +132,12 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | |||
| 132 | extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); | 132 | extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); |
| 133 | 133 | ||
| 134 | /* | 134 | /* |
| 135 | * splice.c | ||
| 136 | */ | ||
| 137 | extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | ||
| 138 | loff_t *opos, size_t len, unsigned int flags); | ||
| 139 | |||
| 140 | /* | ||
| 135 | * pipe.c | 141 | * pipe.c |
| 136 | */ | 142 | */ |
| 137 | extern const struct file_operations pipefifo_fops; | 143 | extern const struct file_operations pipefifo_fops; |
diff --git a/fs/read_write.c b/fs/read_write.c index 03430008704e..2cefa417be34 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -1064,6 +1064,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1064 | struct fd in, out; | 1064 | struct fd in, out; |
| 1065 | struct inode *in_inode, *out_inode; | 1065 | struct inode *in_inode, *out_inode; |
| 1066 | loff_t pos; | 1066 | loff_t pos; |
| 1067 | loff_t out_pos; | ||
| 1067 | ssize_t retval; | 1068 | ssize_t retval; |
| 1068 | int fl; | 1069 | int fl; |
| 1069 | 1070 | ||
| @@ -1077,12 +1078,14 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1077 | if (!(in.file->f_mode & FMODE_READ)) | 1078 | if (!(in.file->f_mode & FMODE_READ)) |
| 1078 | goto fput_in; | 1079 | goto fput_in; |
| 1079 | retval = -ESPIPE; | 1080 | retval = -ESPIPE; |
| 1080 | if (!ppos) | 1081 | if (!ppos) { |
| 1081 | ppos = &in.file->f_pos; | 1082 | pos = in.file->f_pos; |
| 1082 | else | 1083 | } else { |
| 1084 | pos = *ppos; | ||
| 1083 | if (!(in.file->f_mode & FMODE_PREAD)) | 1085 | if (!(in.file->f_mode & FMODE_PREAD)) |
| 1084 | goto fput_in; | 1086 | goto fput_in; |
| 1085 | retval = rw_verify_area(READ, in.file, ppos, count); | 1087 | } |
| 1088 | retval = rw_verify_area(READ, in.file, &pos, count); | ||
| 1086 | if (retval < 0) | 1089 | if (retval < 0) |
| 1087 | goto fput_in; | 1090 | goto fput_in; |
| 1088 | count = retval; | 1091 | count = retval; |
| @@ -1099,7 +1102,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1099 | retval = -EINVAL; | 1102 | retval = -EINVAL; |
| 1100 | in_inode = file_inode(in.file); | 1103 | in_inode = file_inode(in.file); |
| 1101 | out_inode = file_inode(out.file); | 1104 | out_inode = file_inode(out.file); |
| 1102 | retval = rw_verify_area(WRITE, out.file, &out.file->f_pos, count); | 1105 | out_pos = out.file->f_pos; |
| 1106 | retval = rw_verify_area(WRITE, out.file, &out_pos, count); | ||
| 1103 | if (retval < 0) | 1107 | if (retval < 0) |
| 1104 | goto fput_out; | 1108 | goto fput_out; |
| 1105 | count = retval; | 1109 | count = retval; |
| @@ -1107,7 +1111,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1107 | if (!max) | 1111 | if (!max) |
| 1108 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); | 1112 | max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); |
| 1109 | 1113 | ||
| 1110 | pos = *ppos; | ||
| 1111 | if (unlikely(pos + count > max)) { | 1114 | if (unlikely(pos + count > max)) { |
| 1112 | retval = -EOVERFLOW; | 1115 | retval = -EOVERFLOW; |
| 1113 | if (pos >= max) | 1116 | if (pos >= max) |
| @@ -1126,18 +1129,23 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, | |||
| 1126 | if (in.file->f_flags & O_NONBLOCK) | 1129 | if (in.file->f_flags & O_NONBLOCK) |
| 1127 | fl = SPLICE_F_NONBLOCK; | 1130 | fl = SPLICE_F_NONBLOCK; |
| 1128 | #endif | 1131 | #endif |
| 1129 | retval = do_splice_direct(in.file, ppos, out.file, count, fl); | 1132 | retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); |
| 1130 | 1133 | ||
| 1131 | if (retval > 0) { | 1134 | if (retval > 0) { |
| 1132 | add_rchar(current, retval); | 1135 | add_rchar(current, retval); |
| 1133 | add_wchar(current, retval); | 1136 | add_wchar(current, retval); |
| 1134 | fsnotify_access(in.file); | 1137 | fsnotify_access(in.file); |
| 1135 | fsnotify_modify(out.file); | 1138 | fsnotify_modify(out.file); |
| 1139 | out.file->f_pos = out_pos; | ||
| 1140 | if (ppos) | ||
| 1141 | *ppos = pos; | ||
| 1142 | else | ||
| 1143 | in.file->f_pos = pos; | ||
| 1136 | } | 1144 | } |
| 1137 | 1145 | ||
| 1138 | inc_syscr(current); | 1146 | inc_syscr(current); |
| 1139 | inc_syscw(current); | 1147 | inc_syscw(current); |
| 1140 | if (*ppos > max) | 1148 | if (pos > max) |
| 1141 | retval = -EOVERFLOW; | 1149 | retval = -EOVERFLOW; |
| 1142 | 1150 | ||
| 1143 | fput_out: | 1151 | fput_out: |
diff --git a/fs/splice.c b/fs/splice.c index e6b25598c8c4..9eca476227d5 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -1274,7 +1274,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, | |||
| 1274 | { | 1274 | { |
| 1275 | struct file *file = sd->u.file; | 1275 | struct file *file = sd->u.file; |
| 1276 | 1276 | ||
| 1277 | return do_splice_from(pipe, file, &file->f_pos, sd->total_len, | 1277 | return do_splice_from(pipe, file, sd->opos, sd->total_len, |
| 1278 | sd->flags); | 1278 | sd->flags); |
| 1279 | } | 1279 | } |
| 1280 | 1280 | ||
| @@ -1294,7 +1294,7 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, | |||
| 1294 | * | 1294 | * |
| 1295 | */ | 1295 | */ |
| 1296 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | 1296 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, |
| 1297 | size_t len, unsigned int flags) | 1297 | loff_t *opos, size_t len, unsigned int flags) |
| 1298 | { | 1298 | { |
| 1299 | struct splice_desc sd = { | 1299 | struct splice_desc sd = { |
| 1300 | .len = len, | 1300 | .len = len, |
| @@ -1302,6 +1302,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
| 1302 | .flags = flags, | 1302 | .flags = flags, |
| 1303 | .pos = *ppos, | 1303 | .pos = *ppos, |
| 1304 | .u.file = out, | 1304 | .u.file = out, |
| 1305 | .opos = opos, | ||
| 1305 | }; | 1306 | }; |
| 1306 | long ret; | 1307 | long ret; |
| 1307 | 1308 | ||
| @@ -1325,7 +1326,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1325 | { | 1326 | { |
| 1326 | struct pipe_inode_info *ipipe; | 1327 | struct pipe_inode_info *ipipe; |
| 1327 | struct pipe_inode_info *opipe; | 1328 | struct pipe_inode_info *opipe; |
| 1328 | loff_t offset, *off; | 1329 | loff_t offset; |
| 1329 | long ret; | 1330 | long ret; |
| 1330 | 1331 | ||
| 1331 | ipipe = get_pipe_info(in); | 1332 | ipipe = get_pipe_info(in); |
| @@ -1356,13 +1357,15 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1356 | return -EINVAL; | 1357 | return -EINVAL; |
| 1357 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) | 1358 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) |
| 1358 | return -EFAULT; | 1359 | return -EFAULT; |
| 1359 | off = &offset; | 1360 | } else { |
| 1360 | } else | 1361 | offset = out->f_pos; |
| 1361 | off = &out->f_pos; | 1362 | } |
| 1362 | 1363 | ||
| 1363 | ret = do_splice_from(ipipe, out, off, len, flags); | 1364 | ret = do_splice_from(ipipe, out, &offset, len, flags); |
| 1364 | 1365 | ||
| 1365 | if (off_out && copy_to_user(off_out, off, sizeof(loff_t))) | 1366 | if (!off_out) |
| 1367 | out->f_pos = offset; | ||
| 1368 | else if (copy_to_user(off_out, &offset, sizeof(loff_t))) | ||
| 1366 | ret = -EFAULT; | 1369 | ret = -EFAULT; |
| 1367 | 1370 | ||
| 1368 | return ret; | 1371 | return ret; |
| @@ -1376,13 +1379,15 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1376 | return -EINVAL; | 1379 | return -EINVAL; |
| 1377 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) | 1380 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) |
| 1378 | return -EFAULT; | 1381 | return -EFAULT; |
| 1379 | off = &offset; | 1382 | } else { |
| 1380 | } else | 1383 | offset = in->f_pos; |
| 1381 | off = &in->f_pos; | 1384 | } |
| 1382 | 1385 | ||
| 1383 | ret = do_splice_to(in, off, opipe, len, flags); | 1386 | ret = do_splice_to(in, &offset, opipe, len, flags); |
| 1384 | 1387 | ||
| 1385 | if (off_in && copy_to_user(off_in, off, sizeof(loff_t))) | 1388 | if (!off_in) |
| 1389 | in->f_pos = offset; | ||
| 1390 | else if (copy_to_user(off_in, &offset, sizeof(loff_t))) | ||
| 1386 | ret = -EFAULT; | 1391 | ret = -EFAULT; |
| 1387 | 1392 | ||
| 1388 | return ret; | 1393 | return ret; |
