|
@@ -334,7 +334,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy)
|
|
|
|
|
|
atomic_inc(&policy->genid);
|
|
|
|
|
|
- del_timer(&policy->polq.hold_timer);
|
|
|
+ if (del_timer(&policy->polq.hold_timer))
|
|
|
+ xfrm_pol_put(policy);
|
|
|
xfrm_queue_purge(&policy->polq.hold_queue);
|
|
|
|
|
|
if (del_timer(&policy->timer))
|
|
@@ -589,7 +590,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
|
|
|
|
|
|
spin_lock_bh(&pq->hold_queue.lock);
|
|
|
skb_queue_splice_init(&pq->hold_queue, &list);
|
|
|
- del_timer(&pq->hold_timer);
|
|
|
+ if (del_timer(&pq->hold_timer))
|
|
|
+ xfrm_pol_put(old);
|
|
|
spin_unlock_bh(&pq->hold_queue.lock);
|
|
|
|
|
|
if (skb_queue_empty(&list))
|
|
@@ -600,7 +602,8 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
|
|
|
spin_lock_bh(&pq->hold_queue.lock);
|
|
|
skb_queue_splice(&list, &pq->hold_queue);
|
|
|
pq->timeout = XFRM_QUEUE_TMO_MIN;
|
|
|
- mod_timer(&pq->hold_timer, jiffies);
|
|
|
+ if (!mod_timer(&pq->hold_timer, jiffies))
|
|
|
+ xfrm_pol_hold(new);
|
|
|
spin_unlock_bh(&pq->hold_queue.lock);
|
|
|
}
|
|
|
|
|
@@ -1769,6 +1772,10 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
|
|
|
|
|
spin_lock(&pq->hold_queue.lock);
|
|
|
skb = skb_peek(&pq->hold_queue);
|
|
|
+ if (!skb) {
|
|
|
+ spin_unlock(&pq->hold_queue.lock);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
dst = skb_dst(skb);
|
|
|
sk = skb->sk;
|
|
|
xfrm_decode_session(skb, &fl, dst->ops->family);
|
|
@@ -1787,8 +1794,9 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
|
|
goto purge_queue;
|
|
|
|
|
|
pq->timeout = pq->timeout << 1;
|
|
|
- mod_timer(&pq->hold_timer, jiffies + pq->timeout);
|
|
|
- return;
|
|
|
+ if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
|
|
|
+ xfrm_pol_hold(pol);
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
dst_release(dst);
|
|
@@ -1819,11 +1827,14 @@ static void xfrm_policy_queue_process(unsigned long arg)
|
|
|
err = dst_output(skb);
|
|
|
}
|
|
|
|
|
|
+out:
|
|
|
+ xfrm_pol_put(pol);
|
|
|
return;
|
|
|
|
|
|
purge_queue:
|
|
|
pq->timeout = 0;
|
|
|
xfrm_queue_purge(&pq->hold_queue);
|
|
|
+ xfrm_pol_put(pol);
|
|
|
}
|
|
|
|
|
|
static int xdst_queue_output(struct sk_buff *skb)
|
|
@@ -1831,7 +1842,8 @@ static int xdst_queue_output(struct sk_buff *skb)
|
|
|
unsigned long sched_next;
|
|
|
struct dst_entry *dst = skb_dst(skb);
|
|
|
struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
|
|
|
- struct xfrm_policy_queue *pq = &xdst->pols[0]->polq;
|
|
|
+ struct xfrm_policy *pol = xdst->pols[0];
|
|
|
+ struct xfrm_policy_queue *pq = &pol->polq;
|
|
|
|
|
|
if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) {
|
|
|
kfree_skb(skb);
|
|
@@ -1850,10 +1862,12 @@ static int xdst_queue_output(struct sk_buff *skb)
|
|
|
if (del_timer(&pq->hold_timer)) {
|
|
|
if (time_before(pq->hold_timer.expires, sched_next))
|
|
|
sched_next = pq->hold_timer.expires;
|
|
|
+ xfrm_pol_put(pol);
|
|
|
}
|
|
|
|
|
|
__skb_queue_tail(&pq->hold_queue, skb);
|
|
|
- mod_timer(&pq->hold_timer, sched_next);
|
|
|
+ if (!mod_timer(&pq->hold_timer, sched_next))
|
|
|
+ xfrm_pol_hold(pol);
|
|
|
|
|
|
spin_unlock_bh(&pq->hold_queue.lock);
|
|
|
|