diff options
| author | Jens Axboe <jens.axboe@oracle.com> | 2006-11-04 06:49:32 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-11-04 11:45:39 -0500 |
| commit | ddac0d39cf437d02fde9795ae57d9c4b4c146de9 (patch) | |
| tree | 36766a2ff9e4872f06d9c4e4b269758647aa3cf6 | |
| parent | aaa9b971398f62ab97c1da4f7c352667eb3452c9 (diff) | |
[PATCH] splice: fix problem introduced with inode diet
After the inode slimming patch that unionised i_pipe/i_bdev/i_cdev, it's
no longer enough to check for existance of ->i_pipe to verify that this
is a pipe.
Original patch from Eric Dumazet <dada1@cosmosbay.com>
Final solution suggested by Linus.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | fs/splice.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/fs/splice.c b/fs/splice.c index 8d705954d294..da74583a00ee 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -1109,6 +1109,19 @@ out_release: | |||
| 1109 | EXPORT_SYMBOL(do_splice_direct); | 1109 | EXPORT_SYMBOL(do_splice_direct); |
| 1110 | 1110 | ||
| 1111 | /* | 1111 | /* |
| 1112 | * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same | ||
| 1113 | * location, so checking ->i_pipe is not enough to verify that this is a | ||
| 1114 | * pipe. | ||
| 1115 | */ | ||
| 1116 | static inline struct pipe_inode_info *pipe_info(struct inode *inode) | ||
| 1117 | { | ||
| 1118 | if (S_ISFIFO(inode->i_mode)) | ||
| 1119 | return inode->i_pipe; | ||
| 1120 | |||
| 1121 | return NULL; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | /* | ||
| 1112 | * Determine where to splice to/from. | 1125 | * Determine where to splice to/from. |
| 1113 | */ | 1126 | */ |
| 1114 | static long do_splice(struct file *in, loff_t __user *off_in, | 1127 | static long do_splice(struct file *in, loff_t __user *off_in, |
| @@ -1119,7 +1132,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1119 | loff_t offset, *off; | 1132 | loff_t offset, *off; |
| 1120 | long ret; | 1133 | long ret; |
| 1121 | 1134 | ||
| 1122 | pipe = in->f_dentry->d_inode->i_pipe; | 1135 | pipe = pipe_info(in->f_dentry->d_inode); |
| 1123 | if (pipe) { | 1136 | if (pipe) { |
| 1124 | if (off_in) | 1137 | if (off_in) |
| 1125 | return -ESPIPE; | 1138 | return -ESPIPE; |
| @@ -1140,7 +1153,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1140 | return ret; | 1153 | return ret; |
| 1141 | } | 1154 | } |
| 1142 | 1155 | ||
| 1143 | pipe = out->f_dentry->d_inode->i_pipe; | 1156 | pipe = pipe_info(out->f_dentry->d_inode); |
| 1144 | if (pipe) { | 1157 | if (pipe) { |
| 1145 | if (off_out) | 1158 | if (off_out) |
| 1146 | return -ESPIPE; | 1159 | return -ESPIPE; |
| @@ -1298,7 +1311,7 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
| 1298 | static long do_vmsplice(struct file *file, const struct iovec __user *iov, | 1311 | static long do_vmsplice(struct file *file, const struct iovec __user *iov, |
| 1299 | unsigned long nr_segs, unsigned int flags) | 1312 | unsigned long nr_segs, unsigned int flags) |
| 1300 | { | 1313 | { |
| 1301 | struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe; | 1314 | struct pipe_inode_info *pipe; |
| 1302 | struct page *pages[PIPE_BUFFERS]; | 1315 | struct page *pages[PIPE_BUFFERS]; |
| 1303 | struct partial_page partial[PIPE_BUFFERS]; | 1316 | struct partial_page partial[PIPE_BUFFERS]; |
| 1304 | struct splice_pipe_desc spd = { | 1317 | struct splice_pipe_desc spd = { |
| @@ -1308,7 +1321,8 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov, | |||
| 1308 | .ops = &user_page_pipe_buf_ops, | 1321 | .ops = &user_page_pipe_buf_ops, |
| 1309 | }; | 1322 | }; |
| 1310 | 1323 | ||
| 1311 | if (unlikely(!pipe)) | 1324 | pipe = pipe_info(file->f_dentry->d_inode); |
| 1325 | if (!pipe) | ||
| 1312 | return -EBADF; | 1326 | return -EBADF; |
| 1313 | if (unlikely(nr_segs > UIO_MAXIOV)) | 1327 | if (unlikely(nr_segs > UIO_MAXIOV)) |
| 1314 | return -EINVAL; | 1328 | return -EINVAL; |
| @@ -1535,8 +1549,8 @@ static int link_pipe(struct pipe_inode_info *ipipe, | |||
| 1535 | static long do_tee(struct file *in, struct file *out, size_t len, | 1549 | static long do_tee(struct file *in, struct file *out, size_t len, |
| 1536 | unsigned int flags) | 1550 | unsigned int flags) |
| 1537 | { | 1551 | { |
| 1538 | struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; | 1552 | struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode); |
| 1539 | struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; | 1553 | struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode); |
| 1540 | int ret = -EINVAL; | 1554 | int ret = -EINVAL; |
| 1541 | 1555 | ||
| 1542 | /* | 1556 | /* |
