Merge branch 'for-linus' of git://github.com/richardweinberger/linux
[pandora-kernel.git] / net / ipv4 / tunnel4.c
index 9a17bd2..ac3b3ee 100644 (file)
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
-static struct xfrm_tunnel *tunnel4_handlers __read_mostly;
-static struct xfrm_tunnel *tunnel64_handlers __read_mostly;
+static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
+static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
 static DEFINE_MUTEX(tunnel4_mutex);
 
-static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
+static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
 {
        return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
 }
 
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
 {
-       struct xfrm_tunnel **pprev;
+       struct xfrm_tunnel __rcu **pprev;
+       struct xfrm_tunnel *t;
+
        int ret = -EEXIST;
        int priority = handler->priority;
 
        mutex_lock(&tunnel4_mutex);
 
-       for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
-               if ((*pprev)->priority > priority)
+       for (pprev = fam_handlers(family);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&tunnel4_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t->priority > priority)
                        break;
-               if ((*pprev)->priority == priority)
+               if (t->priority == priority)
                        goto err;
        }
 
@@ -52,13 +57,17 @@ EXPORT_SYMBOL(xfrm4_tunnel_register);
 
 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
 {
-       struct xfrm_tunnel **pprev;
+       struct xfrm_tunnel __rcu **pprev;
+       struct xfrm_tunnel *t;
        int ret = -ENOENT;
 
        mutex_lock(&tunnel4_mutex);
 
-       for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
-               if (*pprev == handler) {
+       for (pprev = fam_handlers(family);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&tunnel4_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t == handler) {
                        *pprev = handler->next;
                        ret = 0;
                        break;