Subject: Re: Kernel panic in inet_twdr_do_twkill_work

From: Daniel Lezcano <[email-masked]>
Date: Thu, 14 May 2009 11:42:02 +0200

Eric W. Biederman wrote:
> Daniel Lezcano <[email-masked]> writes:
>
>   
>> May be you can activate the NETNS_REFCNT_DEBUG in order to check if the timewait
>> socket
>> were destroyed at the namespace destruction ? Unfortunately it looks like the
>> option is not in the Kconfig :(
>>     
>
> Looks like a good starting place.
>
> I will enable that when I respin my internal kernel.
>
> I don't have a good reproducer at the moment....  So I was hoping we could
> figure this out with code inspection.
>   
I found this one which makes a lot of timewait sockets. I tried on a 
2.6.29 kernel and I was not able to reproduce it. Can you check if this 
program reproduce the bug ?
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#include <unistd.h>

#define MAXCONN 10000

int client(int *fds)
{
	int i, len;
	struct sockaddr_in6 addr;

	close(fds[1]);

	memset(&addr, 0, sizeof(addr));

        addr.sin6_family = AF_INET6;
        addr.sin6_port = htons(10000);
        addr.sin6_addr = in6addr_loopback;

	if (read(fds[0], &i, sizeof(i)) == -1) {
		perror("read");
		return 1;
	}

	for (i = 0; i < MAXCONN; i++) {
		int fd = socket(PF_INET6, SOCK_STREAM, 0);
		if (fd == -1) {
			perror("socket");
			return 1;
		}

		if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr))) {
			perror("connect");
			return 1;
		}
		
		len = write(fd, &fd, sizeof(fd));
		if (!len) {
			fprintf(stderr, "write wrote 0 bytes\n");
			return 1;
		}
		if (len == -1) {
			perror("write");
			return 1;
		}
	}

	return 0;
}

int server(int *fds)
{
	int i, fd, fdpoll[MAXCONN];
	struct sockaddr_in6 addr;
	socklen_t socklen = sizeof(addr);

	close(fds[0]);

	fd = socket(PF_INET6, SOCK_STREAM, 0);
	if (fd == -1) {
		perror("socket");
		return 1;
	}

	memset(&addr, 0, sizeof(addr));

        addr.sin6_family = AF_INET6;
        addr.sin6_port = htons(10000);
        addr.sin6_addr = in6addr_loopback;
	
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &fd, sizeof(fd))) {
		perror("setsockopt");
		return 1;
	}

	if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr))) {
		perror("bind");
		return 1;
	}

	if (listen(fd, MAXCONN)) {
		perror("listen");
		return 1;
	}
	
	if (write(fds[1], &i, sizeof(i)) == -1) {
		perror("write");
		return 1;
	}

	for (i = 0; i < MAXCONN; i++) {
		int len, f = accept(fd, (struct sockaddr *)&addr, &socklen);
		if (f == -1) {
			perror("accept");
			return 1;
		}
		fdpoll[i] = f;

		len = read(f, &f, sizeof(f)); 
		if (!len) {
			fprintf(stderr, "read readen 0 bytes\n");
			return 1;
		}
		if (len == -1) {
			perror("read");
			return 1;
		}
	}

	return 0;
}

int main(int argc, char *argv[])
{
	int fds[2];
	int pid;

	if (pipe(fds)) {
		perror("pipe");
		return 1;
	}

	pid = fork();
	if (pid == -1) {
		perror("fork");
		return 1;
	}

	if (!pid) 
		return client(fds);
	else 
		return server(fds);
}