diff options
Diffstat (limited to 'fs/select.c')
| -rw-r--r-- | fs/select.c | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/fs/select.c b/fs/select.c index 0fe0e1469df3..d870237e42c7 100644 --- a/fs/select.c +++ b/fs/select.c | |||
| @@ -168,7 +168,7 @@ static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) | |||
| 168 | return table->entry++; | 168 | return table->entry++; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | 171 | static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) |
| 172 | { | 172 | { |
| 173 | struct poll_wqueues *pwq = wait->private; | 173 | struct poll_wqueues *pwq = wait->private; |
| 174 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); | 174 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); |
| @@ -194,6 +194,16 @@ static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | |||
| 194 | return default_wake_function(&dummy_wait, mode, sync, key); | 194 | return default_wake_function(&dummy_wait, mode, sync, key); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
| 198 | { | ||
| 199 | struct poll_table_entry *entry; | ||
| 200 | |||
| 201 | entry = container_of(wait, struct poll_table_entry, wait); | ||
| 202 | if (key && !((unsigned long)key & entry->key)) | ||
| 203 | return 0; | ||
| 204 | return __pollwake(wait, mode, sync, key); | ||
| 205 | } | ||
| 206 | |||
| 197 | /* Add a new entry */ | 207 | /* Add a new entry */ |
| 198 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | 208 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, |
| 199 | poll_table *p) | 209 | poll_table *p) |
| @@ -205,6 +215,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
| 205 | get_file(filp); | 215 | get_file(filp); |
| 206 | entry->filp = filp; | 216 | entry->filp = filp; |
| 207 | entry->wait_address = wait_address; | 217 | entry->wait_address = wait_address; |
| 218 | entry->key = p->key; | ||
| 208 | init_waitqueue_func_entry(&entry->wait, pollwake); | 219 | init_waitqueue_func_entry(&entry->wait, pollwake); |
| 209 | entry->wait.private = pwq; | 220 | entry->wait.private = pwq; |
| 210 | add_wait_queue(wait_address, &entry->wait); | 221 | add_wait_queue(wait_address, &entry->wait); |
| @@ -362,6 +373,18 @@ get_max: | |||
| 362 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) | 373 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) |
| 363 | #define POLLEX_SET (POLLPRI) | 374 | #define POLLEX_SET (POLLPRI) |
| 364 | 375 | ||
| 376 | static inline void wait_key_set(poll_table *wait, unsigned long in, | ||
| 377 | unsigned long out, unsigned long bit) | ||
| 378 | { | ||
| 379 | if (wait) { | ||
| 380 | wait->key = POLLEX_SET; | ||
| 381 | if (in & bit) | ||
| 382 | wait->key |= POLLIN_SET; | ||
| 383 | if (out & bit) | ||
| 384 | wait->key |= POLLOUT_SET; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 365 | int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | 388 | int do_select(int n, fd_set_bits *fds, struct timespec *end_time) |
| 366 | { | 389 | { |
| 367 | ktime_t expire, *to = NULL; | 390 | ktime_t expire, *to = NULL; |
| @@ -418,20 +441,25 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | |||
| 418 | if (file) { | 441 | if (file) { |
| 419 | f_op = file->f_op; | 442 | f_op = file->f_op; |
| 420 | mask = DEFAULT_POLLMASK; | 443 | mask = DEFAULT_POLLMASK; |
| 421 | if (f_op && f_op->poll) | 444 | if (f_op && f_op->poll) { |
| 422 | mask = (*f_op->poll)(file, retval ? NULL : wait); | 445 | wait_key_set(wait, in, out, bit); |
| 446 | mask = (*f_op->poll)(file, wait); | ||
| 447 | } | ||
| 423 | fput_light(file, fput_needed); | 448 | fput_light(file, fput_needed); |
| 424 | if ((mask & POLLIN_SET) && (in & bit)) { | 449 | if ((mask & POLLIN_SET) && (in & bit)) { |
| 425 | res_in |= bit; | 450 | res_in |= bit; |
| 426 | retval++; | 451 | retval++; |
| 452 | wait = NULL; | ||
| 427 | } | 453 | } |
| 428 | if ((mask & POLLOUT_SET) && (out & bit)) { | 454 | if ((mask & POLLOUT_SET) && (out & bit)) { |
| 429 | res_out |= bit; | 455 | res_out |= bit; |
| 430 | retval++; | 456 | retval++; |
| 457 | wait = NULL; | ||
| 431 | } | 458 | } |
| 432 | if ((mask & POLLEX_SET) && (ex & bit)) { | 459 | if ((mask & POLLEX_SET) && (ex & bit)) { |
| 433 | res_ex |= bit; | 460 | res_ex |= bit; |
| 434 | retval++; | 461 | retval++; |
| 462 | wait = NULL; | ||
| 435 | } | 463 | } |
| 436 | } | 464 | } |
| 437 | } | 465 | } |
| @@ -685,8 +713,12 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) | |||
| 685 | mask = POLLNVAL; | 713 | mask = POLLNVAL; |
| 686 | if (file != NULL) { | 714 | if (file != NULL) { |
| 687 | mask = DEFAULT_POLLMASK; | 715 | mask = DEFAULT_POLLMASK; |
| 688 | if (file->f_op && file->f_op->poll) | 716 | if (file->f_op && file->f_op->poll) { |
| 717 | if (pwait) | ||
| 718 | pwait->key = pollfd->events | | ||
| 719 | POLLERR | POLLHUP; | ||
| 689 | mask = file->f_op->poll(file, pwait); | 720 | mask = file->f_op->poll(file, pwait); |
| 721 | } | ||
| 690 | /* Mask out unneeded events. */ | 722 | /* Mask out unneeded events. */ |
| 691 | mask &= pollfd->events | POLLERR | POLLHUP; | 723 | mask &= pollfd->events | POLLERR | POLLHUP; |
| 692 | fput_light(file, fput_needed); | 724 | fput_light(file, fput_needed); |
