--- linux-2.3.38.old/fs/select.c Tue Aug 31 13:30:48 1999 +++ linux-2.3.38/fs/select.c Sat Jan 8 05:32:04 2000 @@ -371,11 +371,17 @@ return count; } +/* + * 131072 is the largest slab of memory that kmalloc lets us allocate. + * It's a pain that this is hardcoded... + */ +#define NUM_POLLFDS (131072 / sizeof(struct pollfd)) + asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) { - int i, fdcount, err, size; - struct pollfd * fds, *fds1; - poll_table *wait_table = NULL, *wait = NULL; + int fdcount, err, size, iter, offset, res; + struct pollfd *fds; + poll_table *wait = NULL; lock_kernel(); /* Do a sanity check on nfds ... */ @@ -384,7 +390,7 @@ 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,30 +399,49 @@ 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; + } + + iter = (int)(nfds / NUM_POLLFDS) + 1; + + if (iter == 1) { + size = nfds * sizeof(struct pollfd); + res = nfds; + } else { + size = NUM_POLLFDS * sizeof(struct pollfd); + res = nfds % NUM_POLLFDS; } - size = nfds * sizeof(struct pollfd); fds = (struct pollfd *) kmalloc(size, GFP_KERNEL); + if (!fds) - goto out; + goto out_nomem; + + fdcount = 0; + + for (offset = 0; iter > 0; iter--, offset += NUM_POLLFDS) { + struct pollfd *fds1, *ufds1; + unsigned int fds_num = (iter == 1 ? res : NUM_POLLFDS); + int i; + + err = -EFAULT; + + if (copy_from_user(fds, &ufds[offset], fds_num * sizeof(struct pollfd))) + goto out_fds; + + fdcount += do_poll(fds_num, fds, wait, timeout); + + /* OK, now copy the revents fields back to user space. */ + fds1 = fds; + ufds1 = &ufds[offset]; - err = -EFAULT; - if (copy_from_user(fds, ufds, size)) - goto out_fds; - - fdcount = do_poll(nfds, fds, wait, timeout); - - /* OK, now copy the revents fields back to user space. */ - fds1 = fds; - for(i=0; i < (int)nfds; i++, ufds++, fds1++) { - __put_user(fds1->revents, &ufds->revents); + for (i = 0; i < (int)fds_num; i++, ufds1++, fds1++) + __put_user(fds1->revents, &ufds1->revents); } err = fdcount; @@ -425,9 +450,9 @@ out_fds: kfree(fds); +out_nomem: + free_wait(wait); out: - if (wait) - free_wait(wait_table); unlock_kernel(); return err; }