Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=61dcc6f4d9ed5db71f4f0be9026bdd09f1a7dc06
Commit:     61dcc6f4d9ed5db71f4f0be9026bdd09f1a7dc06
Parent:     9e34682026572f07328208f7d2b2c611d2001844
Author:     Ralf Baechle <[EMAIL PROTECTED]>
AuthorDate: Thu Mar 15 17:10:16 2007 +0000
Committer:  Ralf Baechle <[EMAIL PROTECTED]>
CommitDate: Sat Mar 17 01:03:27 2007 +0000

    [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 <[EMAIL PROTECTED]>
---
 arch/mips/kernel/rtlx.c |   41 ++++++++++++++++++++++++-----------------
 1 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 16d3fde..0441c7c 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)
 
 ssize_t rtlx_read(int index, void *buff, size_t count, int user)
 {
-       size_t fl = 0L;
+       size_t lx_write, fl = 0L;
        struct rtlx_channel *lx;
 
        if (rtlx == NULL)
@@ -314,23 +314,26 @@ ssize_t rtlx_read(int index, void *buff, size_t count, 
int user)
 
        lx = &rtlx->channel[index];
 
+       smp_rmb();
+       lx_write = lx->lx_write;
+
        /* find out how much in total */
        count = min(count,
-                    (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read)
+                    (size_t)(lx_write + lx->buffer_size - lx->lx_read)
                     % lx->buffer_size);
 
        /* then how much from the read pointer onwards */
-       fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
+       fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
 
-       copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user);
+       copy_to(buff, lx->lx_buffer + lx->lx_read, fl, user);
 
        /* and if there is anything left at the beginning of the buffer */
-       if ( count - fl )
-               copy_to (buff + fl, lx->lx_buffer, count - fl, user);
+       if (count - fl)
+               copy_to(buff + fl, lx->lx_buffer, count - fl, user);
 
-       /* update the index */
-       lx->lx_read += count;
-       lx->lx_read %= lx->buffer_size;
+       smp_wmb();
+       lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
+       smp_wmb();
 
        return count;
 }
@@ -338,6 +341,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int 
user)
 ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
 {
        struct rtlx_channel *rt;
+       size_t rt_read;
        size_t fl;
 
        if (rtlx == NULL)
@@ -345,24 +349,27 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, 
int user)
 
        rt = &rtlx->channel[index];
 
+       smp_rmb();
+       rt_read = rt->rt_read;
+
        /* total number of bytes to copy */
        count = min(count,
-                   (size_t)write_spacefree(rt->rt_read, rt->rt_write,
-                                           rt->buffer_size));
+                   (size_t)write_spacefree(rt_read, rt->rt_write, 
rt->buffer_size));
 
        /* first bit from write pointer to the end of the buffer, or count */
        fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
 
-       copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user);
+       copy_from(rt->rt_buffer + rt->rt_write, buffer, fl, user);
 
        /* if there's any left copy to the beginning of the buffer */
-       if( count - fl )
-               copy_from (rt->rt_buffer, buffer + fl, count - fl, user);
+       if (count - fl)
+               copy_from(rt->rt_buffer, buffer + fl, count - fl, user);
 
-       rt->rt_write += count;
-       rt->rt_write %= rt->buffer_size;
+       smp_wmb();
+       rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
+       smp_wmb();
 
-       return(count);
+       return count;
 }
 
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to