diff --git a/src/io.c b/src/io.c
index a75b71024f560788f1f9d8f79cff1c9101c5a65a..9951ddd8e5cc9251d53ba07b2f10abb5737a1774 100644
--- a/src/io.c
+++ b/src/io.c
@@ -99,7 +99,11 @@ static void close_fd(struct io_fd *fd)
     (void) CLOSE_CALLBACK(fd->close_callback, fd->close_reason);
   
   close(fd->fd);
-	      
+
+  /* Make sure writing to the buffer fails. */
+  if (fd->buffer)
+    write_buffer_close(fd->buffer);
+  
   /* There can be other objects around that may still
    * attempt to write to the buffer. So let gc handle it
    * instead of freeing it explicitly */
@@ -532,6 +536,22 @@ void io_set_nonblocking(int fd)
     fatal("io_set_nonblocking: fcntl() failed, %s", strerror(errno));
 }
 
+void io_set_close_on_exec(int fd)
+{
+  if (fcntl(fd, F_SETFD, 1) < 0)
+    fatal("Can't set close-on-exec flag for fd %d: %s\n",
+	  fd, strerror(errno));
+}
+
+/* ALL file descripters handled by the backend should use non-blocking mode,
+ * and have the close-on-exec flag set. */
+
+void io_init_fd(int fd)
+{
+  io_set_nonblocking(fd);
+  io_set_close_on_exec(fd);
+}
+
 /* Some code is taken from bellman's tcputils. */
 struct connect_fd *io_connect(struct io_backend *b,
 			      struct sockaddr_in *remote,
@@ -544,7 +564,7 @@ struct connect_fd *io_connect(struct io_backend *b,
   if (s<0)
     return NULL;
 
-  io_set_nonblocking(s);
+  io_init_fd(s);
 
   if (local  &&  bind(s, (struct sockaddr *)local, sizeof *local) < 0)
     {
@@ -585,7 +605,7 @@ struct listen_fd *io_listen(struct io_backend *b,
   if (s<0)
     return NULL;
 
-  io_set_nonblocking(s);
+  io_init_fd(s);
 
   {
     int yes = 1;
@@ -625,6 +645,8 @@ struct abstract_write *io_read_write(struct io_backend *b,
   struct io_fd *f;
   struct write_buffer *buffer = write_buffer_alloc(block_size);
 
+  io_init_fd(fd);
+  
   NEW(f);
   f->fd = fd;
   
@@ -653,6 +675,8 @@ struct io_fd *io_read(struct io_backend *b,
 {
   struct io_fd *f;
 
+  io_init_fd(fd);
+
   NEW(f);
   f->fd = fd;
   
@@ -675,14 +699,16 @@ struct io_fd *io_read(struct io_backend *b,
   return f;
 }
 
-struct abstract_write *io_write(struct io_backend *b,
-				int fd,
-				UINT32 block_size,
-				struct close_callback *close_callback)
+struct io_fd *io_write(struct io_backend *b,
+		       int fd,
+		       UINT32 block_size,
+		       struct close_callback *close_callback)
 {
   struct io_fd *f;
   struct write_buffer *buffer = write_buffer_alloc(block_size);
 
+  io_init_fd(fd);
+  
   NEW(f);
   f->fd = fd;
   
@@ -700,6 +726,5 @@ struct abstract_write *io_write(struct io_backend *b,
   b->io = f;
   b->nio++;
 
-  return &buffer->super;
+  return f;
 }
-     
diff --git a/src/io.h b/src/io.h
index 35f592ac43201fbf589be06aae2ad6ea3c7c129d..4fbfd3bd9db560ea7579a37aa73f0ec1598cacb8 100644
--- a/src/io.h
+++ b/src/io.h
@@ -128,6 +128,8 @@ int get_inaddr(struct sockaddr_in	* addr,
 	       const char		* protocol);
 
 void io_set_nonblocking(int fd);
+void io_set_close_on_exec(int fd);
+void io_init_fd(int fd);
 
 struct connect_fd *io_connect(struct io_backend *b,
 			      struct sockaddr_in *remote,
@@ -150,10 +152,9 @@ struct io_fd *io_read(struct io_backend *b,
 		      struct read_handler *read_callback,
 		      struct close_callback *close_callback);
 
-struct abstract_write *io_write(struct io_backend *b,
-				int fd,
-				UINT32 block_size,
-				struct close_callback *close_callback);
-
+struct io_fd *io_write(struct io_backend *b,
+		       int fd,
+		       UINT32 block_size,
+		       struct close_callback *close_callback);
 
 #endif /* LSH_IO_H_INCLUDED */