diff -ur linux/fs/select.c linux-poll/fs/select.c --- linux/fs/select.c Sat Dec 12 18:39:02 1998 +++ linux-poll/fs/select.c Sat Dec 12 14:29:41 1998 @@ -41,28 +41,35 @@ static void free_wait(poll_table * p) { - struct poll_table_entry * entry = p->entry + p->nr; + struct poll_table_entry * entry; + poll_table *old; - while (p->nr > 0) { - p->nr--; - entry--; - remove_wait_queue(entry->wait_address,&entry->wait); - fput(entry->filp); + while (p) { + entry = p->entry + p->nr; + while (p->nr > 0) { + p->nr--; + entry--; + remove_wait_queue(entry->wait_address,&entry->wait); + fput(entry->filp); + } + old = p; + p = p->next; + free_page((unsigned long) old); } } -#define __IN(in) (in) -#define __OUT(in) (in + sizeof(kernel_fd_set)/sizeof(unsigned long)) -#define __EX(in) (in + 2*sizeof(kernel_fd_set)/sizeof(unsigned long)) -#define __RES_IN(in) (in + 3*sizeof(kernel_fd_set)/sizeof(unsigned long)) -#define __RES_OUT(in) (in + 4*sizeof(kernel_fd_set)/sizeof(unsigned long)) -#define __RES_EX(in) (in + 5*sizeof(kernel_fd_set)/sizeof(unsigned long)) +#define __IN(fds, n) (fds->in + n) +#define __OUT(fds, n) (fds->out + n) +#define __EX(fds, n) (fds->ex + n) +#define __RES_IN(fds, n) (fds->res_in + n) +#define __RES_OUT(fds, n) (fds->res_out + n) +#define __RES_EX(fds, n) (fds->res_ex + n) -#define BITS(in) (*__IN(in)|*__OUT(in)|*__EX(in)) +#define BITS(fds, n) (*__IN(fds, n)|*__OUT(fds, n)|*__EX(fds, n)) -static int max_select_fd(unsigned long n, fd_set_buffer *fds) +static int max_select_fd(unsigned long n, fd_set_bits *fds) { - unsigned long *open_fds, *in; + unsigned long *open_fds; unsigned long set; int max; @@ -70,10 +77,9 @@ set = ~(~0UL << (n & (__NFDBITS-1))); n /= __NFDBITS; open_fds = current->files->open_fds->fds_bits+n; - in = fds->in+n; max = 0; if (set) { - set &= BITS(in); + set &= BITS(fds, n); if (set) { if (!(set & ~*open_fds)) goto get_max; @@ -81,10 +87,9 @@ } } while (n) { - in--; open_fds--; n--; - set = BITS(in); + set = BITS(fds, n); if (!set) continue; if (set & ~*open_fds) @@ -111,21 +116,22 @@ #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) #define POLLEX_SET (POLLPRI) -int do_select(int n, fd_set_buffer *fds, long *timeout) +int do_select(int n, fd_set_bits *fds, long *timeout) { - poll_table wait_table, *wait; - int retval, i; + poll_table *wait_table, *wait; + int retval, i, off; long __timeout = *timeout; - wait = NULL; + wait = wait_table = NULL; if (__timeout) { - struct poll_table_entry *entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL); - if (!entry) + wait_table = (poll_table *) __get_free_page(GFP_KERNEL); + if (!wait_table) return -ENOMEM; - wait_table.nr = 0; - wait_table.entry = entry; - wait = &wait_table; + wait_table->nr = 0; + wait_table->entry = (struct poll_table_entry *)(wait_table + 1); + wait_table->next = NULL; + wait = wait_table; } lock_kernel(); @@ -139,11 +145,11 @@ current->state = TASK_INTERRUPTIBLE; for (i = 0 ; i < n; i++) { unsigned long bit = BIT(i); - unsigned long *in = MEM(i,fds->in); unsigned long mask; struct file *file; - if (!(bit & BITS(in))) + off = i / __NFDBITS; + if (!(bit & BITS(fds, off))) continue; /* * The poll_wait routine will increment f_count if @@ -157,18 +163,18 @@ if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, wait); } - if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) { - SET(bit, __RES_IN(in)); + if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) { + SET(bit, __RES_IN(fds,off)); retval++; wait = NULL; } - if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) { - SET(bit, __RES_OUT(in)); + if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) { + SET(bit, __RES_OUT(fds,off)); retval++; wait = NULL; } - if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) { - SET(bit, __RES_EX(in)); + if ((mask & POLLEX_SET) && ISSET(bit, __EX(fds,off))) { + SET(bit, __RES_EX(fds,off)); retval++; wait = NULL; } @@ -181,10 +187,8 @@ current->state = TASK_RUNNING; out: - if (*timeout) { - free_wait(&wait_table); - free_page((unsigned long) wait_table.entry); - } + if (*timeout) + free_wait(wait_table); /* * Up-to-date the caller timeout. @@ -208,9 +212,10 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - fd_set_buffer *fds; + fd_set_bits fds; + char *bits; long timeout; - int ret; + int ret, size; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -227,24 +232,36 @@ } } + ret = -EINVAL; + if (n <= 0 || n > current->files->max_fdset + 1) + goto out_nofds; + /* + * We need 6 bitmaps (in/out/ex for both incoming and outgoing), + * since we used fdset we need to allocate memory in units of + * long-words. + */ + ret = -ENOMEM; - fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL); - if (!fds) + size = (n + 8 * sizeof(long) - 1) / (8 * sizeof(long)) * sizeof(long); + bits = kmalloc(6 * size, GFP_KERNEL); + if (!bits) goto out_nofds; - ret = -EINVAL; - if (n < 0) + fds.in = (unsigned long *) bits; + fds.out = (unsigned long *) (bits + size); + fds.ex = (unsigned long *) (bits + 2*size); + fds.res_in = (unsigned long *) (bits + 3*size); + fds.res_out = (unsigned long *) (bits + 4*size); + fds.res_ex = (unsigned long *) (bits + 5*size); + + if ((ret = get_fd_set(n, inp, fds.in)) || + (ret = get_fd_set(n, outp, fds.out)) || + (ret = get_fd_set(n, exp, fds.ex))) goto out; - if (n > KFDS_NR) - n = KFDS_NR; - if ((ret = get_fd_set(n, inp, fds->in)) || - (ret = get_fd_set(n, outp, fds->out)) || - (ret = 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); + zero_fd_set(n, fds.res_in); + zero_fd_set(n, fds.res_out); + zero_fd_set(n, fds.res_ex); - ret = do_select(n, fds, &timeout); + ret = do_select(n, &fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { time_t sec = 0, usec = 0; @@ -266,12 +283,12 @@ ret = 0; } - set_fd_set(n, inp, fds->res_in); - set_fd_set(n, outp, fds->res_out); - set_fd_set(n, exp, fds->res_ex); + set_fd_set(n, inp, fds.res_in); + set_fd_set(n, outp, fds.res_out); + set_fd_set(n, exp, fds.res_ex); out: - free_page((unsigned long) fds); + kfree(bits); out_nofds: return ret; } @@ -323,7 +340,7 @@ { int i, fdcount, err, size; struct pollfd * fds, *fds1; - poll_table wait_table, *wait = NULL; + poll_table *wait_table = NULL, *wait = NULL; lock_kernel(); /* Do a sanity check on nfds ... */ @@ -338,13 +355,13 @@ err = -ENOMEM; if (timeout) { - struct poll_table_entry *entry; - entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL); - if (!entry) + wait_table = (poll_table *) __get_free_page(GFP_KERNEL); + if (!wait_table) goto out; - wait_table.nr = 0; - wait_table.entry = entry; - wait = &wait_table; + wait_table->nr = 0; + wait_table->entry = (struct poll_table_entry *)(wait_table + 1); + wait_table->next = NULL; + wait = wait_table; } size = nfds * sizeof(struct pollfd); @@ -371,10 +388,8 @@ out_fds: kfree(fds); out: - if (wait) { - free_wait(&wait_table); - free_page((unsigned long) wait->entry); - } + if (wait) + free_wait(wait_table); unlock_kernel(); return err; } diff -ur linux/include/linux/poll.h linux-poll/include/linux/poll.h --- linux/include/linux/poll.h Tue Nov 24 15:56:25 1998 +++ linux-poll/include/linux/poll.h Sat Dec 12 14:31:36 1998 @@ -7,6 +7,7 @@ #include #include +#include #include @@ -17,11 +18,12 @@ }; typedef struct poll_table_struct { + struct poll_table_struct * next; unsigned int nr; struct poll_table_entry * entry; } poll_table; -#define __MAX_POLL_TABLE_ENTRIES (PAGE_SIZE / sizeof (struct poll_table_entry)) +#define __MAX_POLL_TABLE_ENTRIES ((PAGE_SIZE - sizeof (poll_table)) / sizeof (struct poll_table_entry)) extern inline void poll_wait(struct file * filp, struct wait_queue ** wait_address, poll_table *p) { @@ -29,8 +31,18 @@ if (!p || !wait_address) return; - if (p->nr >= __MAX_POLL_TABLE_ENTRIES) - return; + while (p->nr >= __MAX_POLL_TABLE_ENTRIES && p->next != NULL) + p = p->next; + if (p->nr >= __MAX_POLL_TABLE_ENTRIES) { + poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL); + if (!tmp) + return; + tmp->nr = 0; + tmp->entry = (struct poll_table_entry *)(tmp + 1); + tmp->next = NULL; + p->next = tmp; + p = tmp; + } entry = p->entry + p->nr; entry->filp = filp; filp->f_count++; @@ -59,11 +71,23 @@ #define KFDS_NR (KFDS_64BLOCK*8 > NR_OPEN ? NR_OPEN : KFDS_64BLOCK*8) typedef unsigned long kernel_fd_set[KFDS_NR/__NFDBITS]; +/* + * XXX - still used by alpha osf and sparc32 compatiblity. + */ + typedef struct { kernel_fd_set in, out, ex; kernel_fd_set res_in, res_out, res_ex; } fd_set_buffer; +/* + * Scaleable version of the fd_set. + */ + +typedef struct { + unsigned long *in, *out, *ex; + unsigned long *res_in, *res_out, *res_ex; +} fd_set_bits; /* * We do a VERIFY_WRITE here even though we are only reading this time: @@ -103,7 +127,7 @@ memset(fdset, 0, nr); } -extern int do_select(int n, fd_set_buffer *fds, long *timeout); +extern int do_select(int n, fd_set_bits *fds, long *timeout); #endif /* KERNEL */ diff -ur linux/kernel/fork.c linux-poll/kernel/fork.c --- linux/kernel/fork.c Sat Dec 12 18:39:11 1998 +++ linux-poll/kernel/fork.c Thu Dec 10 18:42:16 1998 @@ -1,4 +1,4 @@ -#define FDSET_DEBUG +#undef FDSET_DEBUG /* * linux/kernel/fork.c