| @@ -2128,8 +2128,6 @@ void activate_task(struct rq *rq, struct task_struct *p, int flags) · 2127 unmodified lines |
| 2128 | { | 2128 | { |
| 2129 | if (task_on_rq_migrating(p)) | 2129 | if (task_on_rq_migrating(p)) |
| 2130 | flags |= ENQUEUE_MIGRATED; | 2130 | flags |= ENQUEUE_MIGRATED; |
| 2131 | if (flags & ENQUEUE_MIGRATED) | | |
| 2132 | sched_mm_cid_migrate_to(rq, p); | | |
| 2133 | | 2131 | |
| 2134 | enqueue_task(rq, p, flags); | 2132 | enqueue_task(rq, p, flags); |
| 2135 | | 2133 | |
| @@ -3329,7 +3327,6 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) · 1193 unmodified lines |
| 3329 | if (p->sched_class->migrate_task_rq) | 3327 | if (p->sched_class->migrate_task_rq) |
| 3330 | p->sched_class->migrate_task_rq(p, new_cpu); | 3328 | p->sched_class->migrate_task_rq(p, new_cpu); |
| 3331 | p->se.nr_migrations++; | 3329 | p->se.nr_migrations++; |
| 3332 | sched_mm_cid_migrate_from(p); | | |
| 3333 | perf_event_task_migrate(p); | 3330 | perf_event_task_migrate(p); |
| 3334 | } | 3331 | } |
| 3335 | | 3332 | |
| @@ -5280,9 +5277,6 @@ context_switch(struct rq *rq, struct task_struct *prev, · 1944 unmodified lines |
| 5280 | * | 5277 | * |
| 5281 | * kernel -> user switch + mmdrop_lazy_tlb() active | 5278 | * kernel -> user switch + mmdrop_lazy_tlb() active |
| 5282 | * user -> user switch | 5279 | * user -> user switch |
| 5283 | * | | |
| 5284 | * switch_mm_cid() needs to be updated if the barriers provided | | |
| 5285 | * by context_switch() are modified. | | |
| 5286 | */ | 5280 | */ |
| 5287 | if (!next->mm) { // to kernel | 5281 | if (!next->mm) { // to kernel |
| 5288 | enter_lazy_tlb(prev->active_mm, next); | 5282 | enter_lazy_tlb(prev->active_mm, next); |
| @@ -5312,8 +5306,7 @@ context_switch(struct rq *rq, struct task_struct *prev, · 23 unmodified lines |
| 5312 | } | 5306 | } |
| 5313 | } | 5307 | } |
| 5314 | | 5308 | |
| 5315 | /* switch_mm_cid() requires the memory barriers above. */ | 5309 | switch_mm_cid(prev, next); |
| 5316 | switch_mm_cid(rq, prev, next); | | |
| 5317 | | 5310 | |
| 5318 | /* | 5311 | /* |
| 5319 | * Tell rseq that the task was scheduled in. Must be after | 5312 | * Tell rseq that the task was scheduled in. Must be after |
| @@ -5604,7 +5597,6 @@ void sched_tick(void) · 284 unmodified lines |
| 5604 | resched_latency = cpu_resched_latency(rq); | 5597 | resched_latency = cpu_resched_latency(rq); |
| 5605 | calc_global_load_tick(rq); | 5598 | calc_global_load_tick(rq); |
| 5606 | sched_core_tick(rq); | 5599 | sched_core_tick(rq); |
| 5607 | task_tick_mm_cid(rq, donor); | | |
| 5608 | scx_tick(rq); | 5600 | scx_tick(rq); |
| 5609 | | 5601 | |
| 5610 | rq_unlock(rq, &rf); | 5602 | rq_unlock(rq, &rf); |
| @@ -10376,522 +10368,47 @@ void call_trace_sched_update_nr_running(struct rq *rq, int count) · 4765 unmodified lines |
| 10376 | } | 10368 | } |
| 10377 | | 10369 | |
| 10378 | #ifdef CONFIG_SCHED_MM_CID | 10370 | #ifdef CONFIG_SCHED_MM_CID |
| 10379 | | | |
| 10380 | /* | 10371 | /* |
| 10381 | * @cid_lock: Guarantee forward-progress of cid allocation. | 10372 | * When a task exits, the MM CID held by the task is not longer required as |
| 10382 | * | 10373 | * the task cannot return to user space. |
| 10383 | * Concurrency ID allocation within a bitmap is mostly lock-free. The cid_lock | | |
| 10384 | * is only used when contention is detected by the lock-free allocation so | | |
| 10385 | * forward progress can be guaranteed. | | |
| 10386 | */ | | |
| 10387 | DEFINE_RAW_SPINLOCK(cid_lock); | | |
| 10388 | | | |
| 10389 | /* | | |
| 10390 | * @use_cid_lock: Select cid allocation behavior: lock-free vs spinlock. | | |
| 10391 | * | | |
| 10392 | * When @use_cid_lock is 0, the cid allocation is lock-free. When contention is | | |
| 10393 | * detected, it is set to 1 to ensure that all newly coming allocations are | | |
| 10394 | * serialized by @cid_lock until the allocation which detected contention | | |
| 10395 | * completes and sets @use_cid_lock back to 0. This guarantees forward progress | | |
| 10396 | * of a cid allocation. | | |
| 10397 | */ | | |
| 10398 | int use_cid_lock; | | |
| 10399 | | | |
| 10400 | /* | | |
| 10401 | * mm_cid remote-clear implements a lock-free algorithm to clear per-mm/cpu cid | | |
| 10402 | * concurrently with respect to the execution of the source runqueue context | | |
| 10403 | * switch. | | |
| 10404 | * | | |
| 10405 | * There is one basic properties we want to guarantee here: | | |
| 10406 | * | | |
| 10407 | * (1) Remote-clear should _never_ mark a per-cpu cid UNSET when it is actively | | |
| 10408 | * used by a task. That would lead to concurrent allocation of the cid and | | |
| 10409 | * userspace corruption. | | |
| 10410 | * | | |
| 10411 | * Provide this guarantee by introducing a Dekker memory ordering to guarantee | | |
| 10412 | * that a pair of loads observe at least one of a pair of stores, which can be | | |
| 10413 | * shown as: | | |
| 10414 | * | | |
| 10415 | * X = Y = 0 | | |
| 10416 | * | | |
| 10417 | * w[X]=1 w[Y]=1 | | |
| 10418 | * MB MB | | |
| 10419 | * r[Y]=y r[X]=x | | |
| 10420 | * | | |
| 10421 | * Which guarantees that x==0 && y==0 is impossible. But rather than using | | |
| 10422 | * values 0 and 1, this algorithm cares about specific state transitions of the | | |
| 10423 | * runqueue current task (as updated by the scheduler context switch), and the | | |
| 10424 | * per-mm/cpu cid value. | | |
| 10425 | * | | |
| 10426 | * Let's introduce task (Y) which has task->mm == mm and task (N) which has | | |
| 10427 | * task->mm != mm for the rest of the discussion. There are two scheduler state | | |
| 10428 | * transitions on context switch we care about: | | |
| 10429 | * | | |
| 10430 | * (TSA) Store to rq->curr with transition from (N) to (Y) | | |
| 10431 | * | | |
| 10432 | * (TSB) Store to rq->curr with transition from (Y) to (N) | | |
| 10433 | * | | |
| 10434 | * On the remote-clear side, there is one transition we care about: | | |
| 10435 | * | | |
| 10436 | * (TMA) cmpxchg to *pcpu_cid to set the LAZY flag | | |
| 10437 | * | | |
| 10438 | * There is also a transition to UNSET state which can be performed from all | | |
| 10439 | * sides (scheduler, remote-clear). It is always performed with a cmpxchg which | | |
| 10440 | * guarantees that only a single thread will succeed: | | |
| 10441 | * | | |
| 10442 | * (TMB) cmpxchg to *pcpu_cid to mark UNSET | | |
| 10443 | * | | |
| 10444 | * Just to be clear, what we do _not_ want to happen is a transition to UNSET | | |
| 10445 | * when a thread is actively using the cid (property (1)). | | |
| 10446 | * | | |
| 10447 | * Let's looks at the relevant combinations of TSA/TSB, and TMA transitions. | | |
| 10448 | * | | |
| 10449 | * Scenario A) (TSA)+(TMA) (from next task perspective) | | |
| 10450 | * | | |
| 10451 | * CPU0 CPU1 | | |
| 10452 | * | | |
| 10453 | * Context switch CS-1 Remote-clear | | |
| 10454 | * - store to rq->curr: (N)->(Y) (TSA) - cmpxchg to *pcpu_id to LAZY (TMA) | | |
| 10455 | * (implied barrier after cmpxchg) | | |
| 10456 | * - switch_mm_cid() | | |
| 10457 | * - memory barrier (see switch_mm_cid() | | |
| 10458 | * comment explaining how this barrier | | |
| 10459 | * is combined with other scheduler | | |
| 10460 | * barriers) | | |
| 10461 | * - mm_cid_get (next) | | |
| 10462 | * - READ_ONCE(*pcpu_cid) - rcu_dereference(src_rq->curr) | | |
| 10463 | * | | |
| 10464 | * This Dekker ensures that either task (Y) is observed by the | | |
| 10465 | * rcu_dereference() or the LAZY flag is observed by READ_ONCE(), or both are | | |
| 10466 | * observed. | | |
| 10467 | * | | |
| 10468 | * If task (Y) store is observed by rcu_dereference(), it means that there is | | |
| 10469 | * still an active task on the cpu. Remote-clear will therefore not transition | | |
| 10470 | * to UNSET, which fulfills property (1). | | |
| 10471 | * | | |
| 10472 | * If task (Y) is not observed, but the lazy flag is observed by READ_ONCE(), | | |
| 10473 | * it will move its state to UNSET, which clears the percpu cid perhaps | | |
| 10474 | * uselessly (which is not an issue for correctness). Because task (Y) is not | | |
| 10475 | * observed, CPU1 can move ahead to set the state to UNSET. Because moving | | |
| 10476 | * state to UNSET is done with a cmpxchg expecting that the old state has the | | |
| 10477 | * LAZY flag set, only one thread will successfully UNSET. | | |
| 10478 | * | | |
| 10479 | * If both states (LAZY flag and task (Y)) are observed, the thread on CPU0 | | |
| 10480 | * will observe the LAZY flag and transition to UNSET (perhaps uselessly), and | | |
| 10481 | * CPU1 will observe task (Y) and do nothing more, which is fine. | | |
| 10482 | * | | |
| 10483 | * What we are effectively preventing with this Dekker is a scenario where | | |
| 10484 | * neither LAZY flag nor store (Y) are observed, which would fail property (1) | | |
| 10485 | * because this would UNSET a cid which is actively used. | | |
| 10486 | */ | 10374 | */ |
| 10487 | | | |
| 10488 | void sched_mm_cid_migrate_from(struct task_struct *t) | | |
| 10489 | { | | |
| 10490 | t->migrate_from_cpu = task_cpu(t); | | |
| 10491 | } | | |
| 10492 | | | |
| 10493 | static | | |
| 10494 | int __sched_mm_cid_migrate_from_fetch_cid(struct rq *src_rq, | | |
| 10495 | struct task_struct *t, | | |
| 10496 | struct mm_cid *src_pcpu_cid) | | |
| 10497 | { | | |
| 10498 | struct mm_struct *mm = t->mm; | | |
| 10499 | struct task_struct *src_task; | | |
| 10500 | int src_cid, last_mm_cid; | | |
| 10501 | | | |
| 10502 | if (!mm) | | |
| 10503 | return -1; | | |
| 10504 | | | |
| 10505 | last_mm_cid = t->last_mm_cid; | | |
| 10506 | /* | | |
| 10507 | * If the migrated task has no last cid, or if the current | | |
| 10508 | * task on src rq uses the cid, it means the source cid does not need | | |
| 10509 | * to be moved to the destination cpu. | | |
| 10510 | */ | | |
| 10511 | if (last_mm_cid == -1) | | |
| 10512 | return -1; | | |
| 10513 | src_cid = READ_ONCE(src_pcpu_cid->cid); | | |
| 10514 | if (!mm_cid_is_valid(src_cid) || last_mm_cid != src_cid) | | |
| 10515 | return -1; | | |
| 10516 | | | |
| 10517 | /* | | |
| 10518 | * If we observe an active task using the mm on this rq, it means we | | |
| 10519 | * are not the last task to be migrated from this cpu for this mm, so | | |
| 10520 | * there is no need to move src_cid to the destination cpu. | | |
| 10521 | */ | | |
| 10522 | guard(rcu)(); | | |
| 10523 | src_task = rcu_dereference(src_rq->curr); | | |
| 10524 | if (READ_ONCE(src_task->mm_cid_active) && src_task->mm == mm) { | | |
| 10525 | t->last_mm_cid = -1; | | |
| 10526 | return -1; | | |
| 10527 | } | | |
| 10528 | | | |
| 10529 | return src_cid; | | |
| 10530 | } | | |
| 10531 | | | |
| 10532 | static | | |
| 10533 | int __sched_mm_cid_migrate_from_try_steal_cid(struct rq *src_rq, | | |
| 10534 | struct task_struct *t, | | |
| 10535 | struct mm_cid *src_pcpu_cid, | | |
| 10536 | int src_cid) | | |
| 10537 | { | | |
| 10538 | struct task_struct *src_task; | | |
| 10539 | struct mm_struct *mm = t->mm; | | |
| 10540 | int lazy_cid; | | |
| 10541 | | | |
| 10542 | if (src_cid == -1) | | |
| 10543 | return -1; | | |
| 10544 | | | |
| 10545 | /* | | |
| 10546 | * Attempt to clear the source cpu cid to move it to the destination | | |
| 10547 | * cpu. | | |
| 10548 | */ | | |
| 10549 | lazy_cid = mm_cid_set_lazy_put(src_cid); | | |
| 10550 | if (!try_cmpxchg(&src_pcpu_cid->cid, &src_cid, lazy_cid)) | | |
| 10551 | return -1; | | |
| 10552 | | | |
| 10553 | /* | | |
| 10554 | * The implicit barrier after cmpxchg per-mm/cpu cid before loading | | |
| 10555 | * rq->curr->mm matches the scheduler barrier in context_switch() | | |
| 10556 | * between store to rq->curr and load of prev and next task's | | |
| 10557 | * per-mm/cpu cid. | | |
| 10558 | * | | |
| 10559 | * The implicit barrier after cmpxchg per-mm/cpu cid before loading | | |
| 10560 | * rq->curr->mm_cid_active matches the barrier in | | |
| 10561 | * sched_mm_cid_exit_signals(), sched_mm_cid_before_execve(), and | | |
| 10562 | * sched_mm_cid_after_execve() between store to t->mm_cid_active and | | |
| 10563 | * load of per-mm/cpu cid. | | |
| 10564 | */ | | |
| 10565 | | | |
| 10566 | /* | | |
| 10567 | * If we observe an active task using the mm on this rq after setting | | |
| 10568 | * the lazy-put flag, this task will be responsible for transitioning | | |
| 10569 | * from lazy-put flag set to MM_CID_UNSET. | | |
| 10570 | */ | | |
| 10571 | scoped_guard (rcu) { | | |
| 10572 | src_task = rcu_dereference(src_rq->curr); | | |
| 10573 | if (READ_ONCE(src_task->mm_cid_active) && src_task->mm == mm) { | | |
| 10574 | /* | | |
| 10575 | * We observed an active task for this mm, there is therefore | | |
| 10576 | * no point in moving this cid to the destination cpu. | | |
| 10577 | */ | | |
| 10578 | t->last_mm_cid = -1; | | |
| 10579 | return -1; | | |
| 10580 | } | | |
| 10581 | } | | |
| 10582 | | | |
| 10583 | /* | | |
| 10584 | * The src_cid is unused, so it can be unset. | | |
| 10585 | */ | | |
| 10586 | if (!try_cmpxchg(&src_pcpu_cid->cid, &lazy_cid, MM_CID_UNSET)) | | |
| 10587 | return -1; | | |
| 10588 | WRITE_ONCE(src_pcpu_cid->recent_cid, MM_CID_UNSET); | | |
| 10589 | return src_cid; | | |
| 10590 | } | | |
| 10591 | | | |
| 10592 | /* | | |
| 10593 | * Migration to dst cpu. Called with dst_rq lock held. | | |
| 10594 | * Interrupts are disabled, which keeps the window of cid ownership without the | | |
| 10595 | * source rq lock held small. | | |
| 10596 | */ | | |
| 10597 | void sched_mm_cid_migrate_to(struct rq *dst_rq, struct task_struct *t) | | |
| 10598 | { | | |
| 10599 | struct mm_cid *src_pcpu_cid, *dst_pcpu_cid; | | |
| 10600 | struct mm_struct *mm = t->mm; | | |
| 10601 | int src_cid, src_cpu; | | |
| 10602 | bool dst_cid_is_set; | | |
| 10603 | struct rq *src_rq; | | |
| 10604 | | | |
| 10605 | lockdep_assert_rq_held(dst_rq); | | |
| 10606 | | | |
| 10607 | if (!mm) | | |
| 10608 | return; | | |
| 10609 | src_cpu = t->migrate_from_cpu; | | |
| 10610 | if (src_cpu == -1) { | | |
| 10611 | t->last_mm_cid = -1; | | |
| 10612 | return; | | |
| 10613 | } | | |
| 10614 | /* | | |
| 10615 | * Move the src cid if the dst cid is unset. This keeps id | | |
| 10616 | * allocation closest to 0 in cases where few threads migrate around | | |
| 10617 | * many CPUs. | | |
| 10618 | * | | |
| 10619 | * If destination cid or recent cid is already set, we may have | | |
| 10620 | * to just clear the src cid to ensure compactness in frequent | | |
| 10621 | * migrations scenarios. | | |
| 10622 | * | | |
| 10623 | * It is not useful to clear the src cid when the number of threads is | | |
| 10624 | * greater or equal to the number of allowed CPUs, because user-space | | |
| 10625 | * can expect that the number of allowed cids can reach the number of | | |
| 10626 | * allowed CPUs. | | |
| 10627 | */ | | |
| 10628 | dst_pcpu_cid = per_cpu_ptr(mm->pcpu_cid, cpu_of(dst_rq)); | | |
| 10629 | dst_cid_is_set = !mm_cid_is_unset(READ_ONCE(dst_pcpu_cid->cid)) || | | |
| 10630 | !mm_cid_is_unset(READ_ONCE(dst_pcpu_cid->recent_cid)); | | |
| 10631 | if (dst_cid_is_set && atomic_read(&mm->mm_users) >= READ_ONCE(mm->nr_cpus_allowed)) | | |
| 10632 | return; | | |
| 10633 | src_pcpu_cid = per_cpu_ptr(mm->pcpu_cid, src_cpu); | | |
| 10634 | src_rq = cpu_rq(src_cpu); | | |
| 10635 | src_cid = __sched_mm_cid_migrate_from_fetch_cid(src_rq, t, src_pcpu_cid); | | |
| 10636 | if (src_cid == -1) | | |
| 10637 | return; | | |
| 10638 | src_cid = __sched_mm_cid_migrate_from_try_steal_cid(src_rq, t, src_pcpu_cid, | | |
| 10639 | src_cid); | | |
| 10640 | if (src_cid == -1) | | |
| 10641 | return; | | |
| 10642 | if (dst_cid_is_set) { | | |
| 10643 | __mm_cid_put(mm, src_cid); | | |
| 10644 | return; | | |
| 10645 | } | | |
| 10646 | /* Move src_cid to dst cpu. */ | | |
| 10647 | mm_cid_snapshot_time(dst_rq, mm); | | |
| 10648 | WRITE_ONCE(dst_pcpu_cid->cid, src_cid); | | |
| 10649 | WRITE_ONCE(dst_pcpu_cid->recent_cid, src_cid); | | |
| 10650 | } | | |
| 10651 | | | |
| 10652 | static void sched_mm_cid_remote_clear(struct mm_struct *mm, struct mm_cid *pcpu_cid, | | |
| 10653 | int cpu) | | |
| 10654 | { | | |
| 10655 | struct rq *rq = cpu_rq(cpu); | | |
| 10656 | struct task_struct *t; | | |
| 10657 | int cid, lazy_cid; | | |
| 10658 | | | |
| 10659 | cid = READ_ONCE(pcpu_cid->cid); | | |
| 10660 | if (!mm_cid_is_valid(cid)) | | |
| 10661 | return; | | |
| 10662 | | | |
| 10663 | /* | | |
| 10664 | * Clear the cpu cid if it is set to keep cid allocation compact. If | | |
| 10665 | * there happens to be other tasks left on the source cpu using this | | |
| 10666 | * mm, the next task using this mm will reallocate its cid on context | | |
| 10667 | * switch. | | |
| 10668 | */ | | |
| 10669 | lazy_cid = mm_cid_set_lazy_put(cid); | | |
| 10670 | if (!try_cmpxchg(&pcpu_cid->cid, &cid, lazy_cid)) | | |
| 10671 | return; | | |
| 10672 | | | |
| 10673 | /* | | |
| 10674 | * The implicit barrier after cmpxchg per-mm/cpu cid before loading | | |
| 10675 | * rq->curr->mm matches the scheduler barrier in context_switch() | | |
| 10676 | * between store to rq->curr and load of prev and next task's | | |
| 10677 | * per-mm/cpu cid. | | |
| 10678 | * | | |
| 10679 | * The implicit barrier after cmpxchg per-mm/cpu cid before loading | | |
| 10680 | * rq->curr->mm_cid_active matches the barrier in | | |
| 10681 | * sched_mm_cid_exit_signals(), sched_mm_cid_before_execve(), and | | |
| 10682 | * sched_mm_cid_after_execve() between store to t->mm_cid_active and | | |
| 10683 | * load of per-mm/cpu cid. | | |
| 10684 | */ | | |
| 10685 | | | |
| 10686 | /* | | |
| 10687 | * If we observe an active task using the mm on this rq after setting | | |
| 10688 | * the lazy-put flag, that task will be responsible for transitioning | | |
| 10689 | * from lazy-put flag set to MM_CID_UNSET. | | |
| 10690 | */ | | |
| 10691 | scoped_guard (rcu) { | | |
| 10692 | t = rcu_dereference(rq->curr); | | |
| 10693 | if (READ_ONCE(t->mm_cid_active) && t->mm == mm) | | |
| 10694 | return; | | |
| 10695 | } | | |
| 10696 | | | |
| 10697 | /* | | |
| 10698 | * The cid is unused, so it can be unset. | | |
| 10699 | * Disable interrupts to keep the window of cid ownership without rq | | |
| 10700 | * lock small. | | |
| 10701 | */ | | |
| 10702 | scoped_guard (irqsave) { | | |
| 10703 | if (try_cmpxchg(&pcpu_cid->cid, &lazy_cid, MM_CID_UNSET)) | | |
| 10704 | __mm_cid_put(mm, cid); | | |
| 10705 | } | | |
| 10706 | } | | |
| 10707 | | | |
| 10708 | static void sched_mm_cid_remote_clear_old(struct mm_struct *mm, int cpu) | | |
| 10709 | { | | |
| 10710 | struct rq *rq = cpu_rq(cpu); | | |
| 10711 | struct mm_cid *pcpu_cid; | | |
| 10712 | struct task_struct *curr; | | |
| 10713 | u64 rq_clock; | | |
| 10714 | | | |
| 10715 | /* | | |
| 10716 | * rq->clock load is racy on 32-bit but one spurious clear once in a | | |
| 10717 | * while is irrelevant. | | |
| 10718 | */ | | |
| 10719 | rq_clock = READ_ONCE(rq->clock); | | |
| 10720 | pcpu_cid = per_cpu_ptr(mm->pcpu_cid, cpu); | | |
| 10721 | | | |
| 10722 | /* | | |
| 10723 | * In order to take care of infrequently scheduled tasks, bump the time | | |
| 10724 | * snapshot associated with this cid if an active task using the mm is | | |
| 10725 | * observed on this rq. | | |
| 10726 | */ | | |
| 10727 | scoped_guard (rcu) { | | |
| 10728 | curr = rcu_dereference(rq->curr); | | |
| 10729 | if (READ_ONCE(curr->mm_cid_active) && curr->mm == mm) { | | |
| 10730 | WRITE_ONCE(pcpu_cid->time, rq_clock); | | |
| 10731 | return; | | |
| 10732 | } | | |
| 10733 | } | | |
| 10734 | | | |
| 10735 | if (rq_clock < pcpu_cid->time + SCHED_MM_CID_PERIOD_NS) | | |
| 10736 | return; | | |
| 10737 | sched_mm_cid_remote_clear(mm, pcpu_cid, cpu); | | |
| 10738 | } | | |
| 10739 | | | |
| 10740 | static void sched_mm_cid_remote_clear_weight(struct mm_struct *mm, int cpu, | | |
| 10741 | int weight) | | |
| 10742 | { | | |
| 10743 | struct mm_cid *pcpu_cid; | | |
| 10744 | int cid; | | |
| 10745 | | | |
| 10746 | pcpu_cid = per_cpu_ptr(mm->pcpu_cid, cpu); | | |
| 10747 | cid = READ_ONCE(pcpu_cid->cid); | | |
| 10748 | if (!mm_cid_is_valid(cid) || cid < weight) | | |
| 10749 | return; | | |
| 10750 | sched_mm_cid_remote_clear(mm, pcpu_cid, cpu); | | |
| 10751 | } | | |
| 10752 | | | |
| 10753 | static void task_mm_cid_work(struct callback_head *work) | | |
| 10754 | { | | |
| 10755 | unsigned long now = jiffies, old_scan, next_scan; | | |
| 10756 | struct task_struct *t = current; | | |
| 10757 | struct cpumask *cidmask; | | |
| 10758 | struct mm_struct *mm; | | |
| 10759 | int weight, cpu; | | |
| 10760 | | | |
| 10761 | WARN_ON_ONCE(t != container_of(work, struct task_struct, cid_work)); | | |
| 10762 | | | |
| 10763 | work->next = work; /* Prevent double-add */ | | |
| 10764 | if (t->flags & PF_EXITING) | | |
| 10765 | return; | | |
| 10766 | mm = t->mm; | | |
| 10767 | if (!mm) | | |
| 10768 | return; | | |
| 10769 | old_scan = READ_ONCE(mm->mm_cid_next_scan); | | |
| 10770 | next_scan = now + msecs_to_jiffies(MM_CID_SCAN_DELAY); | | |
| 10771 | if (!old_scan) { | | |
| 10772 | unsigned long res; | | |
| 10773 | | | |
| 10774 | res = cmpxchg(&mm->mm_cid_next_scan, old_scan, next_scan); | | |
| 10775 | if (res != old_scan) | | |
| 10776 | old_scan = res; | | |
| 10777 | else | | |
| 10778 | old_scan = next_scan; | | |
| 10779 | } | | |
| 10780 | if (time_before(now, old_scan)) | | |
| 10781 | return; | | |
| 10782 | if (!try_cmpxchg(&mm->mm_cid_next_scan, &old_scan, next_scan)) | | |
| 10783 | return; | | |
| 10784 | cidmask = mm_cidmask(mm); | | |
| 10785 | /* Clear cids that were not recently used. */ | | |
| 10786 | for_each_possible_cpu(cpu) | | |
| 10787 | sched_mm_cid_remote_clear_old(mm, cpu); | | |
| 10788 | weight = cpumask_weight(cidmask); | | |
| 10789 | /* | | |
| 10790 | * Clear cids that are greater or equal to the cidmask weight to | | |
| 10791 | * recompact it. | | |
| 10792 | */ | | |
| 10793 | for_each_possible_cpu(cpu) | | |
| 10794 | sched_mm_cid_remote_clear_weight(mm, cpu, weight); | | |
| 10795 | } | | |
| 10796 | | | |
| 10797 | void init_sched_mm_cid(struct task_struct *t) | | |
| 10798 | { | | |
| 10799 | struct mm_struct *mm = t->mm; | | |
| 10800 | int mm_users = 0; | | |
| 10801 | | | |
| 10802 | if (mm) { | | |
| 10803 | mm_users = atomic_read(&mm->mm_users); | | |
| 10804 | if (mm_users == 1) | | |
| 10805 | mm->mm_cid_next_scan = jiffies + msecs_to_jiffies(MM_CID_SCAN_DELAY); | | |
| 10806 | } | | |
| 10807 | t->cid_work.next = &t->cid_work; /* Protect against double add */ | | |
| 10808 | init_task_work(&t->cid_work, task_mm_cid_work); | | |
| 10809 | } | | |
| 10810 | | | |
| 10811 | void task_tick_mm_cid(struct rq *rq, struct task_struct *curr) | | |
| 10812 | { | | |
| 10813 | struct callback_head *work = &curr->cid_work; | | |
| 10814 | unsigned long now = jiffies; | | |
| 10815 | | | |
| 10816 | if (!curr->mm || (curr->flags & (PF_EXITING | PF_KTHREAD)) || | | |
| 10817 | work->next != work) | | |
| 10818 | return; | | |
| 10819 | if (time_before(now, READ_ONCE(curr->mm->mm_cid_next_scan))) | | |
| 10820 | return; | | |
| 10821 | | | |
| 10822 | /* No page allocation under rq lock */ | | |
| 10823 | task_work_add(curr, work, TWA_RESUME); | | |
| 10824 | } | | |
| 10825 | | | |
| 10826 | void sched_mm_cid_exit_signals(struct task_struct *t) | 10375 | void sched_mm_cid_exit_signals(struct task_struct *t) |
| 10827 | { | 10376 | { |
| 10828 | struct mm_struct *mm = t->mm; | 10377 | struct mm_struct *mm = t->mm; |
| 10829 | struct rq *rq; | | |
| 10830 | | 10378 | |
| 10831 | if (!mm) | 10379 | if (!mm || !t->mm_cid_active) |
| 10832 | return; | 10380 | return; |
| 10833 | | 10381 | |
| 10834 | preempt_disable(); | 10382 | guard(preempt)(); |
| 10835 | rq = this_rq(); | 10383 | t->mm_cid_active = 0; |
| 10836 | guard(rq_lock_irqsave)(rq); | 10384 | if (t->mm_cid != MM_CID_UNSET) { |
| 10837 | preempt_enable_no_resched(); /* holding spinlock */ | 10385 | cpumask_clear_cpu(t->mm_cid, mm_cidmask(mm)); |
| 10838 | WRITE_ONCE(t->mm_cid_active, 0); | 10386 | t->mm_cid = MM_CID_UNSET; |
| 10839 | /* | 10387 | } |
| 10840 | * Store t->mm_cid_active before loading per-mm/cpu cid. | | |
| 10841 | * Matches barrier in sched_mm_cid_remote_clear_old(). | | |
| 10842 | */ | | |
| 10843 | smp_mb(); | | |
| 10844 | mm_cid_put(mm); | | |
| 10845 | t->last_mm_cid = t->mm_cid = -1; | | |
| 10846 | } | 10388 | } |
| 10847 | | 10389 | |
| | 10390 | /* Deactivate MM CID allocation across execve() */ |
| 10848 | void sched_mm_cid_before_execve(struct task_struct *t) | 10391 | void sched_mm_cid_before_execve(struct task_struct *t) |
| 10849 | { | 10392 | { |
| 10850 | struct mm_struct *mm = t->mm; | 10393 | sched_mm_cid_exit_signals(t); |
| 10851 | struct rq *rq; | | |
| 10852 | | | |
| 10853 | if (!mm) | | |
| 10854 | return; | | |
| 10855 | | | |
| 10856 | preempt_disable(); | | |
| 10857 | rq = this_rq(); | | |
| 10858 | guard(rq_lock_irqsave)(rq); | | |
| 10859 | preempt_enable_no_resched(); /* holding spinlock */ | | |
| 10860 | WRITE_ONCE(t->mm_cid_active, 0); | | |
| 10861 | /* | | |
| 10862 | * Store t->mm_cid_active before loading per-mm/cpu cid. | | |
| 10863 | * Matches barrier in sched_mm_cid_remote_clear_old(). | | |
| 10864 | */ | | |
| 10865 | smp_mb(); | | |
| 10866 | mm_cid_put(mm); | | |
| 10867 | t->last_mm_cid = t->mm_cid = -1; | | |
| 10868 | } | 10394 | } |
| 10869 | | 10395 | |
| | 10396 | /* Reactivate MM CID after successful execve() */ |
| 10870 | void sched_mm_cid_after_execve(struct task_struct *t) | 10397 | void sched_mm_cid_after_execve(struct task_struct *t) |
| 10871 | { | 10398 | { |
| 10872 | struct mm_struct *mm = t->mm; | 10399 | struct mm_struct *mm = t->mm; |
| 10873 | struct rq *rq; | | |
| 10874 | | 10400 | |
| 10875 | if (!mm) | 10401 | if (!mm) |
| 10876 | return; | 10402 | return; |
| 10877 | | 10403 | |
| 10878 | preempt_disable(); | 10404 | guard(preempt)(); |
| 10879 | rq = this_rq(); | 10405 | t->mm_cid_active = 1; |
| 10880 | scoped_guard (rq_lock_irqsave, rq) { | 10406 | mm_cid_select(t); |
| 10881 | preempt_enable_no_resched(); /* holding spinlock */ | | |
| 10882 | WRITE_ONCE(t->mm_cid_active, 1); | | |
| 10883 | /* | | |
| 10884 | * Store t->mm_cid_active before loading per-mm/cpu cid. | | |
| 10885 | * Matches barrier in sched_mm_cid_remote_clear_old(). | | |
| 10886 | */ | | |
| 10887 | smp_mb(); | | |
| 10888 | t->last_mm_cid = t->mm_cid = mm_cid_get(rq, t, mm); | | |
| 10889 | } | | |
| 10890 | } | 10407 | } |
| 10891 | | 10408 | |
| 10892 | void sched_mm_cid_fork(struct task_struct *t) | 10409 | void sched_mm_cid_fork(struct task_struct *t) |
| 10893 | { | 10410 | { |
| 10894 | WARN_ON_ONCE(!t->mm || t->mm_cid != -1); | 10411 | WARN_ON_ONCE(!t->mm || t->mm_cid != MM_CID_UNSET); |
| 10895 | t->mm_cid_active = 1; | 10412 | t->mm_cid_active = 1; |
| 10896 | } | 10413 | } |
| 10897 | #endif /* CONFIG_SCHED_MM_CID */ | 10414 | #endif /* CONFIG_SCHED_MM_CID */ |