do_sys_poll: simplify playing with on-stack data
Cleanup. Lessens both the source and compiled code (100 bytes) and imho makes the code much more understandable. With this patch "struct poll_list *head" always points to on-stack stack_pps, so we can remove all "is it on-stack" and "was it initialized" checks. Also, move poll_initwait/poll_freewait and -EINTR detection closer to the do_poll()'s callsite. [akpm@linux-foundation.org: fix warning (size_t != uint)] Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Looks-good-to: Andi Kleen <ak@suse.de> Cc: Davide Libenzi <davidel@xmailserver.org> Cc: Vadim Lobanov <vlobanov@speakeasy.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
759d7c6c47
commit
252e5725cf
1 changed files with 36 additions and 56 deletions
90
fs/select.c
90
fs/select.c
|
@ -651,86 +651,66 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
|
||||||
int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
|
int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
|
||||||
{
|
{
|
||||||
struct poll_wqueues table;
|
struct poll_wqueues table;
|
||||||
int fdcount, err;
|
int err = -EFAULT, fdcount, len, size;
|
||||||
unsigned int i;
|
|
||||||
struct poll_list *head;
|
|
||||||
struct poll_list *walk;
|
|
||||||
/* Allocate small arguments on the stack to save memory and be
|
/* Allocate small arguments on the stack to save memory and be
|
||||||
faster - use long to make sure the buffer is aligned properly
|
faster - use long to make sure the buffer is aligned properly
|
||||||
on 64 bit archs to avoid unaligned access */
|
on 64 bit archs to avoid unaligned access */
|
||||||
long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
|
long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
|
||||||
struct poll_list *stack_pp = NULL;
|
struct poll_list *const head = (struct poll_list *)stack_pps;
|
||||||
|
struct poll_list *walk = head;
|
||||||
|
unsigned long todo = nfds;
|
||||||
|
|
||||||
/* Do a sanity check on nfds ... */
|
|
||||||
if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
poll_initwait(&table);
|
len = min_t(unsigned int, nfds, N_STACK_PPS);
|
||||||
|
for (;;) {
|
||||||
|
walk->next = NULL;
|
||||||
|
walk->len = len;
|
||||||
|
if (!len)
|
||||||
|
break;
|
||||||
|
|
||||||
head = NULL;
|
if (copy_from_user(walk->entries, ufds + nfds-todo,
|
||||||
walk = NULL;
|
sizeof(struct pollfd) * walk->len))
|
||||||
i = nfds;
|
goto out_fds;
|
||||||
|
|
||||||
|
todo -= walk->len;
|
||||||
|
if (!todo)
|
||||||
|
break;
|
||||||
|
|
||||||
|
len = min(todo, POLLFD_PER_PAGE);
|
||||||
|
size = sizeof(struct poll_list) + sizeof(struct pollfd) * len;
|
||||||
|
walk = walk->next = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (!walk) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
while(i!=0) {
|
|
||||||
struct poll_list *pp;
|
|
||||||
int num, size;
|
|
||||||
if (stack_pp == NULL)
|
|
||||||
num = N_STACK_PPS;
|
|
||||||
else
|
|
||||||
num = POLLFD_PER_PAGE;
|
|
||||||
if (num > i)
|
|
||||||
num = i;
|
|
||||||
size = sizeof(struct poll_list) + sizeof(struct pollfd)*num;
|
|
||||||
if (!stack_pp)
|
|
||||||
stack_pp = pp = (struct poll_list *)stack_pps;
|
|
||||||
else {
|
|
||||||
pp = kmalloc(size, GFP_KERNEL);
|
|
||||||
if (!pp)
|
|
||||||
goto out_fds;
|
goto out_fds;
|
||||||
}
|
}
|
||||||
pp->next=NULL;
|
|
||||||
pp->len = num;
|
|
||||||
if (head == NULL)
|
|
||||||
head = pp;
|
|
||||||
else
|
|
||||||
walk->next = pp;
|
|
||||||
|
|
||||||
walk = pp;
|
|
||||||
if (copy_from_user(pp->entries, ufds + nfds-i,
|
|
||||||
sizeof(struct pollfd)*num)) {
|
|
||||||
err = -EFAULT;
|
|
||||||
goto out_fds;
|
|
||||||
}
|
|
||||||
i -= pp->len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
poll_initwait(&table);
|
||||||
fdcount = do_poll(nfds, head, &table, timeout);
|
fdcount = do_poll(nfds, head, &table, timeout);
|
||||||
|
if (!fdcount && signal_pending(current))
|
||||||
|
fdcount = -EINTR;
|
||||||
|
poll_freewait(&table);
|
||||||
|
|
||||||
/* OK, now copy the revents fields back to user space. */
|
for (walk = head; walk; walk = walk->next) {
|
||||||
walk = head;
|
|
||||||
err = -EFAULT;
|
|
||||||
while(walk != NULL) {
|
|
||||||
struct pollfd *fds = walk->entries;
|
struct pollfd *fds = walk->entries;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j=0; j < walk->len; j++, ufds++) {
|
for (j = 0; j < walk->len; j++, ufds++)
|
||||||
if (__put_user(fds[j].revents, &ufds->revents))
|
if (__put_user(fds[j].revents, &ufds->revents))
|
||||||
goto out_fds;
|
goto out_fds;
|
||||||
}
|
}
|
||||||
walk = walk->next;
|
|
||||||
}
|
|
||||||
err = fdcount;
|
err = fdcount;
|
||||||
if (!fdcount && signal_pending(current))
|
|
||||||
err = -EINTR;
|
|
||||||
out_fds:
|
out_fds:
|
||||||
walk = head;
|
walk = head->next;
|
||||||
while(walk!=NULL) {
|
while (walk) {
|
||||||
struct poll_list *pp = walk->next;
|
struct poll_list *pos = walk;
|
||||||
if (walk != stack_pp)
|
walk = walk->next;
|
||||||
kfree(walk);
|
kfree(pos);
|
||||||
walk = pp;
|
|
||||||
}
|
}
|
||||||
poll_freewait(&table);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue