Skip to content

Commit 28712d6

Browse files
committed
Merge branch 'ipsec: fix splat due to ipcomp fallback tunnel'
Sabrina Dubroca says: ==================== IPcomp tunnel states have an associated fallback tunnel, a keep a reference on the corresponding xfrm_state, to allow deleting that extra state when it's not needed anymore. These states cause issues during netns deletion. Commit f75a280 ("xfrm: destroy xfrm_state synchronously on net exit path") tried to address these problems but doesn't fully solve them, and slowed down netns deletion by adding one synchronize_rcu per deleted state. The first patch solves the problem by moving the fallback state deletion earlier (when we delete the user state, rather than at destruction), then we can revert the previous fix. ==================== Signed-off-by: Steffen Klassert <[email protected]>
2 parents a90b2a1 + 2a198bb commit 28712d6

File tree

8 files changed

+26
-38
lines changed

8 files changed

+26
-38
lines changed

include/net/xfrm.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo);
441441
int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo);
442442

443443
void xfrm_flush_gc(void);
444-
void xfrm_state_delete_tunnel(struct xfrm_state *x);
445444

446445
struct xfrm_type {
447446
struct module *owner;
@@ -916,7 +915,7 @@ static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
916915
xfrm_pol_put(pols[i]);
917916
}
918917

919-
void __xfrm_state_destroy(struct xfrm_state *, bool);
918+
void __xfrm_state_destroy(struct xfrm_state *);
920919

921920
static inline void __xfrm_state_put(struct xfrm_state *x)
922921
{
@@ -926,13 +925,7 @@ static inline void __xfrm_state_put(struct xfrm_state *x)
926925
static inline void xfrm_state_put(struct xfrm_state *x)
927926
{
928927
if (refcount_dec_and_test(&x->refcnt))
929-
__xfrm_state_destroy(x, false);
930-
}
931-
932-
static inline void xfrm_state_put_sync(struct xfrm_state *x)
933-
{
934-
if (refcount_dec_and_test(&x->refcnt))
935-
__xfrm_state_destroy(x, true);
928+
__xfrm_state_destroy(x);
936929
}
937930

938931
static inline void xfrm_state_hold(struct xfrm_state *x)
@@ -1770,7 +1763,7 @@ struct xfrmk_spdinfo {
17701763

17711764
struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq, u32 pcpu_num);
17721765
int xfrm_state_delete(struct xfrm_state *x);
1773-
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync);
1766+
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
17741767
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
17751768
int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
17761769
bool task_valid);

net/ipv4/ipcomp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ static int ipcomp4_err(struct sk_buff *skb, u32 info)
5454
}
5555

5656
/* We always hold one tunnel user reference to indicate a tunnel */
57+
static struct lock_class_key xfrm_state_lock_key;
5758
static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
5859
{
5960
struct net *net = xs_net(x);
@@ -62,6 +63,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
6263
t = xfrm_state_alloc(net);
6364
if (!t)
6465
goto out;
66+
lockdep_set_class(&t->lock, &xfrm_state_lock_key);
6567

6668
t->id.proto = IPPROTO_IPIP;
6769
t->id.spi = x->props.saddr.a4;

net/ipv6/ipcomp6.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
7171
return 0;
7272
}
7373

74+
static struct lock_class_key xfrm_state_lock_key;
7475
static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
7576
{
7677
struct net *net = xs_net(x);
@@ -79,6 +80,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
7980
t = xfrm_state_alloc(net);
8081
if (!t)
8182
goto out;
83+
lockdep_set_class(&t->lock, &xfrm_state_lock_key);
8284

8385
t->id.proto = IPPROTO_IPV6;
8486
t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr);

net/ipv6/xfrm6_tunnel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
334334
struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
335335
unsigned int i;
336336

337+
xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
337338
xfrm_flush_gc();
338-
xfrm_state_flush(net, 0, false, true);
339339

340340
for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
341341
WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i]));

net/key/af_key.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m
17661766
if (proto == 0)
17671767
return -EINVAL;
17681768

1769-
err = xfrm_state_flush(net, proto, true, false);
1769+
err = xfrm_state_flush(net, proto, true);
17701770
err2 = unicast_flush_resp(sk, hdr);
17711771
if (err || err2) {
17721772
if (err == -ESRCH) /* empty table - go quietly */

net/xfrm/xfrm_ipcomp.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ void ipcomp_destroy(struct xfrm_state *x)
313313
struct ipcomp_data *ipcd = x->data;
314314
if (!ipcd)
315315
return;
316-
xfrm_state_delete_tunnel(x);
317316
ipcomp_free_data(ipcd);
318317
kfree(ipcd);
319318
}

net/xfrm/xfrm_state.c

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ void xfrm_state_free(struct xfrm_state *x)
592592
}
593593
EXPORT_SYMBOL(xfrm_state_free);
594594

