summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.23/0001-splice-fix-racy-pipe-buffers-uses.patch
diff options
context:
space:
mode:
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.patch298
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 @@
1From e02d361ade75d22d28ce36460954b4bc6439fc74 Mon Sep 17 00:00:00 2001
2From: Eric Dumazet <edumazet@google.com>
3Date: Tue, 12 Jun 2012 15:24:40 +0200
4Subject: [PATCH 01/49] splice: fix racy pipe->buffers uses
5
6commit 047fe3605235888f3ebcda0c728cb31937eadfe6 upstream.
7
8Dave Jones reported a kernel BUG at mm/slub.c:3474! triggered
9by splice_shrink_spd() called from vmsplice_to_pipe()
10
11commit 35f3d14dbbc5 (pipe: add support for shrinking and growing pipes)
12added capability to adjust pipe->buffers.
13
14Problem is some paths don't hold pipe mutex and assume pipe->buffers
15doesn't change for their duration.
16
17Fix this by adding nr_pages_max field in struct splice_pipe_desc, and
18use it in place of pipe->buffers where appropriate.
19
20splice_shrink_spd() loses its struct pipe_inode_info argument.
21
22Reported-by: Dave Jones <davej@redhat.com>
23Signed-off-by: Eric Dumazet <edumazet@google.com>
24Cc: Jens Axboe <axboe@kernel.dk>
25Cc: Alexander Viro <viro@zeniv.linux.org.uk>
26Cc: Tom Herbert <therbert@google.com>
27Tested-by: Dave Jones <davej@redhat.com>
28Signed-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()]
32Signed-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
42diff --git a/fs/splice.c b/fs/splice.c
43index 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
167diff --git a/include/linux/splice.h b/include/linux/splice.h
168index 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;
193diff --git a/kernel/relay.c b/kernel/relay.c
194index 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,
216diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
217index 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 }
254diff --git a/mm/shmem.c b/mm/shmem.c
255index 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;
275diff --git a/net/core/skbuff.c b/net/core/skbuff.c
276index 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--
2971.7.10
298