]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/netfilter/ipvs/ip_vs_app.c
ipvs: do not disable bh for long time
[mirror_ubuntu-zesty-kernel.git] / net / netfilter / ipvs / ip_vs_app.c
index 0b779d7df8813b1519d9320d72a3b46dccf7c2c3..dfd7b65b3d2a9165eed15c5e8a7b90c1ed30c050 100644 (file)
@@ -58,6 +58,18 @@ static inline void ip_vs_app_put(struct ip_vs_app *app)
        module_put(app->module);
 }
 
+static void ip_vs_app_inc_destroy(struct ip_vs_app *inc)
+{
+       kfree(inc->timeout_table);
+       kfree(inc);
+}
+
+static void ip_vs_app_inc_rcu_free(struct rcu_head *head)
+{
+       struct ip_vs_app *inc = container_of(head, struct ip_vs_app, rcu_head);
+
+       ip_vs_app_inc_destroy(inc);
+}
 
 /*
  *     Allocate/initialize app incarnation and register it in proto apps.
@@ -106,8 +118,7 @@ ip_vs_app_inc_new(struct net *net, struct ip_vs_app *app, __u16 proto,
        return 0;
 
   out:
-       kfree(inc->timeout_table);
-       kfree(inc);
+       ip_vs_app_inc_destroy(inc);
        return ret;
 }
 
@@ -131,8 +142,7 @@ ip_vs_app_inc_release(struct net *net, struct ip_vs_app *inc)
 
        list_del(&inc->a_list);
 
-       kfree(inc->timeout_table);
-       kfree(inc);
+       call_rcu(&inc->rcu_head, ip_vs_app_inc_rcu_free);
 }
 
 
@@ -144,9 +154,9 @@ int ip_vs_app_inc_get(struct ip_vs_app *inc)
 {
        int result;
 
-       atomic_inc(&inc->usecnt);
-       if (unlikely((result = ip_vs_app_get(inc->app)) != 1))
-               atomic_dec(&inc->usecnt);
+       result = ip_vs_app_get(inc->app);
+       if (result)
+               atomic_inc(&inc->usecnt);
        return result;
 }
 
@@ -156,8 +166,8 @@ int ip_vs_app_inc_get(struct ip_vs_app *inc)
  */
 void ip_vs_app_inc_put(struct ip_vs_app *inc)
 {
-       ip_vs_app_put(inc->app);
        atomic_dec(&inc->usecnt);
+       ip_vs_app_put(inc->app);
 }
 
 
@@ -218,6 +228,7 @@ out_unlock:
 /*
  *     ip_vs_app unregistration routine
  *     We are sure there are no app incarnations attached to services
+ *     Caller should use synchronize_rcu() or rcu_barrier()
  */
 void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app)
 {
@@ -341,14 +352,14 @@ static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
                                 unsigned int flag, __u32 seq, int diff)
 {
        /* spinlock is to keep updating cp->flags atomic */
-       spin_lock(&cp->lock);
+       spin_lock_bh(&cp->lock);
        if (!(cp->flags & flag) || after(seq, vseq->init_seq)) {
                vseq->previous_delta = vseq->delta;
                vseq->delta += diff;
                vseq->init_seq = seq;
                cp->flags |= flag;
        }
-       spin_unlock(&cp->lock);
+       spin_unlock_bh(&cp->lock);
 }
 
 static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,