diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 105 |
1 files changed, 77 insertions, 28 deletions
diff --git a/fs/select.c b/fs/select.c index 87df51eadcf2..0fe0e1469df3 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -109,11 +109,11 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
109 | void poll_initwait(struct poll_wqueues *pwq) | 109 | void poll_initwait(struct poll_wqueues *pwq) |
110 | { | 110 | { |
111 | init_poll_funcptr(&pwq->pt, __pollwait); | 111 | init_poll_funcptr(&pwq->pt, __pollwait); |
112 | pwq->polling_task = current; | ||
112 | pwq->error = 0; | 113 | pwq->error = 0; |
113 | pwq->table = NULL; | 114 | pwq->table = NULL; |
114 | pwq->inline_index = 0; | 115 | pwq->inline_index = 0; |
115 | } | 116 | } |
116 | |||
117 | EXPORT_SYMBOL(poll_initwait); | 117 | EXPORT_SYMBOL(poll_initwait); |
118 | 118 | ||
119 | static void free_poll_entry(struct poll_table_entry *entry) | 119 | static void free_poll_entry(struct poll_table_entry *entry) |
@@ -142,12 +142,10 @@ void poll_freewait(struct poll_wqueues *pwq) | |||
142 | free_page((unsigned long) old); | 142 | free_page((unsigned long) old); |
143 | } | 143 | } |
144 | } | 144 | } |
145 | |||
146 | EXPORT_SYMBOL(poll_freewait); | 145 | EXPORT_SYMBOL(poll_freewait); |
147 | 146 | ||
148 | static struct poll_table_entry *poll_get_entry(poll_table *_p) | 147 | static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) |
149 | { | 148 | { |
150 | struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt); | ||
151 | struct poll_table_page *table = p->table; | 149 | struct poll_table_page *table = p->table; |
152 | 150 | ||
153 | if (p->inline_index < N_INLINE_POLL_ENTRIES) | 151 | if (p->inline_index < N_INLINE_POLL_ENTRIES) |
@@ -159,7 +157,6 @@ static struct poll_table_entry *poll_get_entry(poll_table *_p) | |||
159 | new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL); | 157 | new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL); |
160 | if (!new_table) { | 158 | if (!new_table) { |
161 | p->error = -ENOMEM; | 159 | p->error = -ENOMEM; |
162 | __set_current_state(TASK_RUNNING); | ||
163 | return NULL; | 160 | return NULL; |
164 | } | 161 | } |
165 | new_table->entry = new_table->entries; | 162 | new_table->entry = new_table->entries; |
@@ -171,20 +168,75 @@ static struct poll_table_entry *poll_get_entry(poll_table *_p) | |||
171 | return table->entry++; | 168 | return table->entry++; |
172 | } | 169 | } |
173 | 170 | ||
171 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
172 | { | ||
173 | struct poll_wqueues *pwq = wait->private; | ||
174 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); | ||
175 | |||
176 | /* | ||
177 | * Although this function is called under waitqueue lock, LOCK | ||
178 | * doesn't imply write barrier and the users expect write | ||
179 | * barrier semantics on wakeup functions. The following | ||
180 | * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up() | ||
181 | * and is paired with set_mb() in poll_schedule_timeout. | ||
182 | */ | ||
183 | smp_wmb(); | ||
184 | pwq->triggered = 1; | ||
185 | |||
186 | /* | ||
187 | * Perform the default wake up operation using a dummy | ||
188 | * waitqueue. | ||
189 | * | ||
190 | * TODO: This is hacky but there currently is no interface to | ||
191 | * pass in @sync. @sync is scheduled to be removed and once | ||
192 | * that happens, wake_up_process() can be used directly. | ||
193 | */ | ||
194 | return default_wake_function(&dummy_wait, mode, sync, key); | ||
195 | } | ||
196 | |||
174 | /* Add a new entry */ | 197 | /* Add a new entry */ |
175 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | 198 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, |
176 | poll_table *p) | 199 | poll_table *p) |
177 | { | 200 | { |
178 | struct poll_table_entry *entry = poll_get_entry(p); | 201 | struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); |
202 | struct poll_table_entry *entry = poll_get_entry(pwq); | ||
179 | if (!entry) | 203 | if (!entry) |
180 | return; | 204 | return; |
181 | get_file(filp); | 205 | get_file(filp); |
182 | entry->filp = filp; | 206 | entry->filp = filp; |
183 | entry->wait_address = wait_address; | 207 | entry->wait_address = wait_address; |
184 | init_waitqueue_entry(&entry->wait, current); | 208 | init_waitqueue_func_entry(&entry->wait, pollwake); |
209 | entry->wait.private = pwq; | ||
185 | add_wait_queue(wait_address, &entry->wait); | 210 | add_wait_queue(wait_address, &entry->wait); |
186 | } | 211 | } |
187 | 212 | ||
213 | int poll_schedule_timeout(struct poll_wqueues *pwq, int state, | ||
214 | ktime_t *expires, unsigned long slack) | ||
215 | { | ||
216 | int rc = -EINTR; | ||
217 | |||
218 | set_current_state(state); | ||
219 | if (!pwq->triggered) | ||
220 | rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS); | ||
221 | __set_current_state(TASK_RUNNING); | ||
222 | |||
223 | /* | ||
224 | * Prepare for the next iteration. | ||
225 | * | ||
226 | * The following set_mb() serves two purposes. First, it's | ||
227 | * the counterpart rmb of the wmb in pollwake() such that data | ||
228 | * written before wake up is always visible after wake up. | ||
229 | * Second, the full barrier guarantees that triggered clearing | ||
230 | * doesn't pass event check of the next iteration. Note that | ||
231 | * this problem doesn't exist for the first iteration as | ||
232 | * add_wait_queue() has full barrier semantics. | ||
233 | */ | ||
234 | set_mb(pwq->triggered, 0); | ||
235 | |||
236 | return rc; | ||
237 | } | ||
238 | EXPORT_SYMBOL(poll_schedule_timeout); | ||
239 | |||
188 | /** | 240 | /** |
189 | * poll_select_set_timeout - helper function to setup the timeout value | 241 | * poll_select_set_timeout - helper function to setup the timeout value |
190 | * @to: pointer to timespec variable for the final timeout | 242 | * @to: pointer to timespec variable for the final timeout |
@@ -340,8 +392,6 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | |||
340 | for (;;) { | 392 | for (;;) { |
341 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; | 393 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; |
342 | 394 | ||
343 | set_current_state(TASK_INTERRUPTIBLE); | ||
344 | |||
345 | inp = fds->in; outp = fds->out; exp = fds->ex; | 395 | inp = fds->in; outp = fds->out; exp = fds->ex; |
346 | rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex; | 396 | rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex; |
347 | 397 | ||
@@ -411,10 +461,10 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | |||
411 | to = &expire; | 461 | to = &expire; |
412 | } | 462 | } |
413 | 463 | ||
414 | if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) | 464 | if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE, |
465 | to, slack)) | ||
415 | timed_out = 1; | 466 | timed_out = 1; |
416 | } | 467 | } |
417 | __set_current_state(TASK_RUNNING); | ||
418 | 468 | ||
419 | poll_freewait(&table); | 469 | poll_freewait(&table); |
420 | 470 | ||
@@ -507,8 +557,8 @@ out_nofds: | |||
507 | return ret; | 557 | return ret; |
508 | } | 558 | } |
509 | 559 | ||
510 | asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, | 560 | SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, |
511 | fd_set __user *exp, struct timeval __user *tvp) | 561 | fd_set __user *, exp, struct timeval __user *, tvp) |
512 | { | 562 | { |
513 | struct timespec end_time, *to = NULL; | 563 | struct timespec end_time, *to = NULL; |
514 | struct timeval tv; | 564 | struct timeval tv; |
@@ -532,9 +582,9 @@ asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
532 | } | 582 | } |
533 | 583 | ||
534 | #ifdef HAVE_SET_RESTORE_SIGMASK | 584 | #ifdef HAVE_SET_RESTORE_SIGMASK |
535 | asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, | 585 | static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, |
536 | fd_set __user *exp, struct timespec __user *tsp, | 586 | fd_set __user *exp, struct timespec __user *tsp, |
537 | const sigset_t __user *sigmask, size_t sigsetsize) | 587 | const sigset_t __user *sigmask, size_t sigsetsize) |
538 | { | 588 | { |
539 | sigset_t ksigmask, sigsaved; | 589 | sigset_t ksigmask, sigsaved; |
540 | struct timespec ts, end_time, *to = NULL; | 590 | struct timespec ts, end_time, *to = NULL; |
@@ -560,7 +610,7 @@ asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, | |||
560 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | 610 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
561 | } | 611 | } |
562 | 612 | ||
563 | ret = core_sys_select(n, inp, outp, exp, &end_time); | 613 | ret = core_sys_select(n, inp, outp, exp, to); |
564 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); | 614 | ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
565 | 615 | ||
566 | if (ret == -ERESTARTNOHAND) { | 616 | if (ret == -ERESTARTNOHAND) { |
@@ -586,8 +636,9 @@ asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, | |||
586 | * which has a pointer to the sigset_t itself followed by a size_t containing | 636 | * which has a pointer to the sigset_t itself followed by a size_t containing |
587 | * the sigset size. | 637 | * the sigset size. |
588 | */ | 638 | */ |
589 | asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, | 639 | SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, |
590 | fd_set __user *exp, struct timespec __user *tsp, void __user *sig) | 640 | fd_set __user *, exp, struct timespec __user *, tsp, |
641 | void __user *, sig) | ||
591 | { | 642 | { |
592 | size_t sigsetsize = 0; | 643 | size_t sigsetsize = 0; |
593 | sigset_t __user *up = NULL; | 644 | sigset_t __user *up = NULL; |
@@ -600,7 +651,7 @@ asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, | |||
600 | return -EFAULT; | 651 | return -EFAULT; |
601 | } | 652 | } |
602 | 653 | ||
603 | return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize); | 654 | return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize); |
604 | } | 655 | } |
605 | #endif /* HAVE_SET_RESTORE_SIGMASK */ | 656 | #endif /* HAVE_SET_RESTORE_SIGMASK */ |
606 | 657 | ||
@@ -666,7 +717,6 @@ static int do_poll(unsigned int nfds, struct poll_list *list, | |||
666 | for (;;) { | 717 | for (;;) { |
667 | struct poll_list *walk; | 718 | struct poll_list *walk; |
668 | 719 | ||
669 | set_current_state(TASK_INTERRUPTIBLE); | ||
670 | for (walk = list; walk != NULL; walk = walk->next) { | 720 | for (walk = list; walk != NULL; walk = walk->next) { |
671 | struct pollfd * pfd, * pfd_end; | 721 | struct pollfd * pfd, * pfd_end; |
672 | 722 | ||
@@ -709,10 +759,9 @@ static int do_poll(unsigned int nfds, struct poll_list *list, | |||
709 | to = &expire; | 759 | to = &expire; |
710 | } | 760 | } |
711 | 761 | ||
712 | if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) | 762 | if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) |
713 | timed_out = 1; | 763 | timed_out = 1; |
714 | } | 764 | } |
715 | __set_current_state(TASK_RUNNING); | ||
716 | return count; | 765 | return count; |
717 | } | 766 | } |
718 | 767 | ||
@@ -806,8 +855,8 @@ static long do_restart_poll(struct restart_block *restart_block) | |||
806 | return ret; | 855 | return ret; |
807 | } | 856 | } |
808 | 857 | ||
809 | asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, | 858 | SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, |
810 | long timeout_msecs) | 859 | long, timeout_msecs) |
811 | { | 860 | { |
812 | struct timespec end_time, *to = NULL; | 861 | struct timespec end_time, *to = NULL; |
813 | int ret; | 862 | int ret; |
@@ -841,9 +890,9 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, | |||
841 | } | 890 | } |
842 | 891 | ||
843 | #ifdef HAVE_SET_RESTORE_SIGMASK | 892 | #ifdef HAVE_SET_RESTORE_SIGMASK |
844 | asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, | 893 | SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, |
845 | struct timespec __user *tsp, const sigset_t __user *sigmask, | 894 | struct timespec __user *, tsp, const sigset_t __user *, sigmask, |
846 | size_t sigsetsize) | 895 | size_t, sigsetsize) |
847 | { | 896 | { |
848 | sigset_t ksigmask, sigsaved; | 897 | sigset_t ksigmask, sigsaved; |
849 | struct timespec ts, end_time, *to = NULL; | 898 | struct timespec ts, end_time, *to = NULL; |