[PATCH 02/23] vfs: Implement unpoll_file.

Eric W. Biederman
2009-06-01T21:51:46Z

From: Eric W. Biederman <ebiederm@maxwell.aristanetworks.com>

During a revoke operation it is necessary to stop using all state that is managed
by the underlying file operations implementation. The poll wait queue is one part
of that state.

unpoll_file achieves that by walking through a specified waitqueue. Finding
any entries that were added by select or poll of that file descriptor and
awakening them. If action was taken unpoll sleeps and repeats until
the waitqueue has no entries for the spcified file.

Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
---
fs/select.c | 31 +++++++++++++++++++++++++++++++
include/linux/poll.h | 2 ++
2 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/fs/select.c b/fs/select.c
index 0fe0e14..bd30fe8 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -941,3 +941,34 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
return ret;
}
#endif /* HAVE_SET_RESTORE_SIGMASK */
+
+#ifdef CONFIG_FILE_HOTPLUG
+static int unpoll_file_once(wait_queue_head_t *q, struct file *file)
+{
+ unsigned long flags;
+ wait_queue_t *curr, *next;
+ int found = 0;
+
+ spin_lock_irqsave(&q->lock, flags);
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ struct poll_table_entry *entry;
+ if (curr->func != pollwake)
+ continue;
+ entry = container_of(curr, struct poll_table_entry, wait);
+ if (entry->filp != file)
+ continue;
+ curr->func(curr, TASK_NORMAL, 0, NULL);
+ found = 1;
+ }
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return found;
+}
+
+void unpoll_file(wait_queue_head_t *q, struct file *file)
+{
+ while (unpoll_file_once(q, file))
+ schedule_timeout_uninterruptible(1);
+}
+EXPORT_SYMBOL(unpoll_file);
+#endif
diff --git a/include/linux/poll.h b/include/linux/poll.h
index 8c24ef8..d388620 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -131,6 +131,8 @@ extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,

extern int poll_select_set_timeout(struct timespec *to, long sec, long nsec);

+extern void unpoll_file(wait_queue_head_t *q, struct file *file);
+
#endif /* KERNEL */

#endif /* _LINUX_POLL_H */
--
1.6.3.1.54.g99dd.dirty