diff --git a/Makefile.am b/Makefile.am
index fb380f8..105ae72 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,7 @@ bin_PROGRAMS = nbd-server nbd-trdump
 sbin_PROGRAMS = @NBD_CLIENT_NAME@
 EXTRA_PROGRAMS = nbd-client make-integrityhuge
 TESTS_ENVIRONMENT=$(srcdir)/simple_test
-TESTS = cmd cfg1 cfgmulti cfgnew cfgsize write flush integrity dirconfig #integrityhuge
+TESTS = cmd cfg1 cfgmulti cfgnew cfgsize write flush integrity dirconfig list #integrityhuge
 check_PROGRAMS = nbd-tester-client
 nbd_client_SOURCES = nbd-client.c cliserv.h
 nbd_server_SOURCES = nbd-server.c cliserv.h lfs.h nbd.h
@@ -28,3 +28,4 @@ flush:
 integrity:
 integrityhuge:
 dirconfig:
+list:
diff --git a/configure.ac b/configure.ac
index 0a867df..e11f4fd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 dnl Configure script for NBD system
 dnl (c) 1998 Martin Mares <mj@ucw.cz>, (c) 2000 Pavel Machek <pavel@ucw.cz>,
 dnl (c) 2003-2006 Wouter Verhelst <wouter@debian.org>
-AC_INIT([nbd],[3.1.1],[wouter@debian.org])
+AC_INIT([nbd],[3.2],[wouter@debian.org])
 AM_INIT_AUTOMAKE(foreign dist-bzip2)
 AM_MAINTAINER_MODE
 
diff --git a/man/nbd-client.8.in.sgml b/man/nbd-client.8.in.sgml
index b375dd0..8c862a1 100644
--- a/man/nbd-client.8.in.sgml
+++ b/man/nbd-client.8.in.sgml
@@ -201,7 +201,7 @@ manpage.1: manpage.sgml
 	<term><option>-S</option></term>
 	<listitem>
 	  <para>Connect to the server using the Socket Direct Protocol
-	    (SDP), rather than IP. See nbd-server(1) for details.
+	    (SDP), rather than IP. See nbd-server(5) for details.
 	  </para>
 	</listitem>
       </varlistentry>
@@ -211,8 +211,9 @@ manpage.1: manpage.sgml
 	<listitem>
 	  <para>Specifies that this NBD device will be used as
 	  swapspace. This option attempts to prevent deadlocks by
-	  performing mlockall() at an appropriate time. It does not
-	  however guarantee that such deadlocks can be avoided.</para>
+	  performing mlockall() and adjusting the oom-killer score
+	  at an appropriate time. It does not however guarantee
+	  that such deadlocks can be avoided.</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
diff --git a/nbd-client.c b/nbd-client.c
index 7a526b9..d20f32c 100644
--- a/nbd-client.c
+++ b/nbd-client.c
@@ -35,6 +35,7 @@
 #include <stdlib.h>
 #include <sys/mount.h>
 #include <sys/mman.h>
+#include <signal.h>
 #include <errno.h>
 #include <getopt.h>
 #include <stdarg.h>
