tunneling: Add checks for header cache lock.
authorJesse Gross <jesse@nicira.com>
Sun, 5 Dec 2010 20:36:36 +0000 (12:36 -0800)
committerJesse Gross <jesse@nicira.com>
Mon, 13 Dec 2010 21:42:33 +0000 (13:42 -0800)
When updating the tunnel header cache, we need to hold a lock to
protect against concurrent access.  This adds annotations to
make sparse happy when we access the data without rcu_read_lock
and enables lockdep to verify that we have the correct lock.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/tunnel.c

index 381e2618aaae163f58ebdf25910dce59cc677241..bf66f4f0932abc14df598aad53fcf6659ae2bb3e 100644 (file)
@@ -99,6 +99,15 @@ static inline struct tnl_vport *tnl_vport_table_cast(const struct tbl_node *node
        return container_of(node, struct tnl_vport, tbl_node);
 }
 
+/* This is analogous to rtnl_dereference for the tunnel cache.  It checks that
+ * cache_lock is held, so it is only for update side code.
+ */
+static inline struct tnl_cache *cache_dereference(struct tnl_vport *tnl_vport)
+{
+       return rcu_dereference_protected(tnl_vport->cache,
+                                        lockdep_is_held(&tnl_vport->cache_lock));
+}
+
 static inline void schedule_cache_cleaner(void)
 {
        schedule_delayed_work(&cache_cleaner_wq, CACHE_CLEANER_INTERVAL);
@@ -142,7 +151,7 @@ static void assign_cache_rcu(struct vport *vport, struct tnl_cache *new_cache)
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        struct tnl_cache *old_cache;
 
-       old_cache = tnl_vport->cache;
+       old_cache = cache_dereference(tnl_vport);
        rcu_assign_pointer(tnl_vport->cache, new_cache);
 
        if (old_cache)
@@ -874,7 +883,7 @@ static struct tnl_cache *build_cache(struct vport *vport,
        if (!spin_trylock_bh(&tnl_vport->cache_lock))
                return NULL;
 
-       cache = tnl_vport->cache;
+       cache = cache_dereference(tnl_vport);
        if (check_cache_valid(cache, mutable))
                goto unlock;
        else