--- linux-2.3.40pre4/fs/select.c Tue Aug 31 13:30:48 1999 +++ linux-2.3.40pre4.new/fs/select.c Mon Jan 17 01:08:10 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -375,16 +376,15 @@ { int i, fdcount, err, size; struct pollfd * fds, *fds1; - poll_table *wait_table = NULL, *wait = NULL; + poll_table *wait = NULL; - lock_kernel(); /* Do a sanity check on nfds ... */ err = -EINVAL; if (nfds > current->files->max_fds) goto out; if (timeout) { - /* Carefula about overflow in the intermediate values */ + /* Careful about overflow in the intermediate values */ if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) timeout = (unsigned long)(timeout*HZ+999)/1000+1; else /* Negative or overflow */ @@ -393,41 +393,57 @@ err = -ENOMEM; if (timeout) { - wait_table = (poll_table *) __get_free_page(GFP_KERNEL); - if (!wait_table) + wait = (poll_table *)__get_free_page(GFP_KERNEL); + if (!wait) goto out; - wait_table->nr = 0; - wait_table->entry = (struct poll_table_entry *)(wait_table + 1); - wait_table->next = NULL; - wait = wait_table; + wait->nr = 0; + wait->entry = (struct poll_table_entry *)(wait + 1); + wait->next = NULL; } size = nfds * sizeof(struct pollfd); - fds = (struct pollfd *) kmalloc(size, GFP_KERNEL); + + if (size < PAGE_SIZE) { + fds = (struct pollfd *)kmalloc(size, GFP_KERNEL); + } else if (size == PAGE_SIZE) { + fds = (struct pollfd *)__get_free_page(GFP_KERNEL); + } else { + lock_kernel(); + fds = (struct pollfd *)vmalloc(size); + unlock_kernel(); + } + if (!fds) - goto out; + goto out_nomem; err = -EFAULT; if (copy_from_user(fds, ufds, size)) goto out_fds; + lock_kernel(); fdcount = do_poll(nfds, fds, wait, timeout); + unlock_kernel(); /* OK, now copy the revents fields back to user space. */ - fds1 = fds; - for(i=0; i < (int)nfds; i++, ufds++, fds1++) { + for (fds1 = fds, i = 0; i < (int)nfds; i++, ufds++, fds1++) __put_user(fds1->revents, &ufds->revents); - } err = fdcount; if (!fdcount && signal_pending(current)) err = -EINTR; out_fds: - kfree(fds); + if (size < PAGE_SIZE) { + kfree(fds); + } else if (size == PAGE_SIZE) { + free_page((unsigned long)fds); + } else { + lock_kernel(); + vfree(fds); + unlock_kernel(); + } +out_nomem: + free_wait(wait); out: - if (wait) - free_wait(wait_table); - unlock_kernel(); return err; }