Commit 536ebe9ca999f6d0903d91698678ccc1742e8dd9
Committed by
Ingo Molnar
1 parent
b74e6278fd
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
sched, fanotify: Deal with nested sleeps
As per e23738a7300a ("sched, inotify: Deal with nested sleeps"). fanotify_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. Reported-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Reported-by: Sedat Dilek <sedat.dilek@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Takashi Iwai <tiwai@suse.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Eric Paris <eparis@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Eric Paris <eparis@redhat.com> Link: http://lkml.kernel.org/r/20141216152838.GZ3337@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
Showing 1 changed file with 5 additions and 5 deletions Side-by-side Diff
fs/notify/fanotify/fanotify_user.c
... | ... | @@ -259,16 +259,15 @@ |
259 | 259 | struct fsnotify_event *kevent; |
260 | 260 | char __user *start; |
261 | 261 | int ret; |
262 | - DEFINE_WAIT(wait); | |
262 | + DEFINE_WAIT_FUNC(wait, woken_wake_function); | |
263 | 263 | |
264 | 264 | start = buf; |
265 | 265 | group = file->private_data; |
266 | 266 | |
267 | 267 | pr_debug("%s: group=%p\n", __func__, group); |
268 | 268 | |
269 | + add_wait_queue(&group->notification_waitq, &wait); | |
269 | 270 | while (1) { |
270 | - prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE); | |
271 | - | |
272 | 271 | mutex_lock(&group->notification_mutex); |
273 | 272 | kevent = get_one_event(group, count); |
274 | 273 | mutex_unlock(&group->notification_mutex); |
... | ... | @@ -289,7 +288,8 @@ |
289 | 288 | |
290 | 289 | if (start != buf) |
291 | 290 | break; |
292 | - schedule(); | |
291 | + | |
292 | + wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); | |
293 | 293 | continue; |
294 | 294 | } |
295 | 295 | |
296 | 296 | |
... | ... | @@ -318,8 +318,8 @@ |
318 | 318 | buf += ret; |
319 | 319 | count -= ret; |
320 | 320 | } |
321 | + remove_wait_queue(&group->notification_waitq, &wait); | |
321 | 322 | |
322 | - finish_wait(&group->notification_waitq, &wait); | |
323 | 323 | if (start != buf && ret != -EFAULT) |
324 | 324 | ret = buf - start; |
325 | 325 | return ret; |