@@ -94,7 +95,7 @@ int opennet(char *name, char* portstr, int sdp) {
 	if(e != 0) {
 		fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
 		freeaddrinfo(ai);
-		exit(EXIT_FAILURE);
+		return -1;
 	}
 
 	if(sdp) {
@@ -118,8 +119,10 @@ int opennet(char *name, char* portstr, int sdp) {
 			break;		/* success */
 	}
 
-	if (rp == NULL)
-		err("Socket failed: %m");
+	if (rp == NULL) {
+		err_nonfatal("Socket failed: %m");
+		return -1;
+	}
 
 	setmysockopt(sock);
 
@@ -371,6 +374,21 @@ void finish_sock(int sock, int nbd, int swap) {
 		mlockall(MCL_CURRENT | MCL_FUTURE);
 }
 
+static int
+oom_adjust(const char *file, const char *value)
+{
+	int fd, rc;
+	size_t len;
+
+	fd = open(file, O_WRONLY);
+	if (fd < 0)
+		return -1;
+	len = strlen(value);
+	rc = write(fd, value, len) != (ssize_t) len;
+	close(fd);
+	return rc ? -1 : 0;
+}
+
 void usage(char* errmsg, ...) {
 	if(errmsg) {
 		char tmp[256];
@@ -550,6 +568,8 @@ int main(int argc, char *argv[]) {
 	}
 
 	sock = opennet(hostname, port, sdp);
+	if (sock < 0)
+		exit(EXIT_FAILURE);
 
 	negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
 
@@ -560,6 +580,13 @@ int main(int argc, char *argv[]) {
 	setsizes(nbd, size64, blocksize, flags);
 	set_timeout(nbd, timeout);
 	finish_sock(sock, nbd, swap);
+	if (swap) {
+		/* try linux >= 2.6.36 interface first */
+		if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
+			/* fall back to linux <= 2.6.35 interface */
+			oom_adjust("/proc/self/oom_adj", "-17");
+		}
+	}
 
 	/* Go daemon */
 	
@@ -571,6 +598,16 @@ int main(int argc, char *argv[]) {
 #endif
 	do {
 #ifndef NOFORK
+#ifdef SA_NOCLDWAIT
+		struct sigaction sa;
+
+		sa.sa_handler = SIG_DFL;
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = SA_NOCLDWAIT;
+		if (sigaction(SIGCHLD, &sa, NULL) < 0)
+			err("sigaction: %m");
+#endif
+
 		if (!fork()) {
 			/* Due to a race, the kernel NBD driver cannot
 			 * call for a reread of the partition table
@@ -603,10 +640,17 @@ int main(int argc, char *argv[]) {
 					u64 new_size;
 					u32 new_flags;
 
-					fprintf(stderr, " Reconnecting\n");
 					close(sock); close(nbd);
-					sock = opennet(hostname, port, sdp);
+					for (;;) {
+						fprintf(stderr, " Reconnecting\n");
+						sock = opennet(hostname, port, sdp);
+						if (sock >= 0)
+							break;
+						sleep (1);
+					}
 					nbd = open(nbddev, O_RDWR);
+					if (nbd < 0)
+						err("Cannot open NBD: %m");
 					negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
 					if (size64 != new_size) {
 						err("Size of the device changed. Bye");
diff --git a/nbd-server.c b/nbd-server.c
index a8f4f40..49822a7 100644
--- a/nbd-server.c
+++ b/nbd-server.c
@@ -185,7 +185,7 @@ char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of a
 #define NEG_OLD		(1 << 1)
 #define NEG_MODERN	(1 << 2)
 
-int modernsock=0;	  /**< Socket for the modern handler. Not used
+int modernsock=-1;	  /**< Socket for the modern handler. Not used
 			       if a client was only specified on the
 			       command line; only port used if
 			       oldstyle is set to false (and then the
@@ -803,7 +803,7 @@ GArray* do_cfile_dir(gchar* dir, GError** e) {
 			case DT_REG:
 				/* Skip unless the name ends with '.conf' */
 				if(strcmp((de->d_name + strlen(de->d_name) - 5), ".conf")) {
-					continue;
+					goto next;
 				}
 				tmp = parse_cfile(fname, FALSE, e);
 				errno=saved_errno;
@@ -1087,10 +1087,8 @@ void sigchld_handler(int s) {
  **/
 void killchild(gpointer key, gpointer value, gpointer user_data) {
 	pid_t *pid=value;
-	int *parent=user_data;
 
 	kill(*pid, SIGTERM);
-	*parent=1;
 }
 
 /**
@@ -1099,13 +1097,8 @@ void killchild(gpointer key, gpointer value, gpointer user_data) {
  * is severely wrong).
  **/
 void sigterm_handler(int s) {
-	int parent=0;
-
-	g_hash_table_foreach(children, killchild, &parent);
-
-	if(parent) {
-		unlink(pidfname);
-	}
+	g_hash_table_foreach(children, killchild, NULL);
+	unlink(pidfname);
 
 	exit(EXIT_SUCCESS);
 }
@@ -2062,8 +2055,9 @@ void serveconnection(CLIENT *client) {
  * @param client information about the client. The IP address in human-readable
  * format will be written to a new char* buffer, the address of which will be
  * stored in client->clientname.
+ * @return: 0 - OK, -1 - failed.
  **/
-void set_peername(int net, CLIENT *client) {
+int set_peername(int net, CLIENT *client) {
 	struct sockaddr_storage addrin;
 	struct sockaddr_storage netaddr;
 	struct sockaddr_in  *netaddr4 = NULL;
@@ -2078,13 +2072,15 @@ void set_peername(int net, CLIENT *client) {
 	int e;
 	int shift;
 
-	if (getpeername(net, (struct sockaddr *) &addrin, &addrinlen) < 0)
-		err("getpeername failed: %m");
+	if (getpeername(net, (struct sockaddr *) &addrin, &addrinlen) < 0) {
+		msg2(LOG_INFO, "getpeername failed: %m");
+		return -1;
+	}
 
 	if((e = getnameinfo((struct sockaddr *)&addrin, addrinlen,
 			peername, sizeof (peername), NULL, 0, NI_NUMERICHOST))) {
 		msg3(LOG_INFO, "getnameinfo failed: %s", gai_strerror(e));
-		freeaddrinfo(ai);
+		return -1;
 	}
 
 	memset(&hints, '\0', sizeof (hints));
@@ -2094,23 +2090,27 @@ void set_peername(int net, CLIENT *client) {
 	if(e != 0) {
 		msg3(LOG_INFO, "getaddrinfo failed: %s", gai_strerror(e));
 		freeaddrinfo(ai);
-		return;
+		return -1;
 	}
 
 	switch(client->server->virtstyle) {
 		case VIRT_NONE:
+			msg2(LOG_DEBUG, "virtualization is off");
 			client->exportname=g_strdup(client->server->exportname);
 			break;
 		case VIRT_IPHASH:
+			msg2(LOG_DEBUG, "virtstyle iphash");
 			for(i=0;i<strlen(peername);i++) {
 				if(peername[i]=='.') {
 					peername[i]='/';
 				}
 			}
 		case VIRT_IPLIT:
+			msg2(LOG_DEBUG, "virststyle ipliteral");
 			client->exportname=g_strdup_printf(client->server->exportname, peername);
 			break;
 		case VIRT_CIDR:
+			msg3(LOG_DEBUG, "virtstyle cidr %d", client->server->cidrlen);
 			memcpy(&netaddr, &addrin, addrinlen);
 			if(ai->ai_family == AF_INET) {
 				netaddr4 = (struct sockaddr_in *)&netaddr;
@@ -2148,6 +2148,7 @@ void set_peername(int net, CLIENT *client) {
 	msg4(LOG_INFO, "connect from %s, assigned file is %s", 
 	     peername, client->exportname);
 	client->clientname=g_strdup(peername);
+	return 0;
 }
 
 /**
@@ -2158,6 +2159,95 @@ void destroy_pid_t(gpointer data) {
 	g_free(data);
 }
 
+static void
+handle_connection(GArray *servers, int net, SERVER *serve, CLIENT *client)
+{
+	int sock_flags_old;
+	int sock_flags_new;
+
+	if(serve->max_connections > 0 &&
+	   g_hash_table_size(children) >= serve->max_connections) {
+		msg2(LOG_INFO, "Max connections reached");
+		goto handle_connection_out;
+	}
+	if((sock_flags_old = fcntl(net, F_GETFL, 0)) == -1) {
+		err("fcntl F_GETFL");
+	}
+	sock_flags_new = sock_flags_old & ~O_NONBLOCK;
+	if (sock_flags_new != sock_flags_old &&
+	    fcntl(net, F_SETFL, sock_flags_new) == -1) {
+		err("fcntl F_SETFL ~O_NONBLOCK");
+	}
+	if(!client) {
+		client = g_new0(CLIENT, 1);
+		client->server=serve;
+		client->exportsize=OFFT_MAX;
+		client->net=net;
+		client->transactionlogfd = -1;
+	}
+	if (set_peername(net, client)) {
+		goto handle_connection_out;
+	}
+	if (!authorized_client(client)) {
+		msg2(LOG_INFO,"Unauthorized client") ;
+		goto handle_connection_out;
+	}
+	msg2(LOG_INFO,"Authorized client") ;
+
+	if (!dontfork) {
+		pid_t pid;
+		int i;
+		sigset_t newset;
+		sigset_t oldset;
+
+		sigemptyset(&newset);
+		sigaddset(&newset, SIGCHLD);
+		sigaddset(&newset, SIGTERM);
+		sigprocmask(SIG_BLOCK, &newset, &oldset);
+		if ((pid = fork()) < 0) {
+			msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
+			sigprocmask(SIG_SETMASK, &oldset, NULL);
+			goto handle_connection_out;
+		}
+		if (pid > 0) { /* parent */
+			pid_t *pidp;
+
+			pidp = g_malloc(sizeof(pid_t));
+			*pidp = pid;
+			g_hash_table_insert(children, pidp, pidp);
+			sigprocmask(SIG_SETMASK, &oldset, NULL);
+			goto handle_connection_out;
+		}
+		/* child */
+		signal(SIGCHLD, SIG_DFL);
+		signal(SIGTERM, SIG_DFL);
+		sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+		g_hash_table_destroy(children);
+		children = NULL;
+		for(i=0;i<servers->len;i++) {
+			serve=&g_array_index(servers, SERVER, i);
+			close(serve->socket);
+		}
+		/* FALSE does not free the
+		   actual data. This is required,
+		   because the client has a
+		   direct reference into that
+		   data, and otherwise we get a
+		   segfault... */
+		g_array_free(servers, FALSE);
+		close(modernsock);
+	}
+
+	msg2(LOG_INFO,"Starting to serve");
+	serveconnection(client);
+	exit(EXIT_SUCCESS);
+
+handle_connection_out:
+	g_free(client);
+	close(net);
+}
+
 /**
  * Loop through the available servers, and serve them. Never returns.
  **/
@@ -2185,99 +2275,42 @@ int serveloop(GArray* servers) {
 			max=sock>max?sock:max;
 		}
 	}
-	if(modernsock) {
+	if(modernsock >= 0) {
 		FD_SET(modernsock, &mset);
 		max=modernsock>max?modernsock:max;
 	}
 	for(;;) {
-		CLIENT *client = NULL;
-		pid_t *pid;
-
 		memcpy(&rset, &mset, sizeof(fd_set));
 		if(select(max+1, &rset, NULL, NULL, NULL)>0) {
-			int net = 0;
-			SERVER* serve=NULL;
+			int net;
 
 			DEBUG("accept, ");
-			if(FD_ISSET(modernsock, &rset)) {
-				if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
-					err("accept: %m");
+			if(modernsock >= 0 && FD_ISSET(modernsock, &rset)) {
+				CLIENT *client;
+
+				if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0) {
+					err_nonfatal("accept: %m");
+					continue;
+				}
 				client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
 				if(!client) {
 					err_nonfatal("negotiation failed");
 					close(net);
-					net=0;
 					continue;
 				}
-				serve = client->server;
+				handle_connection(servers, net, client->server, client);
 			}
-			for(i=0;i<servers->len && !net;i++) {
+			for(i=0; i < servers->len; i++) {
+				SERVER *serve;
+
 				serve=&(g_array_index(servers, SERVER, i));
 				if(FD_ISSET(serve->socket, &rset)) {
-					if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
-						err("accept: %m");
-				}
-			}
-			if(net) {
-				int sock_flags;
-
-				if(serve->max_connections > 0 &&
-				   g_hash_table_size(children) >= serve->max_connections) {
-					msg2(LOG_INFO, "Max connections reached");
-					close(net);
-					continue;
-				}
-				if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
-					err("fcntl F_GETFL");
-				}
-				if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
-					err("fcntl F_SETFL ~O_NONBLOCK");
-				}
-				if(!client) {
-					client = g_new0(CLIENT, 1);
-					client->server=serve;
-					client->exportsize=OFFT_MAX;
-					client->net=net;
-					client->transactionlogfd = -1;
-				}
-				set_peername(net, client);
-				if (!authorized_client(client)) {
-					msg2(LOG_INFO,"Unauthorized client") ;
-					close(net);
-					continue;
-				}
-				msg2(LOG_INFO,"Authorized client") ;
-				pid=g_malloc(sizeof(pid_t));
-
-				if (!dontfork) {
-					if ((*pid=fork())<0) {
-						msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
-						close(net);
+					if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0) {
+						err_nonfatal("accept: %m");
 						continue;
 					}
-					if (*pid>0) { /* parent */
-						close(net);
-						g_hash_table_insert(children, pid, pid);
-						continue;
-					}
-					/* child */
-					g_hash_table_destroy(children);
-					for(i=0;i<servers->len;i++) {
-						serve=&g_array_index(servers, SERVER, i);
-						close(serve->socket);
-					}
-					/* FALSE does not free the
-					   actual data. This is required,
-					   because the client has a
-					   direct reference into that
-					   data, and otherwise we get a
-					   segfault... */
-					g_array_free(servers, FALSE);
+					handle_connection(servers, net, serve, NULL);
 				}
-
-				msg2(LOG_INFO,"Starting to serve");
-				serveconnection(client);
-				exit(EXIT_SUCCESS);
 			}
 		}
 	}
@@ -2432,11 +2465,14 @@ void setup_servers(GArray* servers) {
 
 	sa.sa_handler = sigchld_handler;
 	sigemptyset(&sa.sa_mask);
+	sigaddset(&sa.sa_mask, SIGTERM);
 	sa.sa_flags = SA_RESTART;
 	if(sigaction(SIGCHLD, &sa, NULL) == -1)
 		err("sigaction: %m");
+
 	sa.sa_handler = sigterm_handler;
 	sigemptyset(&sa.sa_mask);
+	sigaddset(&sa.sa_mask, SIGCHLD);
 	sa.sa_flags = SA_RESTART;
 	if(sigaction(SIGTERM, &sa, NULL) == -1)
 		err("sigaction: %m");
@@ -2594,9 +2630,10 @@ int main(int argc, char *argv[]) {
 #endif
 			client=g_malloc(sizeof(CLIENT));
 			client->server=serve;
-			client->net=0;
+			client->net=-1;
 			client->exportsize=OFFT_MAX;
-			set_peername(0,client);
+			if (set_peername(0, client))
+				exit(EXIT_FAILURE);
 			serveconnection(client);
 			return 0;
 		}
diff --git a/simple_test b/simple_test
index fcaed0f..26572a6 100755
--- a/simple_test
+++ b/simple_test
@@ -7,6 +7,8 @@ pidfile=${tmpdir}/nbd.pid
 tmpnam=${tmpdir}/nbd.dd
 mydir=$(dirname "`readlink -f $0`")
 
+set -e
+
 ulimit -c unlimited
 
 # Create a one-meg device
@@ -184,6 +186,30 @@ EOF
 		./nbd-tester-client localhost -N export1 -i -t ${mydir}/integrityhuge-test.tr
 		retval=$?
 	;;
+	*/list)
+		# List exports
+		# This only works if we built nbd-client, which only exists on
+		# Linux. But hey, testing nbd-client itself isn't a bad idea,
+		# so here goes.
+		if [ `uname -s` != "Linux" ]
+		then
+			retval=77
+		else
+			cat >${conffile} <<EOF
+[generic]
+	listenaddr = 127.0.0.1
+	allowlist = true
+[export1]
+	exportname = $tmpnam
+	readonly = true
+EOF
+			./nbd-server -C ${conffile} -p ${pidfile} &
+			PID=$!
+			sleep 1
+			./nbd-client -l localhost
+			retval=$?
+		fi
+		;;
 	*)
 		echo "E: unknown test $1"
 		exit 1
@@ -193,7 +219,10 @@ if [ -f ${pidfile} ]
 then
 	kill `cat ${pidfile}`
 else
-	kill $PID
+	if [ ! -z "$PID" ]
+	then
+		kill $PID
+	fi
 fi
 if [ -z "$2" ]
 then
