]> err.no Git - linux-2.6/blobdiff - net/netfilter/nf_conntrack_proto.c
[NETFILTER]: nf_conntrack: change nf_conntrack_l[34]proto_unregister to void
[linux-2.6] / net / netfilter / nf_conntrack_proto.c
index 941b5c3754af10e06907ef71fae3636c4a30239f..456155f05c759d3b3726bacc0f994ba311e7cdba 100644 (file)
@@ -30,6 +30,7 @@
 
 struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
 struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_l3protos);
 
 #ifdef CONFIG_SYSCTL
 static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex);
@@ -65,8 +66,9 @@ __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto)
        if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
                return &nf_conntrack_l4proto_generic;
 
-       return nf_ct_protos[l3proto][l4proto];
+       return rcu_dereference(nf_ct_protos[l3proto][l4proto]);
 }
+EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
 
 /* this is guaranteed to always return a valid protocol helper, since
  * it falls back to generic_protocol */
@@ -75,38 +77,42 @@ nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto)
 {
        struct nf_conntrack_l4proto *p;
 
-       preempt_disable();
+       rcu_read_lock();
        p = __nf_ct_l4proto_find(l3proto, l4proto);
        if (!try_module_get(p->me))
                p = &nf_conntrack_l4proto_generic;
-       preempt_enable();
+       rcu_read_unlock();
 
        return p;
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
 
 void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
 {
        module_put(p->me);
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
 
 struct nf_conntrack_l3proto *
 nf_ct_l3proto_find_get(u_int16_t l3proto)
 {
        struct nf_conntrack_l3proto *p;
 
-       preempt_disable();
+       rcu_read_lock();
        p = __nf_ct_l3proto_find(l3proto);
        if (!try_module_get(p->me))
                p = &nf_conntrack_l3proto_generic;
-       preempt_enable();
+       rcu_read_unlock();
 
        return p;
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get);
 
 void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p)
 {
        module_put(p->me);
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_put);
 
 int
 nf_ct_l3proto_try_module_get(unsigned short l3proto)
@@ -125,17 +131,17 @@ retry:    p = nf_ct_l3proto_find_get(l3proto);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_try_module_get);
 
 void nf_ct_l3proto_module_put(unsigned short l3proto)
 {
        struct nf_conntrack_l3proto *p;
 
-       preempt_disable();
+       /* rcu_read_lock not necessary since the caller holds a reference */
        p = __nf_ct_l3proto_find(l3proto);
-       preempt_enable();
-
        module_put(p->me);
 }
+EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
 
 static int kill_l3proto(struct nf_conn *i, void *data)
 {
@@ -194,7 +200,7 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
                ret = -EBUSY;
                goto out_unlock;
        }
-       nf_ct_l3protos[proto->l3proto] = proto;
+       rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
        write_unlock_bh(&nf_conntrack_lock);
 
        ret = nf_ct_l3proto_register_sysctl(proto);
@@ -207,37 +213,25 @@ out_unlock:
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
 
-int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
+void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
 {
-       int ret = 0;
-
-       if (proto->l3proto >= AF_MAX) {
-               ret = -EBUSY;
-               goto out;
-       }
+       BUG_ON(proto->l3proto >= AF_MAX);
 
        write_lock_bh(&nf_conntrack_lock);
-       if (nf_ct_l3protos[proto->l3proto] != proto) {
-               write_unlock_bh(&nf_conntrack_lock);
-               ret = -EBUSY;
-               goto out;
-       }
-
-       nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic;
+       BUG_ON(nf_ct_l3protos[proto->l3proto] != proto);
+       rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
+                          &nf_conntrack_l3proto_generic);
        write_unlock_bh(&nf_conntrack_lock);
+       synchronize_rcu();
 
        nf_ct_l3proto_unregister_sysctl(proto);
 
-       /* Somebody could be still looking at the proto in bh. */
-       synchronize_net();
-
        /* Remove all contrack entries for this protocol */
        nf_ct_iterate_cleanup(kill_l3proto, proto);
-
-out:
-       return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 
 static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
 {
@@ -250,9 +244,24 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
                                            nf_net_netfilter_sysctl_path,
                                            l4proto->ctl_table,
                                            l4proto->ctl_table_users);
+               if (err < 0)
+                       goto out;
        }
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       if (l4proto->ctl_compat_table != NULL) {
+               err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
+                                           nf_net_ipv4_netfilter_sysctl_path,
+                                           l4proto->ctl_compat_table, NULL);
+               if (err == 0)
+                       goto out;
+               nf_ct_unregister_sysctl(l4proto->ctl_table_header,
+                                       l4proto->ctl_table,
+                                       l4proto->ctl_table_users);
+       }
+#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
+out:
        mutex_unlock(&nf_ct_proto_sysctl_mutex);
-#endif
+#endif /* CONFIG_SYSCTL */
        return err;
 }
 
@@ -265,8 +274,13 @@ static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto
                nf_ct_unregister_sysctl(l4proto->ctl_table_header,
                                        l4proto->ctl_table,
                                        l4proto->ctl_table_users);
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       if (l4proto->ctl_compat_table_header != NULL)
+               nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
+                                       l4proto->ctl_compat_table, NULL);
+#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
        mutex_unlock(&nf_ct_proto_sysctl_mutex);
-#endif
+#endif /* CONFIG_SYSCTL */
 }
 
 /* FIXME: Allow NULL functions and sub in pointers to generic for
@@ -280,6 +294,9 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
                goto out;
        }
 
+       if (l4proto == &nf_conntrack_l4proto_generic)
+               return nf_ct_l4proto_register_sysctl(l4proto);
+
 retry:
        write_lock_bh(&nf_conntrack_lock);
        if (nf_ct_protos[l4proto->l3proto]) {
@@ -323,7 +340,7 @@ retry:
                goto retry;
        }
 
-       nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto;
+       rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto);
        write_unlock_bh(&nf_conntrack_lock);
 
        ret = nf_ct_l4proto_register_sysctl(l4proto);
@@ -336,35 +353,27 @@ out_unlock:
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
-int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
+void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
 {
-       int ret = 0;
+       BUG_ON(l4proto->l3proto >= PF_MAX);
 
-       if (l4proto->l3proto >= PF_MAX) {
-               ret = -EBUSY;
-               goto out;
+       if (l4proto == &nf_conntrack_l4proto_generic) {
+               nf_ct_l4proto_unregister_sysctl(l4proto);
+               return;
        }
 
        write_lock_bh(&nf_conntrack_lock);
-       if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto]
-           != l4proto) {
-               write_unlock_bh(&nf_conntrack_lock);
-               ret = -EBUSY;
-               goto out;
-       }
-       nf_ct_protos[l4proto->l3proto][l4proto->l4proto]
-               = &nf_conntrack_l4proto_generic;
+       BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto);
+       rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+                          &nf_conntrack_l4proto_generic);
        write_unlock_bh(&nf_conntrack_lock);
+       synchronize_rcu();
 
        nf_ct_l4proto_unregister_sysctl(l4proto);
 
-       /* Somebody could be still looking at the proto in bh. */
-       synchronize_net();
-
        /* Remove all contrack entries for this protocol */
        nf_ct_iterate_cleanup(kill_l4proto, l4proto);
-
-out:
-       return ret;
 }
+EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);