595-
static void ___xfrm_state_destroy(struct xfrm_state *x)
595+
static void xfrm_state_gc_destroy(struct xfrm_state *x)
596596
{
597597
if (x->mode_cbs && x->mode_cbs->destroy_state)
598598
x->mode_cbs->destroy_state(x);
@@ -631,7 +631,7 @@ static void xfrm_state_gc_task(struct work_struct *work)
631631
synchronize_rcu();
632632

633633
hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
634-
___xfrm_state_destroy(x);
634+
xfrm_state_gc_destroy(x);
635635
}
636636

637637
static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
@@ -795,22 +795,18 @@ void xfrm_dev_state_free(struct xfrm_state *x)
795795
}
796796
#endif
797797

798-
void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
798+
void __xfrm_state_destroy(struct xfrm_state *x)
799799
{
800800
WARN_ON(x->km.state != XFRM_STATE_DEAD);
801801

802-
if (sync) {
803-
synchronize_rcu();
804-
___xfrm_state_destroy(x);
805-
} else {
806-
spin_lock_bh(&xfrm_state_gc_lock);
807-
hlist_add_head(&x->gclist, &xfrm_state_gc_list);
808-
spin_unlock_bh(&xfrm_state_gc_lock);
809-
schedule_work(&xfrm_state_gc_work);
810-
}
802+
spin_lock_bh(&xfrm_state_gc_lock);
803+
hlist_add_head(&x->gclist, &xfrm_state_gc_list);
804+
spin_unlock_bh(&xfrm_state_gc_lock);
805+
schedule_work(&xfrm_state_gc_work);
811806
}
812807
EXPORT_SYMBOL(__xfrm_state_destroy);
813808

809+
static void xfrm_state_delete_tunnel(struct xfrm_state *x);
814810
int __xfrm_state_delete(struct xfrm_state *x)
815811
{
816812
struct net *net = xs_net(x);
@@ -838,6 +834,8 @@ int __xfrm_state_delete(struct xfrm_state *x)
838834

839835
xfrm_dev_state_delete(x);
840836

837+
xfrm_state_delete_tunnel(x);
838+
841839
/* All xfrm_state objects are created by xfrm_state_alloc.
842840
* The xfrm_state_alloc call gives a reference, and that
843841
* is what we are dropping here.
@@ -919,7 +917,7 @@ xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool
919917
}
920918
#endif
921919

922-
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
920+
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid)
923921
{
924922
int i, err = 0, cnt = 0;
925923

@@ -941,10 +939,7 @@ int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
941939
err = xfrm_state_delete(x);
942940
xfrm_audit_state_delete(x, err ? 0 : 1,
943941
task_valid);
944-
if (sync)
945-
xfrm_state_put_sync(x);
946-
else
947-
xfrm_state_put(x);
942+
xfrm_state_put(x);
948943
if (!err)
949944
cnt++;
950945

@@ -3068,20 +3063,17 @@ void xfrm_flush_gc(void)
30683063
}
30693064
EXPORT_SYMBOL(xfrm_flush_gc);
30703065

3071-
/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
3072-
void xfrm_state_delete_tunnel(struct xfrm_state *x)
3066+
static void xfrm_state_delete_tunnel(struct xfrm_state *x)
30733067
{
30743068
if (x->tunnel) {
30753069
struct xfrm_state *t = x->tunnel;
30763070

3077-
if (atomic_read(&t->tunnel_users) == 2)
3071+
if (atomic_dec_return(&t->tunnel_users) == 1)
30783072
xfrm_state_delete(t);
3079-
atomic_dec(&t->tunnel_users);
3080-
xfrm_state_put_sync(t);
3073+
xfrm_state_put(t);
30813074
x->tunnel = NULL;
30823075
}
30833076
}
3084-
EXPORT_SYMBOL(xfrm_state_delete_tunnel);
30853077

30863078
u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
30873079
{
@@ -3286,8 +3278,8 @@ void xfrm_state_fini(struct net *net)
32863278
unsigned int sz;
32873279

32883280
flush_work(&net->xfrm.state_hash_work);
3281+
xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
32893282
flush_work(&xfrm_state_gc_work);
3290-
xfrm_state_flush(net, 0, false, true);
32913283

32923284
WARN_ON(!list_empty(&net->xfrm.state_all));
32933285

net/xfrm/xfrm_user.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2635,7 +2635,7 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
26352635
struct xfrm_usersa_flush *p = nlmsg_data(nlh);
26362636
int err;
26372637

2638-
err = xfrm_state_flush(net, p->proto, true, false);
2638+
err = xfrm_state_flush(net, p->proto, true);
26392639
if (err) {
26402640
if (err == -ESRCH) /* empty table */
26412641
return 0;

0 commit comments

Comments
 (0)