|
@@ -1262,24 +1262,22 @@ static int packet_release(struct socket *sock)
|
|
net = sock_net(sk);
|
|
net = sock_net(sk);
|
|
po = pkt_sk(sk);
|
|
po = pkt_sk(sk);
|
|
|
|
|
|
- write_lock_bh(&net->packet.sklist_lock);
|
|
|
|
- sk_del_node_init(sk);
|
|
|
|
|
|
+ spin_lock_bh(&net->packet.sklist_lock);
|
|
|
|
+ sk_del_node_init_rcu(sk);
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
- write_unlock_bh(&net->packet.sklist_lock);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Unhook packet receive handler.
|
|
|
|
- */
|
|
|
|
|
|
+ spin_unlock_bh(&net->packet.sklist_lock);
|
|
|
|
|
|
|
|
+ spin_lock(&po->bind_lock);
|
|
if (po->running) {
|
|
if (po->running) {
|
|
/*
|
|
/*
|
|
- * Remove the protocol hook
|
|
|
|
|
|
+ * Remove from protocol table
|
|
*/
|
|
*/
|
|
- dev_remove_pack(&po->prot_hook);
|
|
|
|
po->running = 0;
|
|
po->running = 0;
|
|
po->num = 0;
|
|
po->num = 0;
|
|
|
|
+ __dev_remove_pack(&po->prot_hook);
|
|
__sock_put(sk);
|
|
__sock_put(sk);
|
|
}
|
|
}
|
|
|
|
+ spin_unlock(&po->bind_lock);
|
|
|
|
|
|
packet_flush_mclist(sk);
|
|
packet_flush_mclist(sk);
|
|
|
|
|
|
@@ -1291,10 +1289,10 @@ static int packet_release(struct socket *sock)
|
|
if (po->tx_ring.pg_vec)
|
|
if (po->tx_ring.pg_vec)
|
|
packet_set_ring(sk, &req, 1, 1);
|
|
packet_set_ring(sk, &req, 1, 1);
|
|
|
|
|
|
|
|
+ synchronize_net();
|
|
/*
|
|
/*
|
|
* Now the socket is dead. No more input will appear.
|
|
* Now the socket is dead. No more input will appear.
|
|
*/
|
|
*/
|
|
-
|
|
|
|
sock_orphan(sk);
|
|
sock_orphan(sk);
|
|
sock->sk = NULL;
|
|
sock->sk = NULL;
|
|
|
|
|
|
@@ -1478,10 +1476,11 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
|
|
po->running = 1;
|
|
po->running = 1;
|
|
}
|
|
}
|
|
|
|
|
|
- write_lock_bh(&net->packet.sklist_lock);
|
|
|
|
- sk_add_node(sk, &net->packet.sklist);
|
|
|
|
|
|
+ spin_lock_bh(&net->packet.sklist_lock);
|
|
|
|
+ sk_add_node_rcu(sk, &net->packet.sklist);
|
|
sock_prot_inuse_add(net, &packet_proto, 1);
|
|
sock_prot_inuse_add(net, &packet_proto, 1);
|
|
- write_unlock_bh(&net->packet.sklist_lock);
|
|
|
|
|
|
+ spin_unlock_bh(&net->packet.sklist_lock);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
out:
|
|
out:
|
|
return err;
|
|
return err;
|
|
@@ -2075,8 +2074,8 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
|
|
struct net_device *dev = data;
|
|
struct net_device *dev = data;
|
|
struct net *net = dev_net(dev);
|
|
struct net *net = dev_net(dev);
|
|
|
|
|
|
- read_lock(&net->packet.sklist_lock);
|
|
|
|
- sk_for_each(sk, node, &net->packet.sklist) {
|
|
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+ sk_for_each_rcu(sk, node, &net->packet.sklist) {
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
|
|
|
|
switch (msg) {
|
|
switch (msg) {
|
|
@@ -2104,18 +2103,19 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case NETDEV_UP:
|
|
case NETDEV_UP:
|
|
- spin_lock(&po->bind_lock);
|
|
|
|
- if (dev->ifindex == po->ifindex && po->num &&
|
|
|
|
- !po->running) {
|
|
|
|
- dev_add_pack(&po->prot_hook);
|
|
|
|
- sock_hold(sk);
|
|
|
|
- po->running = 1;
|
|
|
|
|
|
+ if (dev->ifindex == po->ifindex) {
|
|
|
|
+ spin_lock(&po->bind_lock);
|
|
|
|
+ if (po->num && !po->running) {
|
|
|
|
+ dev_add_pack(&po->prot_hook);
|
|
|
|
+ sock_hold(sk);
|
|
|
|
+ po->running = 1;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&po->bind_lock);
|
|
}
|
|
}
|
|
- spin_unlock(&po->bind_lock);
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- read_unlock(&net->packet.sklist_lock);
|
|
|
|
|
|
+ rcu_read_unlock();
|
|
return NOTIFY_DONE;
|
|
return NOTIFY_DONE;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2512,24 +2512,24 @@ static struct notifier_block packet_netdev_notifier = {
|
|
#ifdef CONFIG_PROC_FS
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
|
|
static void *packet_seq_start(struct seq_file *seq, loff_t *pos)
|
|
static void *packet_seq_start(struct seq_file *seq, loff_t *pos)
|
|
- __acquires(seq_file_net(seq)->packet.sklist_lock)
|
|
|
|
|
|
+ __acquires(RCU)
|
|
{
|
|
{
|
|
struct net *net = seq_file_net(seq);
|
|
struct net *net = seq_file_net(seq);
|
|
- read_lock(&net->packet.sklist_lock);
|
|
|
|
- return seq_hlist_start_head(&net->packet.sklist, *pos);
|
|
|
|
|
|
+
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+ return seq_hlist_start_head_rcu(&net->packet.sklist, *pos);
|
|
}
|
|
}
|
|
|
|
|
|
static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
{
|
|
{
|
|
struct net *net = seq_file_net(seq);
|
|
struct net *net = seq_file_net(seq);
|
|
- return seq_hlist_next(v, &net->packet.sklist, pos);
|
|
|
|
|
|
+ return seq_hlist_next_rcu(v, &net->packet.sklist, pos);
|
|
}
|
|
}
|
|
|
|
|
|
static void packet_seq_stop(struct seq_file *seq, void *v)
|
|
static void packet_seq_stop(struct seq_file *seq, void *v)
|
|
- __releases(seq_file_net(seq)->packet.sklist_lock)
|
|
|
|
|
|
+ __releases(RCU)
|
|
{
|
|
{
|
|
- struct net *net = seq_file_net(seq);
|
|
|
|
- read_unlock(&net->packet.sklist_lock);
|
|
|
|
|
|
+ rcu_read_unlock();
|
|
}
|
|
}
|
|
|
|
|
|
static int packet_seq_show(struct seq_file *seq, void *v)
|
|
static int packet_seq_show(struct seq_file *seq, void *v)
|
|
@@ -2581,7 +2581,7 @@ static const struct file_operations packet_seq_fops = {
|
|
|
|
|
|
static int __net_init packet_net_init(struct net *net)
|
|
static int __net_init packet_net_init(struct net *net)
|
|
{
|
|
{
|
|
- rwlock_init(&net->packet.sklist_lock);
|
|
|
|
|
|
+ spin_lock_init(&net->packet.sklist_lock);
|
|
INIT_HLIST_HEAD(&net->packet.sklist);
|
|
INIT_HLIST_HEAD(&net->packet.sklist);
|
|
|
|
|
|
if (!proc_net_fops_create(net, "packet", 0, &packet_seq_fops))
|
|
if (!proc_net_fops_create(net, "packet", 0, &packet_seq_fops))
|