X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fselect.c;h=33b72ba0f86f45790bd7661053266cd8336c9757;hb=a29b0b74e73b66674d20a170e463fe9032f2272a;hp=b3a3a1326af66e63505860cef77c8ae343ebc55a;hpb=d62e54abca1146981fc9f98f85ff398a113a22c2;p=powerpc.git diff --git a/fs/select.c b/fs/select.c index b3a3a1326a..33b72ba0f8 100644 --- a/fs/select.c +++ b/fs/select.c @@ -310,11 +310,12 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s64 *timeout) { fd_set_bits fds; - char *bits; - int ret, size, max_fdset; + void *bits; + int ret, max_fdset; + unsigned int size; struct fdtable *fdt; /* Allocate small arguments on the stack to save memory and be faster */ - char stack_fds[SELECT_STACK_ALLOC]; + long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; ret = -EINVAL; if (n < 0) @@ -333,20 +334,21 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, * since we used fdset we need to allocate memory in units of * long-words. */ - ret = -ENOMEM; size = FDS_BYTES(n); - if (6*size < SELECT_STACK_ALLOC) - bits = stack_fds; - else + bits = stack_fds; + if (size > sizeof(stack_fds) / 6) { + /* Not enough space in on-stack array; must use kmalloc */ + ret = -ENOMEM; bits = kmalloc(6 * size, GFP_KERNEL); - if (!bits) - goto out_nofds; - 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 (!bits) + goto out_nofds; + } + fds.in = bits; + fds.out = bits + size; + fds.ex = bits + 2*size; + fds.res_in = bits + 3*size; + fds.res_out = bits + 4*size; + fds.res_ex = bits + 5*size; if ((ret = get_fd_set(n, inp, fds.in)) || (ret = get_fd_set(n, outp, fds.out)) || @@ -544,37 +546,38 @@ struct poll_list { #define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd)) -static void do_pollfd(unsigned int num, struct pollfd * fdpage, - poll_table ** pwait, int *count) +/* + * Fish for pollable events on the pollfd->fd file descriptor. We're only + * interested in events matching the pollfd->events mask, and the result + * matching that mask is both recorded in pollfd->revents and returned. The + * pwait poll_table will be used by the fd-provided poll handler for waiting, + * if non-NULL. + */ +static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) { - int i; - - for (i = 0; i < num; i++) { - int fd; - unsigned int mask; - struct pollfd *fdp; - - mask = 0; - fdp = fdpage+i; - fd = fdp->fd; - if (fd >= 0) { - int fput_needed; - struct file * file = fget_light(fd, &fput_needed); - mask = POLLNVAL; - if (file != NULL) { - mask = DEFAULT_POLLMASK; - if (file->f_op && file->f_op->poll) - mask = file->f_op->poll(file, *pwait); - mask &= fdp->events | POLLERR | POLLHUP; - fput_light(file, fput_needed); - } - if (mask) { - *pwait = NULL; - (*count)++; - } + unsigned int mask; + int fd; + + mask = 0; + fd = pollfd->fd; + if (fd >= 0) { + int fput_needed; + struct file * file; + + file = fget_light(fd, &fput_needed); + mask = POLLNVAL; + if (file != NULL) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file, pwait); + /* Mask out unneeded events. */ + mask &= pollfd->events | POLLERR | POLLHUP; + fput_light(file, fput_needed); } - fdp->revents = mask; } + pollfd->revents = mask; + + return mask; } static int do_poll(unsigned int nfds, struct poll_list *list, @@ -592,11 +595,29 @@ static int do_poll(unsigned int nfds, struct poll_list *list, long __timeout; set_current_state(TASK_INTERRUPTIBLE); - walk = list; - while(walk != NULL) { - do_pollfd( walk->len, walk->entries, &pt, &count); - walk = walk->next; + for (walk = list; walk != NULL; walk = walk->next) { + struct pollfd * pfd, * pfd_end; + + pfd = walk->entries; + pfd_end = pfd + walk->len; + for (; pfd != pfd_end; pfd++) { + /* + * Fish for events. If we found one, record it + * and kill the poll_table, so we don't + * needlessly register any other waiters after + * this. They'll get immediately deregistered + * when we break out and return. + */ + if (do_pollfd(pfd, pt)) { + count++; + pt = NULL; + } + } } + /* + * All waiters have already been registered, so don't provide + * a poll_table to them on the next loop iteration. + */ pt = NULL; if (count || !*timeout || signal_pending(current)) break; @@ -639,8 +660,10 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) struct poll_list *walk; struct fdtable *fdt; int max_fdset; - /* Allocate small arguments on the stack to save memory and be faster */ - char stack_pps[POLL_STACK_ALLOC]; + /* Allocate small arguments on the stack to save memory and be + faster - use long to make sure the buffer is aligned properly + on 64 bit archs to avoid unaligned access */ + long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; struct poll_list *stack_pp = NULL; /* Do a sanity check on nfds ... */ @@ -723,9 +746,9 @@ out_fds: asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, long timeout_msecs) { - s64 timeout_jiffies = 0; + s64 timeout_jiffies; - if (timeout_msecs) { + if (timeout_msecs > 0) { #if HZ > 1000 /* We can only overflow if HZ > 1000 */ if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ) @@ -733,6 +756,9 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, else #endif timeout_jiffies = msecs_to_jiffies(timeout_msecs); + } else { + /* Infinite (< 0) or no (0) timeout */ + timeout_jiffies = timeout_msecs; } return do_sys_poll(ufds, nfds, &timeout_jiffies);