diff mbox

[02/23] vfs: Implement unpoll_file.

Message ID 1243893048-17031-2-git-send-email-ebiederm@xmission.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Eric W. Biederman June 1, 2009, 9:50 p.m. UTC
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(-)

Comments

Al Viro June 6, 2009, 8:08 a.m. UTC | #1
On Mon, Jun 01, 2009 at 02:50:27PM -0700, Eric W. Biederman wrote:
> 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.

Erm...  Seeing that drivers and filesystems tend to have fsckloads of
other state of their own, why do we treat that separately?
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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 */