Commit 5a56fafe authored by Linus Torvalds's avatar Linus Torvalds Committed by Linus Torvalds

Clean up and fix fast select case

parent 362dff46
...@@ -120,7 +120,7 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table ...@@ -120,7 +120,7 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table
int do_select(int n, fd_set_bits *fds, long *timeout) int do_select(int n, fd_set_bits *fds, long *timeout)
{ {
poll_table table, *wait; poll_table table, *wait;
int retval, off, max, maxoff; int retval, off, maxoff;
long __timeout = *timeout; long __timeout = *timeout;
poll_initwait(&table); poll_initwait(&table);
...@@ -129,27 +129,25 @@ int do_select(int n, fd_set_bits *fds, long *timeout) ...@@ -129,27 +129,25 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
wait = NULL; wait = NULL;
retval = 0; retval = 0;
maxoff = n/BITS_PER_LONG; maxoff = FDS_LONGS(n);
max = 0;
for (;;) { for (;;) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
for (off = 0; off <= maxoff; off++) { for (off = 0; off <= maxoff; off++) {
unsigned long val = BITS(fds, off); unsigned long val = BITS(fds, off);
if (!val)
continue;
while (val) { while (val) {
int k = ffz(~val); int k = ffz(~val), index;
unsigned long mask, bit; unsigned long mask, bit;
struct file *file; struct file *file;
if (k > n%BITS_PER_LONG)
break;
bit = (1UL << k); bit = (1UL << k);
val &= ~bit; val &= ~bit;
file = fget((off * BITS_PER_LONG) + k); index = off*BITS_PER_LONG + k;
if (index >= n)
break;
file = fget(index);
mask = POLLNVAL; mask = POLLNVAL;
if (file) { if (file) {
mask = DEFAULT_POLLMASK; mask = DEFAULT_POLLMASK;
...@@ -167,7 +165,7 @@ int do_select(int n, fd_set_bits *fds, long *timeout) ...@@ -167,7 +165,7 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
retval++; retval++;
wait = NULL; wait = NULL;
} }
if ((mask& POLLOUT_SET) && ISSET(bit,__OUT(fds,off))) { if ((mask & POLLOUT_SET) && ISSET(bit,__OUT(fds,off))) {
SET(bit, __RES_OUT(fds,off)); SET(bit, __RES_OUT(fds,off));
retval++; retval++;
wait = NULL; wait = NULL;
...@@ -177,18 +175,13 @@ int do_select(int n, fd_set_bits *fds, long *timeout) ...@@ -177,18 +175,13 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
retval++; retval++;
wait = NULL; wait = NULL;
} }
if (!(val &= ~bit))
break;
} }
} }
maxoff = max;
wait = NULL; wait = NULL;
if (retval || !__timeout || signal_pending(current)) if (retval || !__timeout || signal_pending(current))
break; break;
if(table.error) { if (table.error) {
retval = table.error; retval = table.error;
break; break;
} }
...@@ -214,19 +207,15 @@ int do_select(int n, fd_set_bits *fds, long *timeout) ...@@ -214,19 +207,15 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
static int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset) static int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
{ {
unsigned long rounded = FDS_BYTES(nr), mask; unsigned long rounded = FDS_BYTES(nr);
if (ufdset) { if (ufdset) {
int error = verify_area(VERIFY_WRITE, ufdset, rounded); int error = verify_area(VERIFY_WRITE, ufdset, rounded);
if (!error && __copy_from_user(fdset, ufdset, rounded)) if (!error && __copy_from_user(fdset, ufdset, rounded))
error = -EFAULT; error = -EFAULT;
if (nr % __NFDBITS == 0) if (nr % __NFDBITS) {
mask = 0; unsigned long mask = ~(~0UL << (nr % __NFDBITS));
else { fdset[nr/__NFDBITS] &= mask;
/* This includes one bit too much according to SU;
but without this some programs hang. */
mask = ~(~0UL << (nr%__NFDBITS));
} }
fdset[nr/__NFDBITS] &= mask;
return error; return error;
} }
memset(fdset, 0, rounded); memset(fdset, 0, rounded);
...@@ -248,10 +237,10 @@ asmlinkage long ...@@ -248,10 +237,10 @@ asmlinkage long
sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{ {
fd_set_bits fds; fd_set_bits fds;
char *bits; unsigned long *bits;
long timeout; long timeout;
int ret, size, max_fdset; int ret, size, max_fdset;
char stack_bits[FDS_BYTES(FAST_SELECT_MAX) * 6]; unsigned long stack_bits[FDS_LONGS(FAST_SELECT_MAX) * 6];
timeout = MAX_SCHEDULE_TIMEOUT; timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) { if (tvp) {
...@@ -286,22 +275,21 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) ...@@ -286,22 +275,21 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
* since we used fdset we need to allocate memory in units of * since we used fdset we need to allocate memory in units of
* long-words. * long-words.
*/ */
size = FDS_BYTES(n); size = FDS_LONGS(n);
if (n < FAST_SELECT_MAX) { bits = stack_bits;
bits = stack_bits; if (n >= FAST_SELECT_MAX) {
} else {
ret = -ENOMEM; ret = -ENOMEM;
bits = kmalloc(6*size, GFP_KERNEL); bits = kmalloc(sizeof(unsigned long)*6*size, GFP_KERNEL);
if (!bits) if (!bits)
goto out_nofds; goto out_nofds;
} }
fds.in = (unsigned long *) bits; fds.in = bits;
fds.out = (unsigned long *) (bits + size); fds.out = bits + size;
fds.ex = (unsigned long *) (bits + 2*size); fds.ex = bits + 2*size;
fds.res_in = (unsigned long *) (bits + 3*size); fds.res_in = bits + 3*size;
fds.res_out = (unsigned long *) (bits + 4*size); fds.res_out = bits + 4*size;
fds.res_ex = (unsigned long *) (bits + 5*size); fds.res_ex = bits + 5*size;
if ((ret = get_fd_set(n, inp, fds.in)) || if ((ret = get_fd_set(n, inp, fds.in)) ||
(ret = get_fd_set(n, outp, fds.out)) || (ret = get_fd_set(n, outp, fds.out)) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment