diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 118 |
1 files changed, 71 insertions, 47 deletions
diff --git a/fs/select.c b/fs/select.c index 1815a57d2255..b3a3a1326af6 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -29,12 +29,6 @@ | |||
29 | #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) | 29 | #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) |
30 | #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) | 30 | #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) |
31 | 31 | ||
32 | struct poll_table_entry { | ||
33 | struct file * filp; | ||
34 | wait_queue_t wait; | ||
35 | wait_queue_head_t * wait_address; | ||
36 | }; | ||
37 | |||
38 | struct poll_table_page { | 32 | struct poll_table_page { |
39 | struct poll_table_page * next; | 33 | struct poll_table_page * next; |
40 | struct poll_table_entry * entry; | 34 | struct poll_table_entry * entry; |
@@ -64,13 +58,23 @@ void poll_initwait(struct poll_wqueues *pwq) | |||
64 | init_poll_funcptr(&pwq->pt, __pollwait); | 58 | init_poll_funcptr(&pwq->pt, __pollwait); |
65 | pwq->error = 0; | 59 | pwq->error = 0; |
66 | pwq->table = NULL; | 60 | pwq->table = NULL; |
61 | pwq->inline_index = 0; | ||
67 | } | 62 | } |
68 | 63 | ||
69 | EXPORT_SYMBOL(poll_initwait); | 64 | EXPORT_SYMBOL(poll_initwait); |
70 | 65 | ||
66 | static void free_poll_entry(struct poll_table_entry *entry) | ||
67 | { | ||
68 | remove_wait_queue(entry->wait_address,&entry->wait); | ||
69 | fput(entry->filp); | ||
70 | } | ||
71 | |||
71 | void poll_freewait(struct poll_wqueues *pwq) | 72 | void poll_freewait(struct poll_wqueues *pwq) |
72 | { | 73 | { |
73 | struct poll_table_page * p = pwq->table; | 74 | struct poll_table_page * p = pwq->table; |
75 | int i; | ||
76 | for (i = 0; i < pwq->inline_index; i++) | ||
77 | free_poll_entry(pwq->inline_entries + i); | ||
74 | while (p) { | 78 | while (p) { |
75 | struct poll_table_entry * entry; | 79 | struct poll_table_entry * entry; |
76 | struct poll_table_page *old; | 80 | struct poll_table_page *old; |
@@ -78,8 +82,7 @@ void poll_freewait(struct poll_wqueues *pwq) | |||
78 | entry = p->entry; | 82 | entry = p->entry; |
79 | do { | 83 | do { |
80 | entry--; | 84 | entry--; |
81 | remove_wait_queue(entry->wait_address,&entry->wait); | 85 | free_poll_entry(entry); |
82 | fput(entry->filp); | ||
83 | } while (entry > p->entries); | 86 | } while (entry > p->entries); |
84 | old = p; | 87 | old = p; |
85 | p = p->next; | 88 | p = p->next; |
@@ -89,12 +92,14 @@ void poll_freewait(struct poll_wqueues *pwq) | |||
89 | 92 | ||
90 | EXPORT_SYMBOL(poll_freewait); | 93 | EXPORT_SYMBOL(poll_freewait); |
91 | 94 | ||
92 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | 95 | static struct poll_table_entry *poll_get_entry(poll_table *_p) |
93 | poll_table *_p) | ||
94 | { | 96 | { |
95 | struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt); | 97 | struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt); |
96 | struct poll_table_page *table = p->table; | 98 | struct poll_table_page *table = p->table; |
97 | 99 | ||
100 | if (p->inline_index < N_INLINE_POLL_ENTRIES) | ||
101 | return p->inline_entries + p->inline_index++; | ||
102 | |||
98 | if (!table || POLL_TABLE_FULL(table)) { | 103 | if (!table || POLL_TABLE_FULL(table)) { |
99 | struct poll_table_page *new_table; | 104 | struct poll_table_page *new_table; |
100 | 105 | ||
@@ -102,7 +107,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
102 | if (!new_table) { | 107 | if (!new_table) { |
103 | p->error = -ENOMEM; | 108 | p->error = -ENOMEM; |
104 | __set_current_state(TASK_RUNNING); | 109 | __set_current_state(TASK_RUNNING); |
105 | return; | 110 | return NULL; |
106 | } | 111 | } |
107 | new_table->entry = new_table->entries; | 112 | new_table->entry = new_table->entries; |
108 | new_table->next = table; | 113 | new_table->next = table; |
@@ -110,16 +115,21 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
110 | table = new_table; | 115 | table = new_table; |
111 | } | 116 | } |
112 | 117 | ||
113 | /* Add a new entry */ | 118 | return table->entry++; |
114 | { | 119 | } |
115 | struct poll_table_entry * entry = table->entry; | 120 | |
116 | table->entry = entry+1; | 121 | /* Add a new entry */ |
117 | get_file(filp); | 122 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, |
118 | entry->filp = filp; | 123 | poll_table *p) |
119 | entry->wait_address = wait_address; | 124 | { |
120 | init_waitqueue_entry(&entry->wait, current); | 125 | struct poll_table_entry *entry = poll_get_entry(p); |
121 | add_wait_queue(wait_address,&entry->wait); | 126 | if (!entry) |
122 | } | 127 | return; |
128 | get_file(filp); | ||
129 | entry->filp = filp; | ||
130 | entry->wait_address = wait_address; | ||
131 | init_waitqueue_entry(&entry->wait, current); | ||
132 | add_wait_queue(wait_address,&entry->wait); | ||
123 | } | 133 | } |
124 | 134 | ||
125 | #define FDS_IN(fds, n) (fds->in + n) | 135 | #define FDS_IN(fds, n) (fds->in + n) |
@@ -210,7 +220,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout) | |||
210 | for (i = 0; i < n; ++rinp, ++routp, ++rexp) { | 220 | for (i = 0; i < n; ++rinp, ++routp, ++rexp) { |
211 | unsigned long in, out, ex, all_bits, bit = 1, mask, j; | 221 | unsigned long in, out, ex, all_bits, bit = 1, mask, j; |
212 | unsigned long res_in = 0, res_out = 0, res_ex = 0; | 222 | unsigned long res_in = 0, res_out = 0, res_ex = 0; |
213 | struct file_operations *f_op = NULL; | 223 | const struct file_operations *f_op = NULL; |
214 | struct file *file = NULL; | 224 | struct file *file = NULL; |
215 | 225 | ||
216 | in = *inp++; out = *outp++; ex = *exp++; | 226 | in = *inp++; out = *outp++; ex = *exp++; |
@@ -221,17 +231,18 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout) | |||
221 | } | 231 | } |
222 | 232 | ||
223 | for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) { | 233 | for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) { |
234 | int fput_needed; | ||
224 | if (i >= n) | 235 | if (i >= n) |
225 | break; | 236 | break; |
226 | if (!(bit & all_bits)) | 237 | if (!(bit & all_bits)) |
227 | continue; | 238 | continue; |
228 | file = fget(i); | 239 | file = fget_light(i, &fput_needed); |
229 | if (file) { | 240 | if (file) { |
230 | f_op = file->f_op; | 241 | f_op = file->f_op; |
231 | mask = DEFAULT_POLLMASK; | 242 | mask = DEFAULT_POLLMASK; |
232 | if (f_op && f_op->poll) | 243 | if (f_op && f_op->poll) |
233 | mask = (*f_op->poll)(file, retval ? NULL : wait); | 244 | mask = (*f_op->poll)(file, retval ? NULL : wait); |
234 | fput(file); | 245 | fput_light(file, fput_needed); |
235 | if ((mask & POLLIN_SET) && (in & bit)) { | 246 | if ((mask & POLLIN_SET) && (in & bit)) { |
236 | res_in |= bit; | 247 | res_in |= bit; |
237 | retval++; | 248 | retval++; |
@@ -284,16 +295,6 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout) | |||
284 | return retval; | 295 | return retval; |
285 | } | 296 | } |
286 | 297 | ||
287 | static void *select_bits_alloc(int size) | ||
288 | { | ||
289 | return kmalloc(6 * size, GFP_KERNEL); | ||
290 | } | ||
291 | |||
292 | static void select_bits_free(void *bits, int size) | ||
293 | { | ||
294 | kfree(bits); | ||
295 | } | ||
296 | |||
297 | /* | 298 | /* |
298 | * We can actually return ERESTARTSYS instead of EINTR, but I'd | 299 | * We can actually return ERESTARTSYS instead of EINTR, but I'd |
299 | * like to be certain this leads to no problems. So I return | 300 | * like to be certain this leads to no problems. So I return |
@@ -312,6 +313,8 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
312 | char *bits; | 313 | char *bits; |
313 | int ret, size, max_fdset; | 314 | int ret, size, max_fdset; |
314 | struct fdtable *fdt; | 315 | struct fdtable *fdt; |
316 | /* Allocate small arguments on the stack to save memory and be faster */ | ||
317 | char stack_fds[SELECT_STACK_ALLOC]; | ||
315 | 318 | ||
316 | ret = -EINVAL; | 319 | ret = -EINVAL; |
317 | if (n < 0) | 320 | if (n < 0) |
@@ -332,7 +335,10 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
332 | */ | 335 | */ |
333 | ret = -ENOMEM; | 336 | ret = -ENOMEM; |
334 | size = FDS_BYTES(n); | 337 | size = FDS_BYTES(n); |
335 | bits = select_bits_alloc(size); | 338 | if (6*size < SELECT_STACK_ALLOC) |
339 | bits = stack_fds; | ||
340 | else | ||
341 | bits = kmalloc(6 * size, GFP_KERNEL); | ||
336 | if (!bits) | 342 | if (!bits) |
337 | goto out_nofds; | 343 | goto out_nofds; |
338 | fds.in = (unsigned long *) bits; | 344 | fds.in = (unsigned long *) bits; |
@@ -367,7 +373,8 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
367 | ret = -EFAULT; | 373 | ret = -EFAULT; |
368 | 374 | ||
369 | out: | 375 | out: |
370 | select_bits_free(bits, size); | 376 | if (bits != stack_fds) |
377 | kfree(bits); | ||
371 | out_nofds: | 378 | out_nofds: |
372 | return ret; | 379 | return ret; |
373 | } | 380 | } |
@@ -551,14 +558,15 @@ static void do_pollfd(unsigned int num, struct pollfd * fdpage, | |||
551 | fdp = fdpage+i; | 558 | fdp = fdpage+i; |
552 | fd = fdp->fd; | 559 | fd = fdp->fd; |
553 | if (fd >= 0) { | 560 | if (fd >= 0) { |
554 | struct file * file = fget(fd); | 561 | int fput_needed; |
562 | struct file * file = fget_light(fd, &fput_needed); | ||
555 | mask = POLLNVAL; | 563 | mask = POLLNVAL; |
556 | if (file != NULL) { | 564 | if (file != NULL) { |
557 | mask = DEFAULT_POLLMASK; | 565 | mask = DEFAULT_POLLMASK; |
558 | if (file->f_op && file->f_op->poll) | 566 | if (file->f_op && file->f_op->poll) |
559 | mask = file->f_op->poll(file, *pwait); | 567 | mask = file->f_op->poll(file, *pwait); |
560 | mask &= fdp->events | POLLERR | POLLHUP; | 568 | mask &= fdp->events | POLLERR | POLLHUP; |
561 | fput(file); | 569 | fput_light(file, fput_needed); |
562 | } | 570 | } |
563 | if (mask) { | 571 | if (mask) { |
564 | *pwait = NULL; | 572 | *pwait = NULL; |
@@ -619,6 +627,9 @@ static int do_poll(unsigned int nfds, struct poll_list *list, | |||
619 | return count; | 627 | return count; |
620 | } | 628 | } |
621 | 629 | ||
630 | #define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \ | ||
631 | sizeof(struct pollfd)) | ||
632 | |||
622 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) | 633 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) |
623 | { | 634 | { |
624 | struct poll_wqueues table; | 635 | struct poll_wqueues table; |
@@ -628,6 +639,9 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) | |||
628 | struct poll_list *walk; | 639 | struct poll_list *walk; |
629 | struct fdtable *fdt; | 640 | struct fdtable *fdt; |
630 | int max_fdset; | 641 | int max_fdset; |
642 | /* Allocate small arguments on the stack to save memory and be faster */ | ||
643 | char stack_pps[POLL_STACK_ALLOC]; | ||
644 | struct poll_list *stack_pp = NULL; | ||
631 | 645 | ||
632 | /* Do a sanity check on nfds ... */ | 646 | /* Do a sanity check on nfds ... */ |
633 | rcu_read_lock(); | 647 | rcu_read_lock(); |
@@ -645,14 +659,23 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) | |||
645 | err = -ENOMEM; | 659 | err = -ENOMEM; |
646 | while(i!=0) { | 660 | while(i!=0) { |
647 | struct poll_list *pp; | 661 | struct poll_list *pp; |
648 | pp = kmalloc(sizeof(struct poll_list)+ | 662 | int num, size; |
649 | sizeof(struct pollfd)* | 663 | if (stack_pp == NULL) |
650 | (i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i), | 664 | num = N_STACK_PPS; |
651 | GFP_KERNEL); | 665 | else |
652 | if(pp==NULL) | 666 | num = POLLFD_PER_PAGE; |
653 | goto out_fds; | 667 | if (num > i) |
668 | num = i; | ||
669 | size = sizeof(struct poll_list) + sizeof(struct pollfd)*num; | ||
670 | if (!stack_pp) | ||
671 | stack_pp = pp = (struct poll_list *)stack_pps; | ||
672 | else { | ||
673 | pp = kmalloc(size, GFP_KERNEL); | ||
674 | if (!pp) | ||
675 | goto out_fds; | ||
676 | } | ||
654 | pp->next=NULL; | 677 | pp->next=NULL; |
655 | pp->len = (i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i); | 678 | pp->len = num; |
656 | if (head == NULL) | 679 | if (head == NULL) |
657 | head = pp; | 680 | head = pp; |
658 | else | 681 | else |
@@ -660,7 +683,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) | |||
660 | 683 | ||
661 | walk = pp; | 684 | walk = pp; |
662 | if (copy_from_user(pp->entries, ufds + nfds-i, | 685 | if (copy_from_user(pp->entries, ufds + nfds-i, |
663 | sizeof(struct pollfd)*pp->len)) { | 686 | sizeof(struct pollfd)*num)) { |
664 | err = -EFAULT; | 687 | err = -EFAULT; |
665 | goto out_fds; | 688 | goto out_fds; |
666 | } | 689 | } |
@@ -689,7 +712,8 @@ out_fds: | |||
689 | walk = head; | 712 | walk = head; |
690 | while(walk!=NULL) { | 713 | while(walk!=NULL) { |
691 | struct poll_list *pp = walk->next; | 714 | struct poll_list *pp = walk->next; |
692 | kfree(walk); | 715 | if (walk != stack_pp) |
716 | kfree(walk); | ||
693 | walk = pp; | 717 | walk = pp; |
694 | } | 718 | } |
695 | poll_freewait(&table); | 719 | poll_freewait(&table); |