diff -urN linux-2.1.52/fs/select.c linux/fs/select.c --- linux-2.1.52/fs/select.c Thu Sep 4 13:18:35 1997 +++ linux/fs/select.c Thu Sep 4 13:03:59 1997 @@ -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,21 +275,13 @@ */ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - int error = -EINVAL; - fd_set_buffer *fds; + int error = -ENOMEM; + fd_set_buffer *fds = NULL; unsigned long timeout; + poll_table wait_table, *wait; + struct poll_table_entry *entry = NULL; 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)); @@ -316,11 +297,33 @@ if (timeout) timeout += jiffies + 1; } + if (timeout) { + 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; + } + else { + wait = NULL; + } + fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL); + if (!fds) + goto out; + 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); + error = do_select(n, fds, wait); timeout = current->timeout - jiffies - 1; current->timeout = 0; if ((long) timeout < 0) @@ -343,7 +346,12 @@ set_fd_set(n, outp, &fds->res_out); set_fd_set(n, exp, &fds->res_ex); out: - free_page((unsigned long) fds); + if (entry) { + free_wait(&wait_table); + free_page((unsigned long) entry); + } + if (fds) + free_page((unsigned long) fds); unlock_kernel(); return error; } @@ -392,43 +400,44 @@ { int i, count, fdcount, err; struct pollfd * fds, *fds1; - poll_table wait_table; - struct poll_table_entry *entry; + poll_table wait_table, *wait; + struct poll_table_entry *entry = NULL; 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; + if (timeout) { + 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; + } + else { + wait = NULL; + } 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 +449,10 @@ else err = fdcount; out: + if (entry) { + free_wait(&wait_table); + free_page((unsigned long) entry); + } unlock_kernel(); return err; }