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

Commit 26abe143 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller
Browse files

net: Modify sk_alloc to not reference count the netns of kernel sockets.



Now that sk_alloc knows when a kernel socket is being allocated modify
it to not reference count the network namespace of kernel sockets.

Keep track of if a socket needs reference counting by adding a flag to
struct sock called sk_net_refcnt.

Update all of the callers of sock_create_kern to stop using
sk_change_net and sk_release_kernel as those hacks are no longer
needed, to avoid reference counting a kernel socket.

Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 11aa9c28
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ int inet_recv_error(struct sock *sk, struct msghdr *msg, int len,

static inline void inet_ctl_sock_destroy(struct sock *sk)
{
	sk_release_kernel(sk);
	sock_release(sk->sk_socket);
}

#endif
+2 −0
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ struct sock_common {
	unsigned char		skc_reuse:4;
	unsigned char		skc_reuseport:1;
	unsigned char		skc_ipv6only:1;
	unsigned char		skc_net_refcnt:1;
	int			skc_bound_dev_if;
	union {
		struct hlist_node	skc_bind_node;
@@ -323,6 +324,7 @@ struct sock {
#define sk_reuse		__sk_common.skc_reuse
#define sk_reuseport		__sk_common.skc_reuseport
#define sk_ipv6only		__sk_common.skc_ipv6only
#define sk_net_refcnt		__sk_common.skc_net_refcnt
#define sk_bound_dev_if		__sk_common.skc_bound_dev_if
#define sk_bind_node		__sk_common.skc_bind_node
#define sk_prot			__sk_common.skc_prot
+6 −2
Original line number Diff line number Diff line
@@ -1412,7 +1412,10 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
		 */
		sk->sk_prot = sk->sk_prot_creator = prot;
		sock_lock_init(sk);
		sock_net_set(sk, get_net(net));
		sk->sk_net_refcnt = kern ? 0 : 1;
		if (likely(sk->sk_net_refcnt))
			get_net(net);
		sock_net_set(sk, net);
		atomic_set(&sk->sk_wmem_alloc, 1);

		sock_update_classid(sk);
@@ -1446,6 +1449,7 @@ static void __sk_free(struct sock *sk)
	if (sk->sk_peer_cred)
		put_cred(sk->sk_peer_cred);
	put_pid(sk->sk_peer_pid);
	if (likely(sk->sk_net_refcnt))
		put_net(sock_net(sk));
	sk_prot_free(sk->sk_prot_creator, sk);
}
+1 −3
Original line number Diff line number Diff line
@@ -1430,7 +1430,7 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family,
			 struct net *net)
{
	struct socket *sock;
	int rc = sock_create_kern(&init_net, family, type, protocol, &sock);
	int rc = sock_create_kern(net, family, type, protocol, &sock);

	if (rc == 0) {
		*sk = sock->sk;
@@ -1440,8 +1440,6 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family,
		 * we do not wish this socket to see incoming packets.
		 */
		(*sk)->sk_prot->unhash(*sk);

		sk_change_net(*sk, net);
	}
	return rc;
}
+3 −5
Original line number Diff line number Diff line
@@ -15,12 +15,10 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
	struct socket *sock = NULL;
	struct sockaddr_in udp_addr;

	err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &sock);
	err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
	if (err < 0)
		goto error;

	sk_change_net(sock->sk, net);

	udp_addr.sin_family = AF_INET;
	udp_addr.sin_addr = cfg->local_ip;
	udp_addr.sin_port = cfg->local_udp_port;
@@ -47,7 +45,7 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
error:
	if (sock) {
		kernel_sock_shutdown(sock, SHUT_RDWR);
		sk_release_kernel(sock->sk);
		sock_release(sock);
	}
	*sockp = NULL;
	return err;
@@ -101,7 +99,7 @@ void udp_tunnel_sock_release(struct socket *sock)
{
	rcu_assign_sk_user_data(sock->sk, NULL);
	kernel_sock_shutdown(sock, SHUT_RDWR);
	sk_release_kernel(sock->sk);
	sock_release(sock);
}
EXPORT_SYMBOL_GPL(udp_tunnel_sock_release);

Loading