diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-13 13:51:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-13 13:51:07 -0400 |
commit | 12a22960549979c10a95cc97f8ec63b461c55692 (patch) | |
tree | 87b4130e0ae0f2a548087a3934bb7dba37ed6e87 | |
parent | 31c4ab430a448cfb13fc88779d8a870c7af9f72b (diff) | |
parent | 51a92c0f6ce8fa85fa0e18ecda1d847e606e8066 (diff) |
Merge branch 'splice-2.6.23' of git://git.kernel.dk/data/git/linux-2.6-block
* 'splice-2.6.23' of git://git.kernel.dk/data/git/linux-2.6-block:
splice: fix offset mangling with direct splicing (sendfile)
security: revalidate rw permissions for sys_splice and sys_vmsplice
relay: fixup kerneldoc comment
relay: fix bogus cast in subbuf_splice_actor()
-rw-r--r-- | fs/splice.c | 43 | ||||
-rw-r--r-- | kernel/relay.c | 6 |
2 files changed, 24 insertions, 25 deletions
diff --git a/fs/splice.c b/fs/splice.c index ed2ce995475c..6c9828651e6f 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/syscalls.h> | 29 | #include <linux/syscalls.h> |
30 | #include <linux/uio.h> | 30 | #include <linux/uio.h> |
31 | #include <linux/security.h> | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Attempt to steal a page from a pipe buffer. This should perhaps go into | 34 | * Attempt to steal a page from a pipe buffer. This should perhaps go into |
@@ -491,7 +492,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
491 | 492 | ||
492 | ret = 0; | 493 | ret = 0; |
493 | spliced = 0; | 494 | spliced = 0; |
494 | while (len) { | 495 | while (len && !spliced) { |
495 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); | 496 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
496 | 497 | ||
497 | if (ret < 0) | 498 | if (ret < 0) |
@@ -961,6 +962,10 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | |||
961 | if (unlikely(ret < 0)) | 962 | if (unlikely(ret < 0)) |
962 | return ret; | 963 | return ret; |
963 | 964 | ||
965 | ret = security_file_permission(out, MAY_WRITE); | ||
966 | if (unlikely(ret < 0)) | ||
967 | return ret; | ||
968 | |||
964 | return out->f_op->splice_write(pipe, out, ppos, len, flags); | 969 | return out->f_op->splice_write(pipe, out, ppos, len, flags); |
965 | } | 970 | } |
966 | 971 | ||
@@ -983,6 +988,10 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
983 | if (unlikely(ret < 0)) | 988 | if (unlikely(ret < 0)) |
984 | return ret; | 989 | return ret; |
985 | 990 | ||
991 | ret = security_file_permission(in, MAY_READ); | ||
992 | if (unlikely(ret < 0)) | ||
993 | return ret; | ||
994 | |||
986 | return in->f_op->splice_read(in, ppos, pipe, len, flags); | 995 | return in->f_op->splice_read(in, ppos, pipe, len, flags); |
987 | } | 996 | } |
988 | 997 | ||
@@ -1051,15 +1060,10 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
1051 | sd->flags &= ~SPLICE_F_NONBLOCK; | 1060 | sd->flags &= ~SPLICE_F_NONBLOCK; |
1052 | 1061 | ||
1053 | while (len) { | 1062 | while (len) { |
1054 | size_t read_len, max_read_len; | 1063 | size_t read_len; |
1055 | |||
1056 | /* | ||
1057 | * Do at most PIPE_BUFFERS pages worth of transfer: | ||
1058 | */ | ||
1059 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); | ||
1060 | 1064 | ||
1061 | ret = do_splice_to(in, &sd->pos, pipe, max_read_len, flags); | 1065 | ret = do_splice_to(in, &sd->pos, pipe, len, flags); |
1062 | if (unlikely(ret < 0)) | 1066 | if (unlikely(ret <= 0)) |
1063 | goto out_release; | 1067 | goto out_release; |
1064 | 1068 | ||
1065 | read_len = ret; | 1069 | read_len = ret; |
@@ -1071,26 +1075,17 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
1071 | * could get stuck data in the internal pipe: | 1075 | * could get stuck data in the internal pipe: |
1072 | */ | 1076 | */ |
1073 | ret = actor(pipe, sd); | 1077 | ret = actor(pipe, sd); |
1074 | if (unlikely(ret < 0)) | 1078 | if (unlikely(ret <= 0)) |
1075 | goto out_release; | 1079 | goto out_release; |
1076 | 1080 | ||
1077 | bytes += ret; | 1081 | bytes += ret; |
1078 | len -= ret; | 1082 | len -= ret; |
1079 | 1083 | ||
1080 | /* | 1084 | if (ret < read_len) |
1081 | * In nonblocking mode, if we got back a short read then | 1085 | goto out_release; |
1082 | * that was due to either an IO error or due to the | ||
1083 | * pagecache entry not being there. In the IO error case | ||
1084 | * the _next_ splice attempt will produce a clean IO error | ||
1085 | * return value (not a short read), so in both cases it's | ||
1086 | * correct to break out of the loop here: | ||
1087 | */ | ||
1088 | if ((flags & SPLICE_F_NONBLOCK) && (read_len < max_read_len)) | ||
1089 | break; | ||
1090 | } | 1086 | } |
1091 | 1087 | ||
1092 | pipe->nrbufs = pipe->curbuf = 0; | 1088 | pipe->nrbufs = pipe->curbuf = 0; |
1093 | |||
1094 | return bytes; | 1089 | return bytes; |
1095 | 1090 | ||
1096 | out_release: | 1091 | out_release: |
@@ -1152,10 +1147,12 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
1152 | .pos = *ppos, | 1147 | .pos = *ppos, |
1153 | .u.file = out, | 1148 | .u.file = out, |
1154 | }; | 1149 | }; |
1155 | size_t ret; | 1150 | long ret; |
1156 | 1151 | ||
1157 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); | 1152 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); |
1158 | *ppos = sd.pos; | 1153 | if (ret > 0) |
1154 | *ppos += ret; | ||
1155 | |||
1159 | return ret; | 1156 | return ret; |
1160 | } | 1157 | } |
1161 | 1158 | ||
diff --git a/kernel/relay.c b/kernel/relay.c index 3b299fb3855c..a615a8f513fc 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
@@ -1061,7 +1061,7 @@ static struct pipe_buf_operations relay_pipe_buf_ops = { | |||
1061 | .get = generic_pipe_buf_get, | 1061 | .get = generic_pipe_buf_get, |
1062 | }; | 1062 | }; |
1063 | 1063 | ||
1064 | /** | 1064 | /* |
1065 | * subbuf_splice_actor - splice up to one subbuf's worth of data | 1065 | * subbuf_splice_actor - splice up to one subbuf's worth of data |
1066 | */ | 1066 | */ |
1067 | static int subbuf_splice_actor(struct file *in, | 1067 | static int subbuf_splice_actor(struct file *in, |
@@ -1074,7 +1074,9 @@ static int subbuf_splice_actor(struct file *in, | |||
1074 | unsigned int pidx, poff, total_len, subbuf_pages, ret; | 1074 | unsigned int pidx, poff, total_len, subbuf_pages, ret; |
1075 | struct rchan_buf *rbuf = in->private_data; | 1075 | struct rchan_buf *rbuf = in->private_data; |
1076 | unsigned int subbuf_size = rbuf->chan->subbuf_size; | 1076 | unsigned int subbuf_size = rbuf->chan->subbuf_size; |
1077 | size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size; | 1077 | uint64_t pos = (uint64_t) *ppos; |
1078 | uint32_t alloc_size = (uint32_t) rbuf->chan->alloc_size; | ||
1079 | size_t read_start = (size_t) do_div(pos, alloc_size); | ||
1078 | size_t read_subbuf = read_start / subbuf_size; | 1080 | size_t read_subbuf = read_start / subbuf_size; |
1079 | size_t padding = rbuf->padding[read_subbuf]; | 1081 | size_t padding = rbuf->padding[read_subbuf]; |
1080 | size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding; | 1082 | size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding; |