@@ -5307,7 +5307,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
53075307 }
53085308 }
53095309
5310- switch_mm_cid (prev , next );
5310+ mm_cid_switch_to (prev , next );
53115311
53125312 /*
53135313 * Tell rseq that the task was scheduled in. Must be after
@@ -10624,7 +10624,7 @@ static bool mm_cid_fixup_task_to_cpu(struct task_struct *t, struct mm_struct *mm
1062410624 return true;
1062510625}
1062610626
10627- static void __maybe_unused mm_cid_fixup_tasks_to_cpus (void )
10627+ static void mm_cid_fixup_tasks_to_cpus (void )
1062810628{
1062910629 struct mm_struct * mm = current -> mm ;
1063010630 struct task_struct * p , * t ;
@@ -10674,25 +10674,81 @@ static bool sched_mm_cid_add_user(struct task_struct *t, struct mm_struct *mm)
1067410674void sched_mm_cid_fork (struct task_struct * t )
1067510675{
1067610676 struct mm_struct * mm = t -> mm ;
10677+ bool percpu ;
1067710678
1067810679 WARN_ON_ONCE (!mm || t -> mm_cid .cid != MM_CID_UNSET );
1067910680
1068010681 guard (mutex )(& mm -> mm_cid .mutex );
10681- scoped_guard (raw_spinlock , & mm -> mm_cid .lock ) {
10682- sched_mm_cid_add_user (t , mm );
10683- /* Preset last_cid for mm_cid_select() */
10684- t -> mm_cid .last_cid = mm -> mm_cid .max_cids - 1 ;
10682+ scoped_guard (raw_spinlock_irq , & mm -> mm_cid .lock ) {
10683+ struct mm_cid_pcpu * pcp = this_cpu_ptr (mm -> mm_cid .pcpu );
10684+
10685+ /* First user ? */
10686+ if (!mm -> mm_cid .users ) {
10687+ sched_mm_cid_add_user (t , mm );
10688+ t -> mm_cid .cid = mm_get_cid (mm );
10689+ /* Required for execve() */
10690+ pcp -> cid = t -> mm_cid .cid ;
10691+ return ;
10692+ }
10693+
10694+ if (!sched_mm_cid_add_user (t , mm )) {
10695+ if (!mm -> mm_cid .percpu )
10696+ t -> mm_cid .cid = mm_get_cid (mm );
10697+ return ;
10698+ }
10699+
10700+ /* Handle the mode change and transfer current's CID */
10701+ percpu = !!mm -> mm_cid .percpu ;
10702+ if (!percpu )
10703+ mm_cid_transit_to_task (current , pcp );
10704+ else
10705+ mm_cid_transfer_to_cpu (current , pcp );
10706+ }
10707+
10708+ if (percpu ) {
10709+ mm_cid_fixup_tasks_to_cpus ();
10710+ } else {
10711+ mm_cid_fixup_cpus_to_tasks (mm );
10712+ t -> mm_cid .cid = mm_get_cid (mm );
1068510713 }
1068610714}
1068710715
1068810716static bool sched_mm_cid_remove_user (struct task_struct * t )
1068910717{
1069010718 t -> mm_cid .active = 0 ;
10691- mm_unset_cid_on_task (t );
10719+ scoped_guard (preempt ) {
10720+ /* Clear the transition bit */
10721+ t -> mm_cid .cid = cid_from_transit_cid (t -> mm_cid .cid );
10722+ mm_unset_cid_on_task (t );
10723+ }
1069210724 t -> mm -> mm_cid .users -- ;
1069310725 return mm_update_max_cids (t -> mm );
1069410726}
1069510727
10728+ static bool __sched_mm_cid_exit (struct task_struct * t )
10729+ {
10730+ struct mm_struct * mm = t -> mm ;
10731+
10732+ if (!sched_mm_cid_remove_user (t ))
10733+ return false;
10734+ /*
10735+ * Contrary to fork() this only deals with a switch back to per
10736+ * task mode either because the above decreased users or an
10737+ * affinity change increased the number of allowed CPUs and the
10738+ * deferred fixup did not run yet.
10739+ */
10740+ if (WARN_ON_ONCE (mm -> mm_cid .percpu ))
10741+ return false;
10742+ /*
10743+ * A failed fork(2) cleanup never gets here, so @current must have
10744+ * the same MM as @t. That's true for exit() and the failed
10745+ * pthread_create() cleanup case.
10746+ */
10747+ if (WARN_ON_ONCE (current -> mm != mm ))
10748+ return false;
10749+ return true;
10750+ }
10751+
1069610752/*
1069710753 * When a task exits, the MM CID held by the task is not longer required as
1069810754 * the task cannot return to user space.
@@ -10703,10 +10759,43 @@ void sched_mm_cid_exit(struct task_struct *t)
1070310759
1070410760 if (!mm || !t -> mm_cid .active )
1070510761 return ;
10762+ /*
10763+ * Ensure that only one instance is doing MM CID operations within
10764+ * a MM. The common case is uncontended. The rare fixup case adds
10765+ * some overhead.
10766+ */
10767+ scoped_guard (mutex , & mm -> mm_cid .mutex ) {
10768+ /* mm_cid::mutex is sufficient to protect mm_cid::users */
10769+ if (likely (mm -> mm_cid .users > 1 )) {
10770+ scoped_guard (raw_spinlock_irq , & mm -> mm_cid .lock ) {
10771+ if (!__sched_mm_cid_exit (t ))
10772+ return ;
10773+ /* Mode change required. Transfer currents CID */
10774+ mm_cid_transit_to_task (current , this_cpu_ptr (mm -> mm_cid .pcpu ));
10775+ }
10776+ mm_cid_fixup_cpus_to_tasks (mm );
10777+ return ;
10778+ }
10779+ /* Last user */
10780+ scoped_guard (raw_spinlock_irq , & mm -> mm_cid .lock ) {
10781+ /* Required across execve() */
10782+ if (t == current )
10783+ mm_cid_transit_to_task (t , this_cpu_ptr (mm -> mm_cid .pcpu ));
10784+ /* Ignore mode change. There is nothing to do. */
10785+ sched_mm_cid_remove_user (t );
10786+ }
10787+ }
1070610788
10707- guard (mutex )(& mm -> mm_cid .mutex );
10708- scoped_guard (raw_spinlock , & mm -> mm_cid .lock )
10709- sched_mm_cid_remove_user (t );
10789+ /*
10790+ * As this is the last user (execve(), process exit or failed
10791+ * fork(2)) there is no concurrency anymore.
10792+ *
10793+ * Synchronize eventually pending work to ensure that there are no
10794+ * dangling references left. @t->mm_cid.users is zero so nothing
10795+ * can queue this work anymore.
10796+ */
10797+ irq_work_sync (& mm -> mm_cid .irq_work );
10798+ cancel_work_sync (& mm -> mm_cid .work );
1071010799}
1071110800
1071210801/* Deactivate MM CID allocation across execve() */
@@ -10719,18 +10808,12 @@ void sched_mm_cid_before_execve(struct task_struct *t)
1071910808void sched_mm_cid_after_execve (struct task_struct * t )
1072010809{
1072110810 sched_mm_cid_fork (t );
10722- guard (preempt )();
10723- mm_cid_select (t );
1072410811}
1072510812
1072610813static void mm_cid_work_fn (struct work_struct * work )
1072710814{
1072810815 struct mm_struct * mm = container_of (work , struct mm_struct , mm_cid .work );
1072910816
10730- /* Make it compile, but not functional yet */
10731- if (!IS_ENABLED (CONFIG_NEW_MM_CID ))
10732- return ;
10733-
1073410817 guard (mutex )(& mm -> mm_cid .mutex );
1073510818 /* Did the last user task exit already? */
1073610819 if (!mm -> mm_cid .users )
0 commit comments