Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
[cascardo/linux.git] / net / xfrm / xfrm_policy.c
index d8c35ad..18cead7 100644 (file)
@@ -700,6 +700,9 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
        struct xfrm_policy_queue *pq = &old->polq;
        struct sk_buff_head list;
 
+       if (skb_queue_empty(&pq->hold_queue))
+               return;
+
        __skb_queue_head_init(&list);
 
        spin_lock_bh(&pq->hold_queue.lock);
@@ -708,9 +711,6 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
                xfrm_pol_put(old);
        spin_unlock_bh(&pq->hold_queue.lock);
 
-       if (skb_queue_empty(&list))
-               return;
-
        pq = &new->polq;
 
        spin_lock_bh(&pq->hold_queue.lock);
@@ -1004,7 +1004,9 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
        if (list_empty(&walk->walk.all))
                x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
        else
-               x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
+               x = list_first_entry(&walk->walk.all,
+                                    struct xfrm_policy_walk_entry, all);
+
        list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
                if (x->dead)
                        continue;
@@ -1112,6 +1114,9 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
        }
        chain = &net->xfrm.policy_inexact[dir];
        hlist_for_each_entry(pol, chain, bydst) {
+               if ((pol->priority >= priority) && ret)
+                       break;
+
                err = xfrm_policy_match(pol, fl, type, family, dir);
                if (err) {
                        if (err == -ESRCH)
@@ -1120,13 +1125,13 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
                                ret = ERR_PTR(err);
                                goto fail;
                        }
-               } else if (pol->priority < priority) {
+               } else {
                        ret = pol;
                        break;
                }
        }
-       if (ret)
-               xfrm_pol_hold(ret);
+
+       xfrm_pol_hold(ret);
 fail:
        read_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
@@ -2806,7 +2811,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
                return -EAFNOSUPPORT;
        spin_lock(&xfrm_policy_afinfo_lock);
        if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
-               err = -ENOBUFS;
+               err = -EEXIST;
        else {
                struct dst_ops *dst_ops = afinfo->dst_ops;
                if (likely(dst_ops->kmem_cachep == NULL))
@@ -3201,16 +3206,17 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
        }
        chain = &net->xfrm.policy_inexact[dir];
        hlist_for_each_entry(pol, chain, bydst) {
+               if ((pol->priority >= priority) && ret)
+                       break;
+
                if (xfrm_migrate_selector_match(sel, &pol->selector) &&
-                   pol->type == type &&
-                   pol->priority < priority) {
+                   pol->type == type) {
                        ret = pol;
                        break;
                }
        }
 
-       if (ret)
-               xfrm_pol_hold(ret);
+       xfrm_pol_hold(ret);
 
        read_unlock_bh(&net->xfrm.xfrm_policy_lock);