diff options
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch')
-rw-r--r-- | recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch new file mode 100644 index 00000000..6441cc29 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch | |||
@@ -0,0 +1,298 @@ | |||
1 | From e02d361ade75d22d28ce36460954b4bc6439fc74 Mon Sep 17 00:00:00 2001 | ||
2 | From: Eric Dumazet <edumazet@google.com> | ||
3 | Date: Tue, 12 Jun 2012 15:24:40 +0200 | ||
4 | Subject: [PATCH 01/49] splice: fix racy pipe->buffers uses | ||
5 | |||
6 | commit 047fe3605235888f3ebcda0c728cb31937eadfe6 upstream. | ||
7 | |||
8 | Dave Jones reported a kernel BUG at mm/slub.c:3474! triggered | ||
9 | by splice_shrink_spd() called from vmsplice_to_pipe() | ||
10 | |||
11 | commit 35f3d14dbbc5 (pipe: add support for shrinking and growing pipes) | ||
12 | added capability to adjust pipe->buffers. | ||
13 | |||
14 | Problem is some paths don't hold pipe mutex and assume pipe->buffers | ||
15 | doesn't change for their duration. | ||
16 | |||
17 | Fix this by adding nr_pages_max field in struct splice_pipe_desc, and | ||
18 | use it in place of pipe->buffers where appropriate. | ||
19 | |||
20 | splice_shrink_spd() loses its struct pipe_inode_info argument. | ||
21 | |||
22 | Reported-by: Dave Jones <davej@redhat.com> | ||
23 | Signed-off-by: Eric Dumazet <edumazet@google.com> | ||
24 | Cc: Jens Axboe <axboe@kernel.dk> | ||
25 | Cc: Alexander Viro <viro@zeniv.linux.org.uk> | ||
26 | Cc: Tom Herbert <therbert@google.com> | ||
27 | Tested-by: Dave Jones <davej@redhat.com> | ||
28 | Signed-off-by: Jens Axboe <axboe@kernel.dk> | ||
29 | [bwh: Backported to 3.2: | ||
30 | - Adjust context in vmsplice_to_pipe() | ||
31 | - Update one more call to splice_shrink_spd(), from skb_splice_bits()] | ||
32 | Signed-off-by: Ben Hutchings <ben@decadent.org.uk> | ||
33 | --- | ||
34 | fs/splice.c | 35 ++++++++++++++++++++--------------- | ||
35 | include/linux/splice.h | 8 ++++---- | ||
36 | kernel/relay.c | 5 +++-- | ||
37 | kernel/trace/trace.c | 6 ++++-- | ||
38 | mm/shmem.c | 3 ++- | ||
39 | net/core/skbuff.c | 3 ++- | ||
40 | 6 files changed, 35 insertions(+), 25 deletions(-) | ||
41 | |||
42 | diff --git a/fs/splice.c b/fs/splice.c | ||
43 | index 6d0dfb8..014fcb4 100644 | ||
44 | --- a/fs/splice.c | ||
45 | +++ b/fs/splice.c | ||
46 | @@ -274,13 +274,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) | ||
47 | * Check if we need to grow the arrays holding pages and partial page | ||
48 | * descriptions. | ||
49 | */ | ||
50 | -int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) | ||
51 | +int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) | ||
52 | { | ||
53 | - if (pipe->buffers <= PIPE_DEF_BUFFERS) | ||
54 | + unsigned int buffers = ACCESS_ONCE(pipe->buffers); | ||
55 | + | ||
56 | + spd->nr_pages_max = buffers; | ||
57 | + if (buffers <= PIPE_DEF_BUFFERS) | ||
58 | return 0; | ||
59 | |||
60 | - spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL); | ||
61 | - spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL); | ||
62 | + spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL); | ||
63 | + spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL); | ||
64 | |||
65 | if (spd->pages && spd->partial) | ||
66 | return 0; | ||
67 | @@ -290,10 +293,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) | ||
68 | return -ENOMEM; | ||
69 | } | ||
70 | |||
71 | -void splice_shrink_spd(struct pipe_inode_info *pipe, | ||
72 | - struct splice_pipe_desc *spd) | ||
73 | +void splice_shrink_spd(struct splice_pipe_desc *spd) | ||
74 | { | ||
75 | - if (pipe->buffers <= PIPE_DEF_BUFFERS) | ||
76 | + if (spd->nr_pages_max <= PIPE_DEF_BUFFERS) | ||
77 | return; | ||
78 | |||
79 | kfree(spd->pages); | ||
80 | @@ -316,6 +318,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | ||
81 | struct splice_pipe_desc spd = { | ||
82 | .pages = pages, | ||
83 | .partial = partial, | ||
84 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
85 | .flags = flags, | ||
86 | .ops = &page_cache_pipe_buf_ops, | ||
87 | .spd_release = spd_release_page, | ||
88 | @@ -327,7 +330,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | ||
89 | index = *ppos >> PAGE_CACHE_SHIFT; | ||
90 | loff = *ppos & ~PAGE_CACHE_MASK; | ||
91 | req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
92 | - nr_pages = min(req_pages, pipe->buffers); | ||
93 | + nr_pages = min(req_pages, spd.nr_pages_max); | ||
94 | |||
95 | /* | ||
96 | * Lookup the (hopefully) full range of pages we need. | ||
97 | @@ -498,7 +501,7 @@ fill_it: | ||
98 | if (spd.nr_pages) | ||
99 | error = splice_to_pipe(pipe, &spd); | ||
100 | |||
101 | - splice_shrink_spd(pipe, &spd); | ||
102 | + splice_shrink_spd(&spd); | ||
103 | return error; | ||
104 | } | ||
105 | |||
106 | @@ -599,6 +602,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | ||
107 | struct splice_pipe_desc spd = { | ||
108 | .pages = pages, | ||
109 | .partial = partial, | ||
110 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
111 | .flags = flags, | ||
112 | .ops = &default_pipe_buf_ops, | ||
113 | .spd_release = spd_release_page, | ||
114 | @@ -609,8 +613,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | ||
115 | |||
116 | res = -ENOMEM; | ||
117 | vec = __vec; | ||
118 | - if (pipe->buffers > PIPE_DEF_BUFFERS) { | ||
119 | - vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL); | ||
120 | + if (spd.nr_pages_max > PIPE_DEF_BUFFERS) { | ||
121 | + vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL); | ||
122 | if (!vec) | ||
123 | goto shrink_ret; | ||
124 | } | ||
125 | @@ -618,7 +622,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | ||
126 | offset = *ppos & ~PAGE_CACHE_MASK; | ||
127 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
128 | |||
129 | - for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) { | ||
130 | + for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) { | ||
131 | struct page *page; | ||
132 | |||
133 | page = alloc_page(GFP_USER); | ||
134 | @@ -666,7 +670,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | ||
135 | shrink_ret: | ||
136 | if (vec != __vec) | ||
137 | kfree(vec); | ||
138 | - splice_shrink_spd(pipe, &spd); | ||
139 | + splice_shrink_spd(&spd); | ||
140 | return res; | ||
141 | |||
142 | err: | ||
143 | @@ -1616,6 +1620,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, | ||
144 | struct splice_pipe_desc spd = { | ||
145 | .pages = pages, | ||
146 | .partial = partial, | ||
147 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
148 | .flags = flags, | ||
149 | .ops = &user_page_pipe_buf_ops, | ||
150 | .spd_release = spd_release_page, | ||
151 | @@ -1631,13 +1636,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov, | ||
152 | |||
153 | spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages, | ||
154 | spd.partial, flags & SPLICE_F_GIFT, | ||
155 | - pipe->buffers); | ||
156 | + spd.nr_pages_max); | ||
157 | if (spd.nr_pages <= 0) | ||
158 | ret = spd.nr_pages; | ||
159 | else | ||
160 | ret = splice_to_pipe(pipe, &spd); | ||
161 | |||
162 | - splice_shrink_spd(pipe, &spd); | ||
163 | + splice_shrink_spd(&spd); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | diff --git a/include/linux/splice.h b/include/linux/splice.h | ||
168 | index 26e5b61..09a545a 100644 | ||
169 | --- a/include/linux/splice.h | ||
170 | +++ b/include/linux/splice.h | ||
171 | @@ -51,7 +51,8 @@ struct partial_page { | ||
172 | struct splice_pipe_desc { | ||
173 | struct page **pages; /* page map */ | ||
174 | struct partial_page *partial; /* pages[] may not be contig */ | ||
175 | - int nr_pages; /* number of pages in map */ | ||
176 | + int nr_pages; /* number of populated pages in map */ | ||
177 | + unsigned int nr_pages_max; /* pages[] & partial[] arrays size */ | ||
178 | unsigned int flags; /* splice flags */ | ||
179 | const struct pipe_buf_operations *ops;/* ops associated with output pipe */ | ||
180 | void (*spd_release)(struct splice_pipe_desc *, unsigned int); | ||
181 | @@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, | ||
182 | /* | ||
183 | * for dynamic pipe sizing | ||
184 | */ | ||
185 | -extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *); | ||
186 | -extern void splice_shrink_spd(struct pipe_inode_info *, | ||
187 | - struct splice_pipe_desc *); | ||
188 | +extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *); | ||
189 | +extern void splice_shrink_spd(struct splice_pipe_desc *); | ||
190 | extern void spd_release_page(struct splice_pipe_desc *, unsigned int); | ||
191 | |||
192 | extern const struct pipe_buf_operations page_cache_pipe_buf_ops; | ||
193 | diff --git a/kernel/relay.c b/kernel/relay.c | ||
194 | index b6f803a..a535fc9 100644 | ||
195 | --- a/kernel/relay.c | ||
196 | +++ b/kernel/relay.c | ||
197 | @@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in, | ||
198 | struct splice_pipe_desc spd = { | ||
199 | .pages = pages, | ||
200 | .nr_pages = 0, | ||
201 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
202 | .partial = partial, | ||
203 | .flags = flags, | ||
204 | .ops = &relay_pipe_buf_ops, | ||
205 | @@ -1302,8 +1303,8 @@ static ssize_t subbuf_splice_actor(struct file *in, | ||
206 | ret += padding; | ||
207 | |||
208 | out: | ||
209 | - splice_shrink_spd(pipe, &spd); | ||
210 | - return ret; | ||
211 | + splice_shrink_spd(&spd); | ||
212 | + return ret; | ||
213 | } | ||
214 | |||
215 | static ssize_t relay_file_splice_read(struct file *in, | ||
216 | diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c | ||
217 | index 697e49d..7e4edd3 100644 | ||
218 | --- a/kernel/trace/trace.c | ||
219 | +++ b/kernel/trace/trace.c | ||
220 | @@ -3456,6 +3456,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | ||
221 | .pages = pages_def, | ||
222 | .partial = partial_def, | ||
223 | .nr_pages = 0, /* This gets updated below. */ | ||
224 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
225 | .flags = flags, | ||
226 | .ops = &tracing_pipe_buf_ops, | ||
227 | .spd_release = tracing_spd_release_pipe, | ||
228 | @@ -3527,7 +3528,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | ||
229 | |||
230 | ret = splice_to_pipe(pipe, &spd); | ||
231 | out: | ||
232 | - splice_shrink_spd(pipe, &spd); | ||
233 | + splice_shrink_spd(&spd); | ||
234 | return ret; | ||
235 | |||
236 | out_err: | ||
237 | @@ -4017,6 +4018,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | ||
238 | struct splice_pipe_desc spd = { | ||
239 | .pages = pages_def, | ||
240 | .partial = partial_def, | ||
241 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
242 | .flags = flags, | ||
243 | .ops = &buffer_pipe_buf_ops, | ||
244 | .spd_release = buffer_spd_release, | ||
245 | @@ -4104,7 +4106,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | ||
246 | } | ||
247 | |||
248 | ret = splice_to_pipe(pipe, &spd); | ||
249 | - splice_shrink_spd(pipe, &spd); | ||
250 | + splice_shrink_spd(&spd); | ||
251 | out: | ||
252 | return ret; | ||
253 | } | ||
254 | diff --git a/mm/shmem.c b/mm/shmem.c | ||
255 | index 6c253f7..7a82174 100644 | ||
256 | --- a/mm/shmem.c | ||
257 | +++ b/mm/shmem.c | ||
258 | @@ -1359,6 +1359,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, | ||
259 | struct splice_pipe_desc spd = { | ||
260 | .pages = pages, | ||
261 | .partial = partial, | ||
262 | + .nr_pages_max = PIPE_DEF_BUFFERS, | ||
263 | .flags = flags, | ||
264 | .ops = &page_cache_pipe_buf_ops, | ||
265 | .spd_release = spd_release_page, | ||
266 | @@ -1447,7 +1448,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos, | ||
267 | if (spd.nr_pages) | ||
268 | error = splice_to_pipe(pipe, &spd); | ||
269 | |||
270 | - splice_shrink_spd(pipe, &spd); | ||
271 | + splice_shrink_spd(&spd); | ||
272 | |||
273 | if (error > 0) { | ||
274 | *ppos += error; | ||
275 | diff --git a/net/core/skbuff.c b/net/core/skbuff.c | ||
276 | index 2ec200de..af9c3c6 100644 | ||
277 | --- a/net/core/skbuff.c | ||
278 | +++ b/net/core/skbuff.c | ||
279 | @@ -1663,6 +1663,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | ||
280 | struct splice_pipe_desc spd = { | ||
281 | .pages = pages, | ||
282 | .partial = partial, | ||
283 | + .nr_pages_max = MAX_SKB_FRAGS, | ||
284 | .flags = flags, | ||
285 | .ops = &sock_pipe_buf_ops, | ||
286 | .spd_release = sock_spd_release, | ||
287 | @@ -1709,7 +1710,7 @@ done: | ||
288 | lock_sock(sk); | ||
289 | } | ||
290 | |||
291 | - splice_shrink_spd(pipe, &spd); | ||
292 | + splice_shrink_spd(&spd); | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | -- | ||
297 | 1.7.10 | ||
298 | |||