fs/userfaultfd.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 52de29000c7e..bd739488bb29 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -473,6 +473,16 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) goto out; } + /* + * If this is a kernel fault, and we're retrying, consider + * it fatal. Otherwise we have deadlocks and other nasty + * stuff. + */ + if (vmf->flags & FAULT_FLAG_TRIED) { + if (WARN_ON_ONCE(!(vmf->flags & FAULT_FLAG_USER))) + goto out; + } + /* * Handle nowait, not much to do other than tell it to retry * and wait. @@ -516,33 +526,12 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) vmf->flags, reason); mmap_read_unlock(mm); + /* We'll wait for up to a second, and then return VM_FAULT_RETRY */ if (likely(must_wait && !READ_ONCE(ctx->released) && !userfaultfd_signal_pending(vmf->flags))) { wake_up_poll(&ctx->fd_wqh, EPOLLIN); - schedule(); + schedule_timeout(HZ); ret |= VM_FAULT_MAJOR; - - /* - * False wakeups can orginate even from rwsem before - * up_read() however userfaults will wait either for a - * targeted wakeup on the specific uwq waitqueue from - * wake_userfault() or for signals or for uffd - * release. - */ - while (!READ_ONCE(uwq.waken)) { - /* - * This needs the full smp_store_mb() - * guarantee as the state write must be - * visible to other CPUs before reading - * uwq.waken from other CPUs. - */ - set_current_state(blocking_state); - if (READ_ONCE(uwq.waken) || - READ_ONCE(ctx->released) || - userfaultfd_signal_pending(vmf->flags)) - break; - schedule(); - } } __set_current_state(TASK_RUNNING);