diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-10-09 03:02:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-10-09 03:02:35 -0400 |
commit | 1236d6bb6e19fc72ffc6bbcdeb1bfefe450e54ee (patch) | |
tree | 47da3feee8e263e8c9352c85cf518e624be3c211 /fs/userfaultfd.c | |
parent | 750b1a6894ecc9b178c6e3d0a1170122971b2036 (diff) | |
parent | 8a5776a5f49812d29fe4b2d0a2d71675c3facf3f (diff) |
Merge 4.14-rc4 into staging-next
We want the staging/iio fixes in here as well to handle merge issues.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/userfaultfd.c')
-rw-r--r-- | fs/userfaultfd.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index ef4b48d1ea42..1c713fd5b3e6 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c | |||
@@ -588,6 +588,12 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, | |||
588 | break; | 588 | break; |
589 | if (ACCESS_ONCE(ctx->released) || | 589 | if (ACCESS_ONCE(ctx->released) || |
590 | fatal_signal_pending(current)) { | 590 | fatal_signal_pending(current)) { |
591 | /* | ||
592 | * &ewq->wq may be queued in fork_event, but | ||
593 | * __remove_wait_queue ignores the head | ||
594 | * parameter. It would be a problem if it | ||
595 | * didn't. | ||
596 | */ | ||
591 | __remove_wait_queue(&ctx->event_wqh, &ewq->wq); | 597 | __remove_wait_queue(&ctx->event_wqh, &ewq->wq); |
592 | if (ewq->msg.event == UFFD_EVENT_FORK) { | 598 | if (ewq->msg.event == UFFD_EVENT_FORK) { |
593 | struct userfaultfd_ctx *new; | 599 | struct userfaultfd_ctx *new; |
@@ -1061,6 +1067,12 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, | |||
1061 | (unsigned long) | 1067 | (unsigned long) |
1062 | uwq->msg.arg.reserved.reserved1; | 1068 | uwq->msg.arg.reserved.reserved1; |
1063 | list_move(&uwq->wq.entry, &fork_event); | 1069 | list_move(&uwq->wq.entry, &fork_event); |
1070 | /* | ||
1071 | * fork_nctx can be freed as soon as | ||
1072 | * we drop the lock, unless we take a | ||
1073 | * reference on it. | ||
1074 | */ | ||
1075 | userfaultfd_ctx_get(fork_nctx); | ||
1064 | spin_unlock(&ctx->event_wqh.lock); | 1076 | spin_unlock(&ctx->event_wqh.lock); |
1065 | ret = 0; | 1077 | ret = 0; |
1066 | break; | 1078 | break; |
@@ -1091,19 +1103,53 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, | |||
1091 | 1103 | ||
1092 | if (!ret && msg->event == UFFD_EVENT_FORK) { | 1104 | if (!ret && msg->event == UFFD_EVENT_FORK) { |
1093 | ret = resolve_userfault_fork(ctx, fork_nctx, msg); | 1105 | ret = resolve_userfault_fork(ctx, fork_nctx, msg); |
1106 | spin_lock(&ctx->event_wqh.lock); | ||
1107 | if (!list_empty(&fork_event)) { | ||
1108 | /* | ||
1109 | * The fork thread didn't abort, so we can | ||
1110 | * drop the temporary refcount. | ||
1111 | */ | ||
1112 | userfaultfd_ctx_put(fork_nctx); | ||
1113 | |||
1114 | uwq = list_first_entry(&fork_event, | ||
1115 | typeof(*uwq), | ||
1116 | wq.entry); | ||
1117 | /* | ||
1118 | * If fork_event list wasn't empty and in turn | ||
1119 | * the event wasn't already released by fork | ||
1120 | * (the event is allocated on fork kernel | ||
1121 | * stack), put the event back to its place in | ||
1122 | * the event_wq. fork_event head will be freed | ||
1123 | * as soon as we return so the event cannot | ||
1124 | * stay queued there no matter the current | ||
1125 | * "ret" value. | ||
1126 | */ | ||
1127 | list_del(&uwq->wq.entry); | ||
1128 | __add_wait_queue(&ctx->event_wqh, &uwq->wq); | ||
1094 | 1129 | ||
1095 | if (!ret) { | 1130 | /* |
1096 | spin_lock(&ctx->event_wqh.lock); | 1131 | * Leave the event in the waitqueue and report |
1097 | if (!list_empty(&fork_event)) { | 1132 | * error to userland if we failed to resolve |
1098 | uwq = list_first_entry(&fork_event, | 1133 | * the userfault fork. |
1099 | typeof(*uwq), | 1134 | */ |
1100 | wq.entry); | 1135 | if (likely(!ret)) |
1101 | list_del(&uwq->wq.entry); | ||
1102 | __add_wait_queue(&ctx->event_wqh, &uwq->wq); | ||
1103 | userfaultfd_event_complete(ctx, uwq); | 1136 | userfaultfd_event_complete(ctx, uwq); |
1104 | } | 1137 | } else { |
1105 | spin_unlock(&ctx->event_wqh.lock); | 1138 | /* |
1139 | * Here the fork thread aborted and the | ||
1140 | * refcount from the fork thread on fork_nctx | ||
1141 | * has already been released. We still hold | ||
1142 | * the reference we took before releasing the | ||
1143 | * lock above. If resolve_userfault_fork | ||
1144 | * failed we've to drop it because the | ||
1145 | * fork_nctx has to be freed in such case. If | ||
1146 | * it succeeded we'll hold it because the new | ||
1147 | * uffd references it. | ||
1148 | */ | ||
1149 | if (ret) | ||
1150 | userfaultfd_ctx_put(fork_nctx); | ||
1106 | } | 1151 | } |
1152 | spin_unlock(&ctx->event_wqh.lock); | ||
1107 | } | 1153 | } |
1108 | 1154 | ||
1109 | return ret; | 1155 | return ret; |