diff options
| author | Andrew Lehmer <alehmer@google.com> | 2017-09-28 15:28:11 -0700 |
|---|---|---|
| committer | Andrew Lehmer <alehmer@google.com> | 2017-09-28 15:28:25 -0700 |
| commit | 0fdd4faef3aa46beb89c8a03be3ae1da42d61346 (patch) | |
| tree | d44b7edd7efceeafecafca43a5c21d4c88a41896 /kernel | |
| parent | 8ac3b7cbf14fa5d328213b1592efce6ae16f1167 (diff) | |
| parent | f2807be44c420478c7afc7cc296217521d5e623c (diff) | |
November 2017.1
Bug: 65558954
Change-Id: I3ccc21349b7ac04252c274663a04317a27597cb1
Signed-off-by: Andrew Lehmer <alehmer@google.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/events/core.c | 61 | ||||
| -rw-r--r-- | kernel/pid.c | 11 |
2 files changed, 61 insertions, 11 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index cdbf5b5e69d..75499f5c0d1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6709,6 +6709,37 @@ static void mutex_lock_double(struct mutex *a, struct mutex *b) mutex_lock_nested(b, SINGLE_DEPTH_NESTING); } +/* + * Variation on perf_event_ctx_lock_nested(), except we take two context + * mutexes. + */ +static struct perf_event_context * +__perf_event_ctx_lock_double(struct perf_event *group_leader, + struct perf_event_context *ctx) +{ + struct perf_event_context *gctx; + +again: + rcu_read_lock(); + gctx = ACCESS_ONCE(group_leader->ctx); + if (!atomic_inc_not_zero(&gctx->refcount)) { + rcu_read_unlock(); + goto again; + } + rcu_read_unlock(); + + mutex_lock_double(&gctx->mutex, &ctx->mutex); + + if (group_leader->ctx != gctx) { + mutex_unlock(&ctx->mutex); + mutex_unlock(&gctx->mutex); + put_ctx(gctx); + goto again; + } + + return gctx; +} + /** * sys_perf_event_open - open a performance event, associate it to a task/cpu * @@ -6920,14 +6951,31 @@ SYSCALL_DEFINE5(perf_event_open, } if (move_group) { - gctx = group_leader->ctx; + gctx = __perf_event_ctx_lock_double(group_leader, ctx); + + /* + * Check if we raced against another sys_perf_event_open() call + * moving the software group underneath us. + */ + if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) { + /* + * If someone moved the group out from under us, check + * if this new event wound up on the same ctx, if so + * its the regular !move_group case, otherwise fail. + */ + if (gctx != ctx) { + err = -EINVAL; + goto err_locked; + } else { + perf_event_ctx_unlock(group_leader, gctx); + move_group = 0; + } + } /* * See perf_event_ctx_lock() for comments on the details * of swizzling perf_event::ctx. */ - mutex_lock_double(&gctx->mutex, &ctx->mutex); - perf_remove_from_context(group_leader); /* @@ -6969,7 +7017,7 @@ SYSCALL_DEFINE5(perf_event_open, perf_unpin_context(ctx); if (move_group) { - mutex_unlock(&gctx->mutex); + perf_event_ctx_unlock(group_leader, gctx); put_ctx(gctx); } mutex_unlock(&ctx->mutex); @@ -7000,6 +7048,11 @@ SYSCALL_DEFINE5(perf_event_open, fd_install(event_fd, event_file); return event_fd; +err_locked: + if (move_group) + perf_event_ctx_unlock(group_leader, gctx); + mutex_unlock(&ctx->mutex); + fput(event_file); err_context: perf_unpin_context(ctx); put_ctx(ctx); diff --git a/kernel/pid.c b/kernel/pid.c index 0eb6d8e8b1d..1d6400df0c4 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -519,8 +519,11 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, if (!ns) ns = task_active_pid_ns(current); if (likely(pid_alive(task))) { - if (type != PIDTYPE_PID) + if (type != PIDTYPE_PID) { + if (type == __PIDTYPE_TGID) + type = PIDTYPE_PID; task = task->group_leader; + } nr = pid_nr_ns(task->pids[type].pid, ns); } rcu_read_unlock(); @@ -529,12 +532,6 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, } EXPORT_SYMBOL(__task_pid_nr_ns); -pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns) -{ - return pid_nr_ns(task_tgid(tsk), ns); -} -EXPORT_SYMBOL(task_tgid_nr_ns); - struct pid_namespace *task_active_pid_ns(struct task_struct *tsk) { return ns_of_pid(task_pid(tsk)); |
