Hi Dave: This patch fixes the index recycling problem for expired policies. -- Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ ) Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/include/net/xfrm.h =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/xfrm.h,v retrieving revision 1.8 diff -u -r1.8 xfrm.h --- kernel-source-2.5/include/net/xfrm.h 5 Jul 2003 04:44:34 -0000 1.8 +++ kernel-source-2.5/include/net/xfrm.h 5 Jul 2003 05:54:39 -0000 @@ -637,16 +637,16 @@ return 0; } -extern void __xfrm_sk_free_policy(struct xfrm_policy *, int dir); +extern void xfrm_policy_delete(struct xfrm_policy *pol, int dir); static inline void xfrm_sk_free_policy(struct sock *sk) { if (unlikely(sk->sk_policy[0] != NULL)) { - __xfrm_sk_free_policy(sk->sk_policy[0], 0); + xfrm_policy_delete(sk->sk_policy[0], XFRM_POLICY_MAX); sk->sk_policy[0] = NULL; } if (unlikely(sk->sk_policy[1] != NULL)) { - __xfrm_sk_free_policy(sk->sk_policy[1], 1); + xfrm_policy_delete(sk->sk_policy[1], XFRM_POLICY_MAX+1); sk->sk_policy[1] = NULL; } } Index: kernel-source-2.5/net/xfrm/xfrm_policy.c =================================================================== RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_policy.c,v retrieving revision 1.15 diff -u -r1.15 xfrm_policy.c --- kernel-source-2.5/net/xfrm/xfrm_policy.c 5 Jul 2003 06:56:57 -0000 1.15 +++ kernel-source-2.5/net/xfrm/xfrm_policy.c 5 Jul 2003 07:33:36 -0000 @@ -141,7 +141,6 @@ struct xfrm_policy *xp = (struct xfrm_policy*)data; unsigned long now = (unsigned long)xtime.tv_sec; long next = LONG_MAX; - u32 index; if (xp->dead) goto out; @@ -163,14 +162,8 @@ return; expired: - index = xp->index; + xfrm_policy_delete(xp, xp->index & 7); xfrm_pol_put(xp); - - /* Not 100% correct. id can be recycled in theory */ - xp = xfrm_policy_byid(0, index, 1); - if (xp) { - xfrm_pol_put(xp); - } } @@ -481,25 +474,36 @@ return pol; } -void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) +static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) { - pol->next = xfrm_policy_list[XFRM_POLICY_MAX+dir]; - xfrm_policy_list[XFRM_POLICY_MAX+dir] = pol; + pol->next = xfrm_policy_list[dir]; + xfrm_policy_list[dir] = pol; xfrm_pol_hold(pol); } -void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) +static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, + int dir) { struct xfrm_policy **polp; - for (polp = &xfrm_policy_list[XFRM_POLICY_MAX+dir]; + for (polp = &xfrm_policy_list[dir]; *polp != NULL; polp = &(*polp)->next) { if (*polp == pol) { *polp = pol->next; atomic_dec(&pol->refcnt); - return; + return pol; } } + return NULL; +} + +void xfrm_policy_delete(struct xfrm_policy *pol, int dir) +{ + write_lock_bh(&xfrm_policy_lock); + pol = __xfrm_policy_unlink(pol, dir); + write_unlock_bh(&xfrm_policy_lock); + if (pol) + xfrm_policy_kill(pol); } int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) @@ -512,10 +516,10 @@ if (pol) { pol->curlft.add_time = (unsigned long)xtime.tv_sec; pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); - xfrm_sk_policy_link(pol, dir); + __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); } if (old_pol) - xfrm_sk_policy_unlink(old_pol, dir); + __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); write_unlock_bh(&xfrm_policy_lock); if (old_pol) { @@ -540,7 +544,7 @@ memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); write_lock_bh(&xfrm_policy_lock); - xfrm_sk_policy_link(newp, dir); + __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); write_unlock_bh(&xfrm_policy_lock); } return newp; @@ -557,15 +561,6 @@ if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL) return -ENOMEM; return 0; -} - -void __xfrm_sk_free_policy(struct xfrm_policy *pol, int dir) -{ - write_lock_bh(&xfrm_policy_lock); - xfrm_sk_policy_unlink(pol, dir); - write_unlock_bh(&xfrm_policy_lock); - - xfrm_policy_kill(pol); } /* Resolve list of templates for the flow, given policy. */