diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-07-07 09:41:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-07-07 09:41:29 -0400 |
commit | afe62c68cd3562c5f8e3ea293e82906dd5a87936 (patch) | |
tree | 5cc472bb610de783a1dca1e9f54043a0918d60bd /net/packet | |
parent | 68ac31918ec359a2bfb9f897bb62c2940652d2b8 (diff) |
af_packet: lock imbalance
fanout_add() might return with fanout_mutex held.
Reduce indentation level while we are at it
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 62 |
1 files changed, 31 insertions, 31 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index aec50a1e9849..aa4c73afa19a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -589,43 +589,43 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) | |||
589 | break; | 589 | break; |
590 | } | 590 | } |
591 | } | 591 | } |
592 | err = -EINVAL; | ||
592 | if (match && match->defrag != defrag) | 593 | if (match && match->defrag != defrag) |
593 | return -EINVAL; | 594 | goto out; |
594 | if (!match) { | 595 | if (!match) { |
596 | err = -ENOMEM; | ||
595 | match = kzalloc(sizeof(*match), GFP_KERNEL); | 597 | match = kzalloc(sizeof(*match), GFP_KERNEL); |
596 | if (match) { | 598 | if (!match) |
597 | write_pnet(&match->net, sock_net(sk)); | 599 | goto out; |
598 | match->id = id; | 600 | write_pnet(&match->net, sock_net(sk)); |
599 | match->type = type; | 601 | match->id = id; |
600 | match->defrag = defrag; | 602 | match->type = type; |
601 | atomic_set(&match->rr_cur, 0); | 603 | match->defrag = defrag; |
602 | INIT_LIST_HEAD(&match->list); | 604 | atomic_set(&match->rr_cur, 0); |
603 | spin_lock_init(&match->lock); | 605 | INIT_LIST_HEAD(&match->list); |
604 | atomic_set(&match->sk_ref, 0); | 606 | spin_lock_init(&match->lock); |
605 | match->prot_hook.type = po->prot_hook.type; | 607 | atomic_set(&match->sk_ref, 0); |
606 | match->prot_hook.dev = po->prot_hook.dev; | 608 | match->prot_hook.type = po->prot_hook.type; |
607 | match->prot_hook.func = packet_rcv_fanout; | 609 | match->prot_hook.dev = po->prot_hook.dev; |
608 | match->prot_hook.af_packet_priv = match; | 610 | match->prot_hook.func = packet_rcv_fanout; |
609 | dev_add_pack(&match->prot_hook); | 611 | match->prot_hook.af_packet_priv = match; |
610 | list_add(&match->list, &fanout_list); | 612 | dev_add_pack(&match->prot_hook); |
611 | } | 613 | list_add(&match->list, &fanout_list); |
612 | } | 614 | } |
613 | err = -ENOMEM; | 615 | err = -EINVAL; |
614 | if (match) { | 616 | if (match->type == type && |
615 | err = -EINVAL; | 617 | match->prot_hook.type == po->prot_hook.type && |
616 | if (match->type == type && | 618 | match->prot_hook.dev == po->prot_hook.dev) { |
617 | match->prot_hook.type == po->prot_hook.type && | 619 | err = -ENOSPC; |
618 | match->prot_hook.dev == po->prot_hook.dev) { | 620 | if (atomic_read(&match->sk_ref) < PACKET_FANOUT_MAX) { |
619 | err = -ENOSPC; | 621 | __dev_remove_pack(&po->prot_hook); |
620 | if (atomic_read(&match->sk_ref) < PACKET_FANOUT_MAX) { | 622 | po->fanout = match; |
621 | __dev_remove_pack(&po->prot_hook); | 623 | atomic_inc(&match->sk_ref); |
622 | po->fanout = match; | 624 | __fanout_link(sk, po); |
623 | atomic_inc(&match->sk_ref); | 625 | err = 0; |
624 | __fanout_link(sk, po); | ||
625 | err = 0; | ||
626 | } | ||
627 | } | 626 | } |
628 | } | 627 | } |
628 | out: | ||
629 | mutex_unlock(&fanout_mutex); | 629 | mutex_unlock(&fanout_mutex); |
630 | return err; | 630 | return err; |
631 | } | 631 | } |