Commit 252e5725cfb55a89e54888317856903fef9d5031
Committed by
Linus Torvalds
1 parent
759d7c6c47
Exists in
master
and in
4 other branches
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>
Showing 1 changed file with 36 additions and 56 deletions Side-by-side Diff
fs/select.c
... | ... | @@ -651,86 +651,66 @@ |
651 | 651 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) |
652 | 652 | { |
653 | 653 | struct poll_wqueues table; |
654 | - int fdcount, err; | |
655 | - unsigned int i; | |
656 | - struct poll_list *head; | |
657 | - struct poll_list *walk; | |
654 | + int err = -EFAULT, fdcount, len, size; | |
658 | 655 | /* Allocate small arguments on the stack to save memory and be |
659 | 656 | faster - use long to make sure the buffer is aligned properly |
660 | 657 | on 64 bit archs to avoid unaligned access */ |
661 | 658 | long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; |
662 | - struct poll_list *stack_pp = NULL; | |
659 | + struct poll_list *const head = (struct poll_list *)stack_pps; | |
660 | + struct poll_list *walk = head; | |
661 | + unsigned long todo = nfds; | |
663 | 662 | |
664 | - /* Do a sanity check on nfds ... */ | |
665 | 663 | if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
666 | 664 | return -EINVAL; |
667 | 665 | |
668 | - poll_initwait(&table); | |
666 | + len = min_t(unsigned int, nfds, N_STACK_PPS); | |
667 | + for (;;) { | |
668 | + walk->next = NULL; | |
669 | + walk->len = len; | |
670 | + if (!len) | |
671 | + break; | |
669 | 672 | |
670 | - head = NULL; | |
671 | - walk = NULL; | |
672 | - i = nfds; | |
673 | - err = -ENOMEM; | |
674 | - while(i!=0) { | |
675 | - struct poll_list *pp; | |
676 | - int num, size; | |
677 | - if (stack_pp == NULL) | |
678 | - num = N_STACK_PPS; | |
679 | - else | |
680 | - num = POLLFD_PER_PAGE; | |
681 | - if (num > i) | |
682 | - num = i; | |
683 | - size = sizeof(struct poll_list) + sizeof(struct pollfd)*num; | |
684 | - if (!stack_pp) | |
685 | - stack_pp = pp = (struct poll_list *)stack_pps; | |
686 | - else { | |
687 | - pp = kmalloc(size, GFP_KERNEL); | |
688 | - if (!pp) | |
689 | - goto out_fds; | |
690 | - } | |
691 | - pp->next=NULL; | |
692 | - pp->len = num; | |
693 | - if (head == NULL) | |
694 | - head = pp; | |
695 | - else | |
696 | - walk->next = pp; | |
673 | + if (copy_from_user(walk->entries, ufds + nfds-todo, | |
674 | + sizeof(struct pollfd) * walk->len)) | |
675 | + goto out_fds; | |
697 | 676 | |
698 | - walk = pp; | |
699 | - if (copy_from_user(pp->entries, ufds + nfds-i, | |
700 | - sizeof(struct pollfd)*num)) { | |
701 | - err = -EFAULT; | |
677 | + todo -= walk->len; | |
678 | + if (!todo) | |
679 | + break; | |
680 | + | |
681 | + len = min(todo, POLLFD_PER_PAGE); | |
682 | + size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; | |
683 | + walk = walk->next = kmalloc(size, GFP_KERNEL); | |
684 | + if (!walk) { | |
685 | + err = -ENOMEM; | |
702 | 686 | goto out_fds; |
703 | 687 | } |
704 | - i -= pp->len; | |
705 | 688 | } |
706 | 689 | |
690 | + poll_initwait(&table); | |
707 | 691 | fdcount = do_poll(nfds, head, &table, timeout); |
692 | + if (!fdcount && signal_pending(current)) | |
693 | + fdcount = -EINTR; | |
694 | + poll_freewait(&table); | |
708 | 695 | |
709 | - /* OK, now copy the revents fields back to user space. */ | |
710 | - walk = head; | |
711 | - err = -EFAULT; | |
712 | - while(walk != NULL) { | |
696 | + for (walk = head; walk; walk = walk->next) { | |
713 | 697 | struct pollfd *fds = walk->entries; |
714 | 698 | int j; |
715 | 699 | |
716 | - for (j=0; j < walk->len; j++, ufds++) { | |
717 | - if(__put_user(fds[j].revents, &ufds->revents)) | |
700 | + for (j = 0; j < walk->len; j++, ufds++) | |
701 | + if (__put_user(fds[j].revents, &ufds->revents)) | |
718 | 702 | goto out_fds; |
719 | - } | |
720 | - walk = walk->next; | |
721 | 703 | } |
704 | + | |
722 | 705 | err = fdcount; |
723 | - if (!fdcount && signal_pending(current)) | |
724 | - err = -EINTR; | |
725 | 706 | out_fds: |
726 | - walk = head; | |
727 | - while(walk!=NULL) { | |
728 | - struct poll_list *pp = walk->next; | |
729 | - if (walk != stack_pp) | |
730 | - kfree(walk); | |
731 | - walk = pp; | |
707 | + walk = head->next; | |
708 | + while (walk) { | |
709 | + struct poll_list *pos = walk; | |
710 | + walk = walk->next; | |
711 | + kfree(pos); | |
732 | 712 | } |
733 | - poll_freewait(&table); | |
713 | + | |
734 | 714 | return err; |
735 | 715 | } |
736 | 716 |