aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/rtlx.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-03-15 13:10:16 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-03-16 21:03:27 -0400
commit61dcc6f4d9ed5db71f4f0be9026bdd09f1a7dc06 (patch)
treeeb28cb6fe958e7f527ac03d58b7a6e80afe425f2 /arch/mips/kernel/rtlx.c
parent9e34682026572f07328208f7d2b2c611d2001844 (diff)
[MIPS] RTLX: Harden against compiler reordering and optimization.
RTLX communication is based on lock-free shared memory buffers. It happened to be working by luck so far but relies on the optimizer doing certain optimizations but no reordering. Fixed by inserting proper barriers in rtlx_read and rtlx_write, and careful pointer dereferencing. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/rtlx.c')
-rw-r--r--arch/mips/kernel/rtlx.c41
1 files changed, 24 insertions, 17 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 16d3fdecf3ea..0441c7c1e44c 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -306,7 +306,7 @@ static inline void copy_from(void *dst, void *src, size_t count, int user)
306 306
307ssize_t rtlx_read(int index, void *buff, size_t count, int user) 307ssize_t rtlx_read(int index, void *buff, size_t count, int user)
308{ 308{
309 size_t fl = 0L; 309 size_t lx_write, fl = 0L;
310 struct rtlx_channel *lx; 310 struct rtlx_channel *lx;
311 311
312 if (rtlx == NULL) 312 if (rtlx == NULL)
@@ -314,23 +314,26 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user)
314 314
315 lx = &rtlx->channel[index]; 315 lx = &rtlx->channel[index];
316 316
317 smp_rmb();
318 lx_write = lx->lx_write;
319
317 /* find out how much in total */ 320 /* find out how much in total */
318 count = min(count, 321 count = min(count,
319 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) 322 (size_t)(lx_write + lx->buffer_size - lx->lx_read)
320 % lx->buffer_size); 323 % lx->buffer_size);
321 324
322 /* then how much from the read pointer onwards */ 325 /* then how much from the read pointer onwards */
323 fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 326 fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
324 327
325 copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user); 328 copy_to(buff, lx->lx_buffer + lx->lx_read, fl, user);
326 329
327 /* and if there is anything left at the beginning of the buffer */ 330 /* and if there is anything left at the beginning of the buffer */
328 if ( count - fl ) 331 if (count - fl)
329 copy_to (buff + fl, lx->lx_buffer, count - fl, user); 332 copy_to(buff + fl, lx->lx_buffer, count - fl, user);
330 333
331 /* update the index */ 334 smp_wmb();
332 lx->lx_read += count; 335 lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
333 lx->lx_read %= lx->buffer_size; 336 smp_wmb();
334 337
335 return count; 338 return count;
336} 339}
@@ -338,6 +341,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user)
338ssize_t rtlx_write(int index, void *buffer, size_t count, int user) 341ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
339{ 342{
340 struct rtlx_channel *rt; 343 struct rtlx_channel *rt;
344 size_t rt_read;
341 size_t fl; 345 size_t fl;
342 346
343 if (rtlx == NULL) 347 if (rtlx == NULL)
@@ -345,24 +349,27 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
345 349
346 rt = &rtlx->channel[index]; 350 rt = &rtlx->channel[index];
347 351
352 smp_rmb();
353 rt_read = rt->rt_read;
354
348 /* total number of bytes to copy */ 355 /* total number of bytes to copy */
349 count = min(count, 356 count = min(count,
350 (size_t)write_spacefree(rt->rt_read, rt->rt_write, 357 (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size));
351 rt->buffer_size));
352 358
353 /* first bit from write pointer to the end of the buffer, or count */ 359 /* first bit from write pointer to the end of the buffer, or count */
354 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 360 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
355 361
356 copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user); 362 copy_from(rt->rt_buffer + rt->rt_write, buffer, fl, user);
357 363
358 /* if there's any left copy to the beginning of the buffer */ 364 /* if there's any left copy to the beginning of the buffer */
359 if( count - fl ) 365 if (count - fl)
360 copy_from (rt->rt_buffer, buffer + fl, count - fl, user); 366 copy_from(rt->rt_buffer, buffer + fl, count - fl, user);
361 367
362 rt->rt_write += count; 368 smp_wmb();
363 rt->rt_write %= rt->buffer_size; 369 rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
370 smp_wmb();
364 371
365 return(count); 372 return count;
366} 373}
367 374
368 375