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 /fs/splice.c | |
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>
Diffstat (limited to 'fs/splice.c')
-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 | /* |