patch-2.0.34 linux/fs/select.c

Next file: linux/fs/smbfs/dir.c
Previous file: linux/fs/nls_koi8_r.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.33/linux/fs/select.c linux/fs/select.c
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/file.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -57,6 +58,34 @@
 }
 
 /*
+ *	File handle locking
+ */
+ 
+static void lock_fd_bits(int n, int x)
+{
+	int i;
+	for(i=0;i<__NFDBITS;i++)
+	{
+		if(x&(1<<i))
+			fget(n+i);
+	}
+}
+
+static void unlock_fd_bits(int n, int x)
+{
+	int i;
+	for(i=0;i<__NFDBITS;i++)
+	{
+		if(x&(1<<i))
+		{
+			/* ick */
+			struct file *f=current->files->fd[n+i];
+			fput(f, f->f_inode);
+		}
+	}
+}
+
+/*
  * The check function checks the ready status of a file using the vfs layer.
  *
  * If the file was not ready we were added to its wait queue.  But in
@@ -83,7 +112,7 @@
 }
 
 static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
-	fd_set *res_in, fd_set *res_out, fd_set *res_ex)
+	fd_set *res_in, fd_set *res_out, fd_set *res_ex, fd_set *locked)
 {
 	int count;
 	select_table wait_table, *wait;
@@ -91,7 +120,7 @@
 	unsigned long set;
 	int i,j;
 	int max = -1;
-
+	int threaded = 0;
 	j = 0;
 	for (;;) {
 		i = j * __NFDBITS;
@@ -113,8 +142,34 @@
 	}
 end_check:
 	n = max + 1;
+	
+	/* Now we _must_ lock the handles before we get the page otherwise
+	   they may get closed on us during the kmalloc causing explosions.. */
+	
+	if(current->files->count>1)
+	{	
+	
+		/*
+		 *	Only for the threaded cases must we do work.
+		 */
+		j = 0;
+		for (;;) {
+			i = j * __NFDBITS;
+			if (i >= n)
+				break;
+			lock_fd_bits(i,in->fds_bits[j]);
+			lock_fd_bits(i,out->fds_bits[j]);
+			lock_fd_bits(i,ex->fds_bits[j]);
+			j++;
+		}
+		threaded=1;
+	}
+		
 	if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
+	{
+		count = -ENOMEM; 
+		goto bale;
+	}
 	count = 0;
 	wait_table.nr = 0;
 	wait_table.entry = entry;
@@ -149,6 +204,22 @@
 	free_wait(&wait_table);
 	free_page((unsigned long) entry);
 	current->state = TASK_RUNNING;
+bale:
+
+	if(threaded)
+	{
+		/* Unlock handles now */	
+		j = 0;
+		for (;;) {
+			i = j * __NFDBITS;
+			if (i >= n)
+				break;
+			unlock_fd_bits(i,in->fds_bits[j]);
+			unlock_fd_bits(i,out->fds_bits[j]);
+			unlock_fd_bits(i,ex->fds_bits[j]);
+			j++;
+		}
+	}
 	return count;
 }
 
@@ -243,6 +314,7 @@
 	limited_fd_set res_in, in;
 	limited_fd_set res_out, out;
 	limited_fd_set res_ex, ex;
+	limited_fd_set locked;
 	unsigned long timeout;
 
 	error = -EINVAL;
@@ -273,7 +345,8 @@
 		(fd_set *) &ex,
 		(fd_set *) &res_in,
 		(fd_set *) &res_out,
-		(fd_set *) &res_ex);
+		(fd_set *) &res_ex,
+		(fd_set *) &locked);
 	timeout = current->timeout - jiffies - 1;
 	current->timeout = 0;
 	if ((long) timeout < 0)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov