static void pppoe_flush_dev(struct net_device *dev) { int hash; BUG_ON(dev == NULL); read_lock_bh(&pppoe_hash_lock); for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) { struct pppox_sock *po = item_hash_table[hash]; while (po != NULL) { if (po->pppoe_dev == dev) { struct sock *sk = sk_pppox(po); sock_hold(sk); po->pppoe_dev = NULL; /* We hold a reference to SK, now drop the * hash table lock so that we may attempt * to lock the socket (which can sleep). */ read_unlock_bh(&pppoe_hash_lock); lock_sock(sk); if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { pppox_unbind_sock(sk); dev_put(dev); sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); } release_sock(sk); sock_put(sk); read_lock_bh(&pppoe_hash_lock); /* Now restart from the beginning of this * hash chain. We always NULL out pppoe_dev * so we are guaranteed to make forward * progress. */ po = item_hash_table[hash]; continue; } po = po->next; } } read_unlock_bh(&pppoe_hash_lock); }
static void pppoe_dzc_flush_dev(struct net_device *dev) { struct pppoe_net *pn; int i; pn = dzc_pppoe_pernet(dev_net(dev)); write_lock_bh(&pn->hash_lock); for (i = 0; i < (1 << 4); i++) { struct pppox_sock *po = pn->hash_table[i]; struct sock *sk; while (po) { while (po && po->pppoe_dev != dev) { po = po->next; } if (!po) break; sk = sk_pppox(po); sock_hold(sk); write_unlock_bh(&pn->hash_lock); lock_sock(sk); if (po->pppoe_dev == dev && sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { pppox_unbind_sock(sk); sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); po->pppoe_dev = NULL; dev_put(dev); } release_sock(sk); sock_put(sk); BUG_ON(dzc_pppoe_pernet(dev_net(dev)) == NULL); write_lock_bh(&pn->hash_lock); po = pn->hash_table[i]; } } write_unlock_bh(&pn->hash_lock); }