Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fff0bbb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "packet: Do not call fanout_release from atomic contexts"

parents e2439200 55c0685b
Loading
Loading
Loading
Loading
+24 −8
Original line number Diff line number Diff line
@@ -1380,6 +1380,8 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po)
	f->arr[f->num_members] = sk;
	smp_wmb();
	f->num_members++;
	if (f->num_members == 1)
		dev_add_pack(&f->prot_hook);
	spin_unlock(&f->lock);
}

@@ -1396,6 +1398,8 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
	BUG_ON(i >= f->num_members);
	f->arr[i] = f->arr[f->num_members - 1];
	f->num_members--;
	if (f->num_members == 0)
		__dev_remove_pack(&f->prot_hook);
	spin_unlock(&f->lock);
}

@@ -1468,7 +1472,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
		match->prot_hook.func = packet_rcv_fanout;
		match->prot_hook.af_packet_priv = match;
		match->prot_hook.id_match = match_fanout_group;
		dev_add_pack(&match->prot_hook);
		list_add(&match->list, &fanout_list);
	}
	err = -EINVAL;
@@ -1489,7 +1492,14 @@ out:
	return err;
}

static void fanout_release(struct sock *sk)
/* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes
 * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout.
 * It is the responsibility of the caller to free the returned packet_fanout 
 * (after synchronize_net())
 * This Branch still does not have support classic BPF fanout mode.
 *  upstream commit 47dceb8ecdc: packet: add classic BPF fanout mode
 */
static struct packet_fanout *fanout_release(struct sock *sk)
{
	struct packet_sock *po = pkt_sk(sk);
	struct packet_fanout *f;
@@ -1499,13 +1509,15 @@ static void fanout_release(struct sock *sk)
	if (f) {
		po->fanout = NULL;

		if (atomic_dec_and_test(&f->sk_ref)) {
		if (atomic_dec_and_test(&f->sk_ref))
			list_del(&f->list);
			dev_remove_pack(&f->prot_hook);
			kfree(f);
		}
		else
			f = NULL;

	}
	mutex_unlock(&fanout_mutex);

	return f;
}

static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
@@ -2587,6 +2599,7 @@ static int packet_release(struct socket *sock)
{
	struct sock *sk = sock->sk;
	struct packet_sock *po;
	struct packet_fanout *f;
	struct net *net;
	union tpacket_req_u req_u;

@@ -2626,9 +2639,13 @@ static int packet_release(struct socket *sock)
		packet_set_ring(sk, &req_u, 1, 1);
	}

	fanout_release(sk);
	f = fanout_release(sk);

	synchronize_net();

	if (f)
		kfree(f);

	/*
	 *	Now the socket is dead. No more input will appear.
	 */
@@ -3567,7 +3584,6 @@ static int packet_notifier(struct notifier_block *this,
				}
				if (msg == NETDEV_UNREGISTER) {
					packet_cached_dev_reset(po);
					fanout_release(sk);
					po->ifindex = -1;
					if (po->prot_hook.dev)
						dev_put(po->prot_hook.dev);