svcrpc: ensure cache_check caller sees updated entry
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 4 Jan 2011 19:12:47 +0000 (14:12 -0500)
committerJ. Bruce Fields <bfields@redhat.com>
Tue, 4 Jan 2011 21:49:25 +0000 (16:49 -0500)
Supposes cache_check runs simultaneously with an update on a different
CPU:

cache_check task doing update
^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^

1. test for CACHE_VALID 1'. set entry->data
   & !CACHE_NEGATIVE

2. use entry->data 2'. set CACHE_VALID

If the two memory writes performed in step 1' and 2' appear misordered
with respect to the reads in step 1 and 2, then the caller could get
stale data at step 2 even though it saw CACHE_VALID set on the cache
entry.

Add memory barriers to prevent this.

Reviewed-by: NeilBrown <neilb@suse.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
net/sunrpc/cache.c

index a6c5733..72ad836 100644 (file)
@@ -128,6 +128,7 @@ static void cache_fresh_locked(struct cache_head *head, time_t expiry)
 {
        head->expiry_time = expiry;
        head->last_refresh = seconds_since_boot();
+       smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
        set_bit(CACHE_VALID, &head->flags);
 }
 
@@ -208,8 +209,16 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head
                /* entry is valid */
                if (test_bit(CACHE_NEGATIVE, &h->flags))
                        return -ENOENT;
-               else
+               else {
+                       /*
+                        * In combination with write barrier in
+                        * sunrpc_cache_update, ensures that anyone
+                        * using the cache entry after this sees the
+                        * updated contents:
+                        */
+                       smp_rmb();
                        return 0;
+               }
        }
 }