patch-2.1.53 linux/fs/select.c
Next file: linux/include/asm-m68k/elf.h
Previous file: linux/fs/dcache.c
Back to the patch index
Back to the overall index
- Lines: 208
- Date:
Wed Sep 3 20:49:40 1997
- Orig file:
v2.1.52/linux/fs/select.c
- Orig date:
Wed Sep 3 20:52:43 1997
diff -u --recursive --new-file v2.1.52/linux/fs/select.c linux/fs/select.c
@@ -141,25 +141,16 @@
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)
-static int do_select(int n, fd_set_buffer *fds)
+static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
{
int retval;
- poll_table wait_table, *wait;
- struct poll_table_entry *entry;
int i;
retval = max_select_fd(n, fds);
if (retval < 0)
goto out;
n = retval;
- retval = -ENOMEM;
- entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
- if (!entry)
- goto out;
retval = 0;
- wait_table.nr = 0;
- wait_table.entry = entry;
- wait = &wait_table;
for (;;) {
struct file ** fd = current->files->fd;
current->state = TASK_INTERRUPTIBLE;
@@ -197,8 +188,6 @@
break;
schedule();
}
- free_wait(&wait_table);
- free_page((unsigned long) entry);
current->state = TASK_RUNNING;
out:
return retval;
@@ -286,51 +275,60 @@
*/
asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int error = -EINVAL;
+ int error;
fd_set_buffer *fds;
unsigned long timeout;
+ poll_table wait_table, *wait;
lock_kernel();
- fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
- if (!fds)
- goto out;
- if (n < 0)
- goto out;
- if (n > KFDS_NR)
- n = KFDS_NR;
- if ((error = get_fd_set(n, inp, &fds->in)) ||
- (error = get_fd_set(n, outp, &fds->out)) ||
- (error = get_fd_set(n, exp, &fds->ex))) goto out;
timeout = ~0UL;
if (tvp) {
- error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
+ error = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, tvp, sizeof(*tvp)))
+ goto out_nowait;
+ error = __get_user(timeout, &tvp->tv_usec);
if (error)
- goto out;
- __get_user(timeout, &tvp->tv_usec);
+ goto out_nowait;
timeout = ROUND_UP(timeout,(1000000/HZ));
{
unsigned long tmp;
- __get_user(tmp, &tvp->tv_sec);
+ error = __get_user(tmp, &tvp->tv_sec);
+ if (error)
+ goto out_nowait;
timeout += tmp * (unsigned long) HZ;
}
if (timeout)
timeout += jiffies + 1;
}
+ error = -ENOMEM;
+ wait = NULL;
+ current->timeout = timeout;
+ if (timeout) {
+ struct poll_table_entry *entry;
+
+ entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+ if (!entry)
+ goto out_nowait;
+ wait_table.nr = 0;
+ wait_table.entry = entry;
+ wait = &wait_table;
+ }
+ fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
+ if (!fds)
+ goto out_nofds;
+ error = -EINVAL;
+ if (n < 0)
+ goto out;
+ if (n > KFDS_NR)
+ n = KFDS_NR;
+ if ((error = get_fd_set(n, inp, &fds->in)) ||
+ (error = get_fd_set(n, outp, &fds->out)) ||
+ (error = get_fd_set(n, exp, &fds->ex))) goto out;
zero_fd_set(n, &fds->res_in);
zero_fd_set(n, &fds->res_out);
zero_fd_set(n, &fds->res_ex);
- current->timeout = timeout;
- error = do_select(n, fds);
- timeout = current->timeout - jiffies - 1;
+ error = do_select(n, fds, wait);
current->timeout = 0;
- if ((long) timeout < 0)
- timeout = 0;
- if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
- __put_user(timeout/HZ, &tvp->tv_sec);
- timeout %= HZ;
- timeout *= (1000000/HZ);
- __put_user(timeout, &tvp->tv_usec);
- }
if (error < 0)
goto out;
if (!error) {
@@ -344,6 +342,12 @@
set_fd_set(n, exp, &fds->res_ex);
out:
free_page((unsigned long) fds);
+out_nofds:
+ if (wait) {
+ free_wait(&wait_table);
+ free_page((unsigned long) wait->entry);
+ }
+out_nowait:
unlock_kernel();
return error;
}
@@ -392,43 +396,43 @@
{
int i, count, fdcount, err;
struct pollfd * fds, *fds1;
- poll_table wait_table;
- struct poll_table_entry *entry;
+ poll_table wait_table, *wait;
lock_kernel();
+ if (timeout < 0)
+ timeout = 0x7fffffff;
+ else if (timeout)
+ timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
err = -ENOMEM;
- entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
- if (!entry)
- goto out;
+
+ wait = NULL;
+ if (timeout) {
+ struct poll_table_entry *entry;
+ entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+ if (!entry)
+ goto out;
+ wait_table.nr = 0;
+ wait_table.entry = entry;
+ wait = &wait_table;
+ }
fds = (struct pollfd *) kmalloc(nfds*sizeof(struct pollfd), GFP_KERNEL);
if (!fds) {
- free_page((unsigned long) entry);
goto out;
}
err = -EFAULT;
if (copy_from_user(fds, ufds, nfds*sizeof(struct pollfd))) {
- free_page((unsigned long)entry);
kfree(fds);
goto out;
}
- if (timeout < 0)
- timeout = 0x7fffffff;
- else if (timeout)
- timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
current->timeout = timeout;
count = 0;
- wait_table.nr = 0;
- wait_table.entry = entry;
- fdcount = do_poll(nfds, fds, timeout ? &wait_table : NULL);
+ fdcount = do_poll(nfds, fds, wait);
current->timeout = 0;
- free_wait(&wait_table);
- free_page((unsigned long) entry);
-
/* OK, now copy the revents fields back to user space. */
fds1 = fds;
for(i=0; i < (int)nfds; i++, ufds++, fds++) {
@@ -440,6 +444,10 @@
else
err = fdcount;
out:
+ if (wait) {
+ free_wait(&wait_table);
+ free_page((unsigned long) wait->entry);
+ }
unlock_kernel();
return err;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov