diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:40:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:40:30 -0400 |
commit | a57793651ff1a09ef18bade998632435ca2dc13f (patch) | |
tree | fffc839d7b001f196421f09f0a06491588835fe1 /net/core | |
parent | 9cf52b2921fbe62566b6b2ee79f71203749c9e5e (diff) | |
parent | 52f095ee88d8851866bc7694ab991ca5abf21d5e (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (51 commits)
[IPV6]: Fix again the fl6_sock_lookup() fixed locking
[NETFILTER]: nf_conntrack_tcp: fix connection reopening fix
[IPV6]: Fix race in ipv6_flowlabel_opt() when inserting two labels
[IPV6]: Lost locking in fl6_sock_lookup
[IPV6]: Lost locking when inserting a flowlabel in ipv6_fl_list
[NETFILTER]: xt_sctp: fix mistake to pass a pointer where array is required
[NET]: Fix OOPS due to missing check in dev_parse_header().
[TCP]: Remove lost_retrans zero seqno special cases
[NET]: fix carrier-on bug?
[NET]: Fix uninitialised variable in ip_frag_reasm()
[IPSEC]: Rename mode to outer_mode and add inner_mode
[IPSEC]: Disallow combinations of RO and AH/ESP/IPCOMP
[IPSEC]: Use the top IPv4 route's peer instead of the bottom
[IPSEC]: Store afinfo pointer in xfrm_mode
[IPSEC]: Add missing BEET checks
[IPSEC]: Move type and mode map into xfrm_state.c
[IPSEC]: Fix length check in xfrm_parse_spi
[IPSEC]: Move ip_summed zapping out of xfrm6_rcv_spi
[IPSEC]: Get nexthdr from caller in xfrm6_rcv_spi
[IPSEC]: Move tunnel parsing for IPv4 out of xfrm4_input
...
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/filter.c | 58 | ||||
-rw-r--r-- | net/core/pktgen.c | 2 | ||||
-rw-r--r-- | net/core/sock.c | 14 |
3 files changed, 49 insertions, 25 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index bd903aaf7aa7..1f0068eae501 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -387,6 +387,25 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
387 | } | 387 | } |
388 | 388 | ||
389 | /** | 389 | /** |
390 | * sk_filter_rcu_release: Release a socket filter by rcu_head | ||
391 | * @rcu: rcu_head that contains the sk_filter to free | ||
392 | */ | ||
393 | static void sk_filter_rcu_release(struct rcu_head *rcu) | ||
394 | { | ||
395 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); | ||
396 | |||
397 | sk_filter_release(fp); | ||
398 | } | ||
399 | |||
400 | static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp) | ||
401 | { | ||
402 | unsigned int size = sk_filter_len(fp); | ||
403 | |||
404 | atomic_sub(size, &sk->sk_omem_alloc); | ||
405 | call_rcu_bh(&fp->rcu, sk_filter_rcu_release); | ||
406 | } | ||
407 | |||
408 | /** | ||
390 | * sk_attach_filter - attach a socket filter | 409 | * sk_attach_filter - attach a socket filter |
391 | * @fprog: the filter program | 410 | * @fprog: the filter program |
392 | * @sk: the socket to use | 411 | * @sk: the socket to use |
@@ -398,7 +417,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
398 | */ | 417 | */ |
399 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | 418 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) |
400 | { | 419 | { |
401 | struct sk_filter *fp; | 420 | struct sk_filter *fp, *old_fp; |
402 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; | 421 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; |
403 | int err; | 422 | int err; |
404 | 423 | ||
@@ -418,19 +437,34 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
418 | fp->len = fprog->len; | 437 | fp->len = fprog->len; |
419 | 438 | ||
420 | err = sk_chk_filter(fp->insns, fp->len); | 439 | err = sk_chk_filter(fp->insns, fp->len); |
421 | if (!err) { | 440 | if (err) { |
422 | struct sk_filter *old_fp; | 441 | sk_filter_uncharge(sk, fp); |
423 | 442 | return err; | |
424 | rcu_read_lock_bh(); | ||
425 | old_fp = rcu_dereference(sk->sk_filter); | ||
426 | rcu_assign_pointer(sk->sk_filter, fp); | ||
427 | rcu_read_unlock_bh(); | ||
428 | fp = old_fp; | ||
429 | } | 443 | } |
430 | 444 | ||
431 | if (fp) | 445 | rcu_read_lock_bh(); |
432 | sk_filter_release(sk, fp); | 446 | old_fp = rcu_dereference(sk->sk_filter); |
433 | return err; | 447 | rcu_assign_pointer(sk->sk_filter, fp); |
448 | rcu_read_unlock_bh(); | ||
449 | |||
450 | sk_filter_delayed_uncharge(sk, old_fp); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | int sk_detach_filter(struct sock *sk) | ||
455 | { | ||
456 | int ret = -ENOENT; | ||
457 | struct sk_filter *filter; | ||
458 | |||
459 | rcu_read_lock_bh(); | ||
460 | filter = rcu_dereference(sk->sk_filter); | ||
461 | if (filter) { | ||
462 | rcu_assign_pointer(sk->sk_filter, NULL); | ||
463 | sk_filter_delayed_uncharge(sk, filter); | ||
464 | ret = 0; | ||
465 | } | ||
466 | rcu_read_unlock_bh(); | ||
467 | return ret; | ||
434 | } | 468 | } |
435 | 469 | ||
436 | EXPORT_SYMBOL(sk_chk_filter); | 470 | EXPORT_SYMBOL(sk_chk_filter); |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2100c734b102..8cae60c53383 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -2454,7 +2454,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | |||
2454 | spin_lock(&x->lock); | 2454 | spin_lock(&x->lock); |
2455 | iph = ip_hdr(skb); | 2455 | iph = ip_hdr(skb); |
2456 | 2456 | ||
2457 | err = x->mode->output(x, skb); | 2457 | err = x->outer_mode->output(x, skb); |
2458 | if (err) | 2458 | if (err) |
2459 | goto error; | 2459 | goto error; |
2460 | err = x->type->output(x, skb); | 2460 | err = x->type->output(x, skb); |
diff --git a/net/core/sock.c b/net/core/sock.c index d45ecdccc6a1..d292b4113d6e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -428,7 +428,6 @@ int sock_setsockopt(struct socket *sock, int level, int optname, | |||
428 | char __user *optval, int optlen) | 428 | char __user *optval, int optlen) |
429 | { | 429 | { |
430 | struct sock *sk=sock->sk; | 430 | struct sock *sk=sock->sk; |
431 | struct sk_filter *filter; | ||
432 | int val; | 431 | int val; |
433 | int valbool; | 432 | int valbool; |
434 | struct linger ling; | 433 | struct linger ling; |
@@ -652,16 +651,7 @@ set_rcvbuf: | |||
652 | break; | 651 | break; |
653 | 652 | ||
654 | case SO_DETACH_FILTER: | 653 | case SO_DETACH_FILTER: |
655 | rcu_read_lock_bh(); | 654 | ret = sk_detach_filter(sk); |
656 | filter = rcu_dereference(sk->sk_filter); | ||
657 | if (filter) { | ||
658 | rcu_assign_pointer(sk->sk_filter, NULL); | ||
659 | sk_filter_release(sk, filter); | ||
660 | rcu_read_unlock_bh(); | ||
661 | break; | ||
662 | } | ||
663 | rcu_read_unlock_bh(); | ||
664 | ret = -ENONET; | ||
665 | break; | 655 | break; |
666 | 656 | ||
667 | case SO_PASSSEC: | 657 | case SO_PASSSEC: |
@@ -925,7 +915,7 @@ void sk_free(struct sock *sk) | |||
925 | 915 | ||
926 | filter = rcu_dereference(sk->sk_filter); | 916 | filter = rcu_dereference(sk->sk_filter); |
927 | if (filter) { | 917 | if (filter) { |
928 | sk_filter_release(sk, filter); | 918 | sk_filter_uncharge(sk, filter); |
929 | rcu_assign_pointer(sk->sk_filter, NULL); | 919 | rcu_assign_pointer(sk->sk_filter, NULL); |
930 | } | 920 | } |
931 | 921 | ||