aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2014-09-24 04:18:50 -0400
committerIngo Molnar <mingo@kernel.org>2014-10-28 05:55:37 -0400
commite23738a7300a7591a57a22f47b813fd1b53ec404 (patch)
tree7801ab095f6b2d1091254806d37da2b383e22acb /fs/notify
parent1029a2b52c09e479fd7b07275812ad97868c0fb0 (diff)
sched, inotify: Deal with nested sleeps
inotify_read is a wait loop with sleeps in. Wait loops rely on task_struct::state and sleeps do too, since that's the only means of actually sleeping. Therefore the nested sleeps destroy the wait loop state and the wait loop breaks the sleep functions that assume TASK_RUNNING (mutex_lock). Fix this by using the new woken_wake_function and wait_woken() stuff, which registers wakeups in wait and thereby allows shrinking the task_state::state changes to the actual sleep part. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: tglx@linutronix.de Cc: ilya.dryomov@inktank.com Cc: umgwanakikbuti@gmail.com Cc: Robert Love <rlove@rlove.org> Cc: Eric Paris <eparis@parisplace.org> Cc: John McCutchan <john@johnmccutchan.com> Cc: Robert Love <rlove@rlove.org> Cc: Oleg Nesterov <oleg@redhat.com> Link: http://lkml.kernel.org/r/20140924082242.254858080@infradead.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'fs/notify')
-rw-r--r--fs/notify/inotify/inotify_user.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index daf76652fe58..283aa312d745 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -227,14 +227,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
227 struct fsnotify_event *kevent; 227 struct fsnotify_event *kevent;
228 char __user *start; 228 char __user *start;
229 int ret; 229 int ret;
230 DEFINE_WAIT(wait); 230 DEFINE_WAIT_FUNC(wait, woken_wake_function);
231 231
232 start = buf; 232 start = buf;
233 group = file->private_data; 233 group = file->private_data;
234 234
235 add_wait_queue(&group->notification_waitq, &wait);
235 while (1) { 236 while (1) {
236 prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE);
237
238 mutex_lock(&group->notification_mutex); 237 mutex_lock(&group->notification_mutex);
239 kevent = get_one_event(group, count); 238 kevent = get_one_event(group, count);
240 mutex_unlock(&group->notification_mutex); 239 mutex_unlock(&group->notification_mutex);
@@ -264,10 +263,10 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
264 if (start != buf) 263 if (start != buf)
265 break; 264 break;
266 265
267 schedule(); 266 wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
268 } 267 }
268 remove_wait_queue(&group->notification_waitq, &wait);
269 269
270 finish_wait(&group->notification_waitq, &wait);
271 if (start != buf && ret != -EFAULT) 270 if (start != buf && ret != -EFAULT)
272 ret = buf - start; 271 ret = buf - start;
273 return ret; 272 return ret;