[커널 18차] 88주차
2023.01.28 22:13
__schdule() 끝
git log : https://github.com/iamroot18/5.10/commit/f49eb8f211658cf0dc26cc9b0bb04c2d4370a09f
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 57069bb47a93..9de76064b117 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -949,6 +949,11 @@ static inline bool system_uses_hw_pan(void)
cpus_have_const_cap(ARM64_HAS_PAN);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * @return true : sw pan을 써야되는 경우
+ * - PAN을 써야되는데 hw pan이 지원 여부 확인.
+ */
static inline bool system_uses_ttbr0_pan(void)
{
return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 36a6b2863a2e..c29e1be0c5be 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -26,6 +26,13 @@
extern bool rodata_full;
+/*
+ * IAMROOT, 2023.01.28:
+ * - pid 저장용도.
+ * - CONTEXTIDR_EL1, Context ID Register (EL1)
+ * AArch64 상태에서 CONTEXTIDR_EL1은 ASID와 독립적이며 EL1&0 변환 체제의
+ * 경우 TTBR0_EL1 또는 TTBR1_EL1이 ASID를 보유합니다.
+ */
static inline void contextidr_thread_switch(struct task_struct *next)
{
if (!IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR))
@@ -278,12 +285,22 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
update_saved_ttbr0(tsk, &init_mm);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - next가 kernel : 교체안한다. ttbr0를 rserved로 set.
+ * next가 user : @next로 mm교체.
+ */
static inline void __switch_mm(struct mm_struct *next)
{
/*
* init_mm.pgd does not contain any user mappings and it is always
* active for kernel addresses in TTBR1. Just set the reserved TTBR0.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - next가 kernel이면 kernel의 user접근을 막기위해
+ * ttbr0를 비운다.
+ */
if (next == &init_mm) {
cpu_set_reserved_ttbr0();
return;
@@ -292,6 +309,10 @@ static inline void __switch_mm(struct mm_struct *next)
check_and_switch_context(next);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - @next로 mm교체
+ */
static inline void
switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
@@ -305,6 +326,13 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
* ASID has changed since the last run (following the context switch
* of another thread of the same process).
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 이전 값이 아직 초기화되지 않았거나(activate_mm 호출자) 마지막 실행
+ * 이후 ASID가 변경되었을 수 있으므로 예약된 작업의 저장된 TTBR0_EL1을
+ * 업데이트합니다(동일한 프로세스의 다른 스레드의 컨텍스트 전환 후).
+ */
update_saved_ttbr0(tsk, next);
}
diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h
index efb098de3a84..52879d7e23ef 100644
--- a/arch/arm64/include/asm/pointer_auth.h
+++ b/arch/arm64/include/asm/pointer_auth.h
@@ -125,6 +125,10 @@ static __always_inline void ptrauth_enable(void)
PR_PAC_ENABLED_KEYS_MASK); \
} while (0)
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ */
#define ptrauth_thread_switch_user(tsk) \
ptrauth_keys_install_user(&(tsk)->thread.keys_user)
diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h
index 4529230e5f3a..30964b7f7b78 100644
--- a/arch/arm64/include/asm/preempt.h
+++ b/arch/arm64/include/asm/preempt.h
@@ -47,6 +47,10 @@ static inline void set_preempt_need_resched(void)
current_thread_info()->preempt.need_resched = 0;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - need_resched clear(1로 set).
+ */
static inline void clear_preempt_need_resched(void)
{
current_thread_info()->preempt.need_resched = 1;
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index a9319d11a998..076f7c035f71 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -1447,6 +1447,17 @@ SYM_DATA_END(__entry_tramp_data_start)
* Previous and next are guaranteed not to be the same.
*
*/
+
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - x0 : prev, x1 : next (__switch_to() 참고)
+ * - 일부 레지스터만 prev에 backup / next에 restore.
+ * thread.cpu_context에 backup한다.
+ * - sp_el0에 x1(next)가 등록된다.
+ * ret을 통해 x0가(prev) return 된다.
+ */
+
SYM_FUNC_START(cpu_switch_to)
mov x10, #THREAD_CPU_CONTEXT
add x8, x0, x10
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index c0b00522be2d..5a38a1f88680 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1035,6 +1035,11 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
current);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * - fpsimd 관련 처리
+ */
void fpsimd_thread_switch(struct task_struct *next)
{
bool wrong_task, wrong_cpu;
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 712e97c03e54..b2bec25dfc90 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -906,6 +906,11 @@ NOKPROBE_SYMBOL(reinstall_suspended_bps);
/*
* Context-switcher for restoring suspended breakpoints.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * hw debug
+ */
void hw_breakpoint_thread_switch(struct task_struct *next)
{
/*
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index e5e801bc5312..f06bd14c5703 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -192,6 +192,11 @@ void mte_thread_init_user(void)
set_mte_ctrl(current, 0);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * - MTE
+ */
void mte_thread_switch(struct task_struct *next)
{
if (!system_supports_mte())
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1129c5a80a96..d2291d4c267e 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -394,6 +394,12 @@ void tls_preserve_current_state(void)
*task_user_tls(current) = read_sysreg(tpidr_el0);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * - tls(thread local storage)
+ */
static void tls_thread_switch(struct task_struct *next)
{
tls_preserve_current_state();
@@ -410,6 +416,11 @@ static void tls_thread_switch(struct task_struct *next)
* Force SSBS state on context-switch, since it may be lost after migrating
* from a CPU which treats the bit as RES0 in a heterogeneous system.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * - SSBS처리
+ */
static void ssbs_thread_switch(struct task_struct *next)
{
/*
@@ -447,6 +458,10 @@ static void ssbs_thread_switch(struct task_struct *next)
*/
DEFINE_PER_CPU(struct task_struct *, __entry_task);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 동작할 task(next)를 __entry_task에 기록한다.
+ */
static void entry_task_switch(struct task_struct *next)
{
__this_cpu_write(__entry_task, next);
@@ -459,6 +474,10 @@ static void entry_task_switch(struct task_struct *next)
* - disable access when switching from a 64bit task to a 32bit task
* - enable access when switching from a 32bit task to a 64bit task
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ */
static void erratum_1418040_thread_switch(struct task_struct *prev,
struct task_struct *next)
{
@@ -490,6 +509,16 @@ static void erratum_1418040_thread_switch(struct task_struct *prev,
* sctlr_user must be made in the same preemption disabled block so that
* __switch_to() does not see the variable update before the SCTLR_EL1 one.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * __switch_to()는 current->thread.sctlr_user를 최적화로 확인합니다. 따라서
+ * 이 함수는 선점을 비활성화한 상태에서 호출해야 하며 sctlr_user에 대한
+ * 업데이트는 동일한 선점 비활성화 블록에서 수행해야 __switch_to()가
+ * SCTLR_EL1 이전에 변수 업데이트를 볼 수 없습니다.
+ *
+ * - sctlr_el1을 수정하면 isb를 무조건해줘야한다.
+ */
void update_sctlr_el1(u64 sctlr)
{
/*
@@ -505,6 +534,13 @@ void update_sctlr_el1(u64 sctlr)
/*
* Thread switching.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - 1. __entry_task에 next기록한다.
+ * 2. dsb(ish)수행한다.
+ * 3. sctlr_el1이 변경됬으면 갱신한다.
+ * 4. cpu_switch_to 실행.
+ */
__notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *next)
{
@@ -525,6 +561,14 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
* This full barrier is also required by the membarrier system
* call.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 스레드가 다른 CPU로 마이그레이션되는 경우 이 CPU에서 보류 중인 TLB 또는
+ * 캐시 유지 관리를 완료하십시오.
+ * 이 전체 장벽은 membarrier 시스템 호출에도 필요합니다.
+ * - tlb cache등을 flush 한 경우에 완료될때까지 기다린다.
+ */
dsb(ish);
/*
@@ -534,6 +578,10 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
*/
mte_thread_switch(next);
/* avoid expensive SCTLR_EL1 accesses if no change */
+/*
+ * IAMROOT, 2023.01.28:
+ * - sctlr_user가 다르다면 sctlr_el1을 변경되는 sctlr_user로 바꾼다.
+ */
if (prev->thread.sctlr_user != next->thread.sctlr_user)
update_sctlr_el1(next->thread.sctlr_user);
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index dce56dac76f9..e3047bae4c80 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -17,9 +17,21 @@
#include <asm/smp.h>
#include <asm/tlbflush.h>
+/*
+ * IAMROOT, 2023.01.28:
+ * - 8bit or 16bit
+ * 8bit일 경우 256
+ * 16bit일 경우 65536
+ */
static u32 asid_bits;
static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 8bit일 경우
+ * 0 ~ 0x100, 0x200, 0x300..
+ * - base asid
+ */
static atomic64_t asid_generation;
static unsigned long *asid_map;
@@ -32,6 +44,11 @@ static unsigned long nr_pinned_asids;
static unsigned long *pinned_asid_map;
#define ASID_MASK (~GENMASK(asid_bits - 1, 0))
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - asid 단위.
+ */
#define ASID_FIRST_VERSION (1UL << asid_bits)
#define NUM_USER_ASIDS ASID_FIRST_VERSION
@@ -76,6 +93,12 @@ void verify_cpu_asid_bits(void)
}
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - KPTI asid bits set.
+ * 0xaa로 @map을 채운다.
+ */
static void set_kpti_asid_bits(unsigned long *map)
{
unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
@@ -85,9 +108,22 @@ static void set_kpti_asid_bits(unsigned long *map)
* is set, then the ASID will map only userspace. Thus
* mark even as reserved for kernel.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * KPTI 커널/사용자 ASID가 쌍으로 할당된 경우 하단 비트는 두 가지를 구분합니다.
+ * 설정되어 있으면 ASID는 사용자 공간만 매핑합니다. 따라서 커널용으로 예약된
+ * 것으로 표시합니다.
+ */
memset(map, 0xaa, len);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - pinned_asid_map이 있다면 pinned_asid_map를 asid_map에 복사한다.
+ * kpti를 사용하는경우 asid_map을 0xaa로 채운다.
+ * 그것도 아니라면 asid_map을 0로 clear한다.
+ */
static void set_reserved_asid_bits(void)
{
if (pinned_asid_map)
@@ -98,9 +134,23 @@ static void set_reserved_asid_bits(void)
bitmap_clear(asid_map, 0, NUM_USER_ASIDS);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - 세대(generation)이 바뀌었는지 확인ㄴ한다.
+ * - 앞자리가 바뀐지를 확인하는 개념.
+ * - ex) asid 0x503, asid_generation = 0x400, bit = 8bit
+ * 결과 false.
+ */
#define asid_gen_match(asid) \
(!(((asid) ^ atomic64_read(&asid_generation)) >> asid_bits))
+/*
+ * IAMROOT, 2023.01.28:
+ * - 1. asid_map clear
+ * 2. reserved_asids에 마지막에 사용했던 active_asids를 기록.
+ * 3. 마지막 사용했던 asid를 asid_map에 기록.
+ * 4. 모든 cpu에 tlb flush pending 등록.
+ */
static void flush_context(void)
{
int i;
@@ -109,6 +159,10 @@ static void flush_context(void)
/* Update the list of reserved ASIDs and the ASID bitmap. */
set_reserved_asid_bits();
+/*
+ * IAMROOT, 2023.01.28:
+ * - pcpu active_asids를 0으로 clear하면서 이전값을 asid로 가져온다.
+ */
for_each_possible_cpu(i) {
asid = atomic64_xchg_relaxed(&per_cpu(active_asids, i), 0);
/*
@@ -118,6 +172,15 @@ static void flush_context(void)
* ASID, as this is the only trace we have of
* the process it is still running.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 이 CPU가 이미 롤오버를 겪었지만 그 동안 다른 작업을 실행하지
+ * 않은 경우 예약된 ASID를 보존해야 합니다. 이것이 여전히 실행
+ * 중인 프로세스에 대한 유일한 추적이기 때문입니다.
+ * - 롤오버가 된 경우 reserved_asids를 asid로 가져온다.
+ * - 맨 마지막의 asid를 reserved_asids로 등록한다.
+ */
if (asid == 0)
asid = per_cpu(reserved_asids, i);
__set_bit(asid2idx(asid), asid_map);
@@ -128,9 +191,21 @@ static void flush_context(void)
* Queue a TLB invalidation for each CPU to perform on next
* context-switch
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - next context switch에 tlb flush가 되도록 모든 cpu에 설정한다.
+ * 해당 cpu들은 context switch일때 local tlb flush를 할것이다.
+ */
cpumask_setall(&tlb_flush_pending);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - pcpu reserved_asids에 @asid가 있다면 hit로 하고, newasid를
+ * reserved_asids로 등록한다.
+ * 버려지게 될 asid가 이미 reserved로 등록되있다면 바뀌게될
+ * newasid로 전환해줘야하기때문이다.
+ */
static bool check_update_reserved_asid(u64 asid, u64 newasid)
{
int cpu;
@@ -145,6 +220,16 @@ static bool check_update_reserved_asid(u64 asid, u64 newasid)
* so could result in us missing the reserved ASID in a future
* generation.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 일치를 찾는 예약된 ASID 세트를 반복합니다.
+ * 하나를 찾으면 newasid(즉, 현재 세대의 동일한 ASID)를 사용하도록
+ * mm을 업데이트할 수 있지만 루프를 조기에 종료할 수는 없습니다.
+ * mm. 그렇게 하지 않으면 미래 세대에서 예약된 ASID가 누락될 수
+ * 있습니다.
+.
+ */
for_each_possible_cpu(cpu) {
if (per_cpu(reserved_asids, cpu) == asid) {
hit = true;
@@ -155,19 +240,49 @@ static bool check_update_reserved_asid(u64 asid, u64 newasid)
return hit;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - asid를 generation을 붙여 newasid를 만든다.
+ * 1. newasid가 reserved_asid에 있으면 reserved_asids를 사용한다.
+ * 2. 요청한 asid가 asid_map에서 비어있는경우 해당자리를 사용한다.
+ * 3. 요청한 자리가 asid_map에서 이미 사용중인경우 cur_idx부터
+ * 빈자리를 찾아서 새로 asid를 구해온다.
+ * 4. asid_map이 full인경우 generation을 증가시키고
+ * 모든 cpu에 대해 flush tlb pending후 asid_map을 새로 설정하여 다시
+ * asid를 가져온다.
+ */
static u64 new_context(struct mm_struct *mm)
{
static u32 cur_idx = 1;
u64 asid = atomic64_read(&mm->context.id);
u64 generation = atomic64_read(&asid_generation);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 최초가 아니면
+ */
if (asid != 0) {
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - 세대(앞자리) + mask값.
+ * ex) generation = 0x300, asid = 0x150인경우
+ * newasid = 0x350
+ */
u64 newasid = generation | (asid & ~ASID_MASK);
/*
* If our current ASID was active during a rollover, we
* can continue to use it and this was just a false alarm.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 롤오버 중에 현재 ASID가 활성화된 경우 계속 사용할 수 있으며
+ * 이는 잘못된 경보일 뿐입니다.
+ * - reserved_asids에 asid가 있는지 확인한다. asid가 있었다면
+ * newasid로 바뀌고 return한다.
+ */
if (check_update_reserved_asid(asid, newasid))
return newasid;
@@ -176,6 +291,13 @@ static u64 new_context(struct mm_struct *mm)
* takes priority, because even if it is also pinned, we need to
* update the generation into the reserved_asids.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 고정되어 있으면 계속 사용할 수 있습니다. reserved도 고정된 경우에도
+ * reserved_asids로 세대를 업데이트해야 하기 때문에 reserved가 우선
+ * 순위입니다.
+ */
if (refcount_read(&mm->context.pinned))
return newasid;
@@ -183,8 +305,21 @@ static u64 new_context(struct mm_struct *mm)
* We had a valid ASID in a previous life, so try to re-use
* it if possible.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 전생에 유효한 ASID가 있었으므로 가능하면 다시 사용하십시오.
+ * - asid_map에 asid에 이미 set되있었는지 검사하면서 set한다.
+ * 사용중이 아니라면 return newasid.
+ */
if (!__test_and_set_bit(asid2idx(asid), asid_map))
return newasid;
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - 이 부분까지왔다면 fork등의 이유로 누군가가 asid_map의 asid자리를
+ * 차지한 상태가된다.
+ */
}
/*
@@ -194,15 +329,34 @@ static u64 new_context(struct mm_struct *mm)
* a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd
* pairs.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 무료 ASID를 할당합니다. 찾을 수 없는 경우 현재 활성 ASID를 기록하고
+ * TLB를 플러시가 필요한 것으로 표시합니다. init_mm에 대해 예약된 TTBR0을
+ * 설정할 때 ASID #0을 사용하고 짝수/홀수 쌍으로 ASID를 할당하므로
+ * 항상 ASID #2(색인 1)부터 계산합니다.
+ *
+ * - asid_map의 첫 zero를 찾는다. 찾아졌다면 return.
+ */
asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
if (asid != NUM_USER_ASIDS)
goto set_asid;
+/*
+ * IAMROOT, 2023.01.28:
+ * - asid_map이 가득 찻다면 asid_generation을 update하고, asid_map을 새로
+ * 설정한다.
+ */
/* We're out of ASIDs, so increment the global generation count */
generation = atomic64_add_return_relaxed(ASID_FIRST_VERSION,
&asid_generation);
flush_context();
+/*
+ * IAMROOT, 2023.01.28:
+ * - 새로설정된 asid_map에서 asid를 얻어온다.
+ */
/* We have more ASIDs than CPUs, so this will always succeed */
asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
@@ -212,6 +366,18 @@ static u64 new_context(struct mm_struct *mm)
return idx2asid(asid) | generation;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - 상황에따라 fastpath / slowpath로 동작한다.
+ * 1. fastpath 조건.
+ * - active_asids가 0이 아니다
+ * - 세대가 같다.
+ * - active_asids update가 성공.
+ * 2. fastpath 실패시 slowpath로 동작한다.
+ * 실패 조건에따라 asid를 새로 얻어올수 있다.
+ * 3. tlb flush pending조건이 있으면 수행한다.
+ * 4. mm을 교체한다.
+ */
void check_and_switch_context(struct mm_struct *mm)
{
unsigned long flags;
@@ -221,6 +387,11 @@ void check_and_switch_context(struct mm_struct *mm)
if (system_supports_cnp())
cpu_set_reserved_ttbr0();
+/*
+ * IAMROOT, 2023.01.28:
+ * - asid + 가상주소로 물리주소를 매핑하는 식으로 사용한다.
+ * pid를 특수한 방식으로 가공하여 asid를 만듣나.
+ */
asid = atomic64_read(&mm->context.id);
/*
@@ -237,24 +408,72 @@ void check_and_switch_context(struct mm_struct *mm)
* relaxed xchg in flush_context will treat us as reserved
* because atomic RmWs are totally ordered for a given location.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 여기서 메모리 순서는 미묘합니다.
+ * active_asids가 0이 아니고 ASID가 현재 세대와 일치하는 경우 완화된
+ * cmpxchg로 active_asids 항목을 업데이트합니다. 동시 롤오버가 있는
+ * 레이싱은 다음 중 하나를 의미합니다.
+ *
+ * - 우리는 cmpxchg에서 0을 되찾고 잠금을 기다리게 됩니다. 잠금을
+ * 해제하면 롤오버와 동기화되므로 업데이트된 세대를 확인해야 합니다.
+ *
+ * - 우리는 cmpxchg에서 유효한 ASID를 다시 얻습니다. 이는 원자 RmW가
+ * 주어진 위치에 대해 완전히 주문되기 때문에 flush_context의 완화된
+ * xchg가 우리를 예약된 것으로 취급함을 의미합니다.
+ *
+ * - fastpath mm 구간
+ */
old_active_asid = atomic64_read(this_cpu_ptr(&active_asids));
+/*
+ * IAMROOT, 2023.01.28:
+ * - 세대가 같고, active_asids를 asid로 바꾸는데 성공했으면
+ * fastpath 성공
+ */
if (old_active_asid && asid_gen_match(asid) &&
atomic64_cmpxchg_relaxed(this_cpu_ptr(&active_asids),
old_active_asid, asid))
goto switch_mm_fastpath;
+/*
+ * IAMROOT, 2023.01.28:
+ * - slowpath
+ * old_active_asid 0이던가, 세대가 바뀌었던가, asid를 넣는게
+ * 실패했을때 진입.
+ */
raw_spin_lock_irqsave(&cpu_asid_lock, flags);
/* Check that our ASID belongs to the current generation. */
asid = atomic64_read(&mm->context.id);
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - 세대비교가 실패하면 asid를 새로 생성한다.
+ */
if (!asid_gen_match(asid)) {
asid = new_context(mm);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 새로만든 asid를 mm에 set해준다.
+ */
atomic64_set(&mm->context.id, asid);
}
cpu = smp_processor_id();
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - tlb flush pending요청이 있으면 flush한다.
+ * - new_context()에서 현재 tlb flush pending요청을 했을경우
+ * 자기신의 경우엔 여기서 즉시 될것이다.
+ */
if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
local_flush_tlb_all();
+/*
+ * IAMROOT, 2023.01.28:
+ * - 바뀐 asid로 active_asids를 update한다.
+ */
atomic64_set(this_cpu_ptr(&active_asids), asid);
raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
@@ -266,6 +485,11 @@ void check_and_switch_context(struct mm_struct *mm)
* Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
* emulating PAN.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - hw가 지원하면 여기서 cpu_switch_mm을 한다.
+ * sw로 pan을 하는 경우엔 나중에(uaccess_enable()) 한다.
+ */
if (!system_uses_ttbr0_pan())
cpu_switch_mm(mm->pgd, mm);
}
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index 626a7b38aaaf..7e47e3eaf10a 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -140,6 +140,11 @@ do { \
#define smp_mb__after_atomic() __smp_mb__after_atomic()
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - cpu간 memory 동기화가 필요할때, 단방향 barrier로 사용한다.
+ * barrier중에서 가장빠른 barrier.
+ */
#ifndef smp_store_release
#define smp_store_release(p, v) __smp_store_release(p, v)
#endif
diff --git a/include/asm-generic/switch_to.h b/include/asm-generic/switch_to.h
index 5897d100a6e6..9c9c89a6089e 100644
--- a/include/asm-generic/switch_to.h
+++ b/include/asm-generic/switch_to.h
@@ -18,6 +18,10 @@
extern struct task_struct *__switch_to(struct task_struct *,
struct task_struct *);
+/*
+ * IAMROOT, 2023.01.28:
+ * - next로 switch. arm64의 경우 last엔 prev가 위치한다.
+ */
#define switch_to(prev, next, last) \
do { \
((last) = __switch_to((prev), (next))); \
diff --git a/include/linux/kcov.h b/include/linux/kcov.h
index 55dc338f6bcd..4ce51fbb904e 100644
--- a/include/linux/kcov.h
+++ b/include/linux/kcov.h
@@ -28,11 +28,20 @@ enum kcov_mode {
void kcov_task_init(struct task_struct *t);
void kcov_task_exit(struct task_struct *t);
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - debug.
+ */
#define kcov_prepare_switch(t) \
do { \
(t)->kcov_mode |= KCOV_IN_CTXSW; \
} while (0)
+/*
+ * IAMROOT, 2023.01.28:
+ * - debug.
+ */
#define kcov_finish_switch(t) \
do { \
(t)->kcov_mode &= ~KCOV_IN_CTXSW; \
diff --git a/include/linux/mmu_context.h b/include/linux/mmu_context.h
index b9b970f7ab45..edea22f2552f 100644
--- a/include/linux/mmu_context.h
+++ b/include/linux/mmu_context.h
@@ -6,6 +6,10 @@
#include <asm/mmu.h>
/* Architectures that care about IRQ state in switch_mm can override this. */
+/*
+ * IAMROOT, 2023.01.28:
+ * - @next로 mm교체.
+ */
#ifndef switch_mm_irqs_off
# define switch_mm_irqs_off switch_mm
#endif
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 9b60bb89d86a..fd8aa57bf4b3 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1201,6 +1201,11 @@ static inline void perf_event_task_migrate(struct task_struct *task)
task->sched_migrated = 1;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * perf
+ */
static inline void perf_event_task_sched_in(struct task_struct *prev,
struct task_struct *task)
{
@@ -1214,6 +1219,10 @@ static inline void perf_event_task_sched_in(struct task_struct *prev,
}
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - perf
+ */
static inline void perf_event_task_sched_out(struct task_struct *prev,
struct task_struct *next)
{
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 25be07d054d9..fcfc1c7c1abb 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -365,10 +365,21 @@ extern struct root_domain def_root_domain;
extern struct mutex sched_domains_mutex;
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - sched_info_arrive(), sched_info_depart() 참고
+ */
struct sched_info {
#ifdef CONFIG_SCHED_INFO
/* Cumulative counters: */
+/*
+ * IAMROOT, 2023.01.28:
+ * - pcount : cpu에 올라간 횟수.
+ * run_delay : 대기queue에서 기다렸던 시간총합.
+ * last_arrival : cpu에 마지막에 올라간 시각
+ * last_queued : cpu에서 마지막에 제거된 시각.
+ */
/* # of times we have run on this CPU: */
unsigned long pcount;
@@ -2327,6 +2338,11 @@ static inline void set_tsk_need_resched(struct task_struct *tsk)
set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - TIF_NEED_RESCHED clear.
+ */
static inline void clear_tsk_need_resched(struct task_struct *tsk)
{
clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
@@ -2551,6 +2567,12 @@ static inline void rseq_signal_deliver(struct ksignal *ksig,
}
/* rseq_preempt() requires preemption to be disabled. */
+/*
+ * IAMROOT, 2023.01.28:
+ * - PASS
+ * - Gitblame 참고 (restartable sequences system call)
+ * rseq systemcall을 위한것
+ */
static inline void rseq_preempt(struct task_struct *t)
{
__set_bit(RSEQ_EVENT_PREEMPT_BIT, &t->rseq_event_mask);
diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h
index 87cdc0af88cb..869eb27415e3 100644
--- a/include/linux/sched/mm.h
+++ b/include/linux/sched/mm.h
@@ -374,6 +374,10 @@ enum {
#include <asm/membarrier.h>
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - membarrier 처리.
+ */
static inline void membarrier_mm_sync_core_before_usermode(struct mm_struct *mm)
{
if (current->mm != mm)
@@ -381,6 +385,11 @@ static inline void membarrier_mm_sync_core_before_usermode(struct mm_struct *mm)
if (likely(!(atomic_read(&mm->membarrier_state) &
MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE)))
return;
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - arm64는 없어보인다.
+ */
sync_core_before_usermode();
}
diff --git a/include/linux/tick.h b/include/linux/tick.h
index bfd571f18cfd..3b20d1554c38 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -299,6 +299,10 @@ static inline void __tick_nohz_task_switch(void) { }
static inline void tick_nohz_full_setup(cpumask_var_t cpumask) { }
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - nohz full을 해제한다.
+ */
static inline void tick_nohz_task_switch(void)
{
if (tick_nohz_full_enabled())
diff --git a/include/linux/vtime.h b/include/linux/vtime.h
index 3684487d01e1..e90a6ae3f54d 100644
--- a/include/linux/vtime.h
+++ b/include/linux/vtime.h
@@ -89,6 +89,10 @@ static inline bool vtime_accounting_enabled_this_cpu(void)
extern void vtime_task_switch_generic(struct task_struct *prev);
+/*
+ * IAMROOT, 2023.01.28:
+ * - vtime accounting
+ */
static inline void vtime_task_switch(struct task_struct *prev)
{
if (vtime_accounting_enabled_this_cpu())
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index b9dcc5012c34..a1f91d4d2cdf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2422,6 +2422,10 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
const struct cpumask *new_mask,
u32 flags);
+/*
+ * IAMROOT, 2023.01.28:
+ * - @p를 SCA_MIGRATE_DISABLE 한다. RT를 위해서 잠깐 migrate disable을 한다는 의미인거같다.
+ */
static void migrate_disable_switch(struct rq *rq, struct task_struct *p)
{
if (likely(!p->migration_disabled))
@@ -4871,6 +4875,10 @@ __fire_sched_out_preempt_notifiers(struct task_struct *curr,
notifier->ops->sched_out(notifier, next);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - cpu에서 switch 될때마다 notify해달라는 요청에 대한 처리.
+ */
static __always_inline void
fire_sched_out_preempt_notifiers(struct task_struct *curr,
struct task_struct *next)
@@ -4893,6 +4901,10 @@ fire_sched_out_preempt_notifiers(struct task_struct *curr,
#endif /* CONFIG_PREEMPT_NOTIFIERS */
+/*
+ * IAMROOT, 2023.01.28:
+ * - on_cpu set.
+ */
static inline void prepare_task(struct task_struct *next)
{
#ifdef CONFIG_SMP
@@ -4902,10 +4914,24 @@ static inline void prepare_task(struct task_struct *next)
*
* See the ttwu() WF_ON_CPU case and its ordering comment.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 작업을 실행 중이라고 주장합니다. 실행 중인 모든 작업이 이 설정을
+ * 갖도록 전환하기 전에 이 작업을 수행합니다.
+ *
+ * ttwu() WF_ON_CPU 사례 및 주문 설명을 참조하십시오.
+ */
WRITE_ONCE(next->on_cpu, 1);
#endif
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - on_cpu clear
+ * 단방향 barrier를 사용하는게 보인다.
+ */
static inline void finish_task(struct task_struct *prev)
{
#ifdef CONFIG_SMP
@@ -4920,6 +4946,18 @@ static inline void finish_task(struct task_struct *prev)
*
* Pairs with the smp_cond_load_acquire() in try_to_wake_up().
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 이것은 이 CPU에서 @prev에 대한 마지막 참조여야 합니다. p->on_cpu가
+ * 지워지면 작업을 다른 CPU로 옮길 수 있습니다. 전환이 완전히 완료될
+ * 때까지 이런 일이 발생하지 않도록 해야 합니다.
+ *
+ * 특히 finish_task_switch()에서 prev->state의 로드는 이보다 먼저
+ * 일어나야 합니다.
+ *
+ * try_to_wake_up()에서 smp_cond_load_acquire()와 쌍을 이룹니다.
+ */
smp_store_release(&prev->on_cpu, 0);
#endif
}
@@ -4961,6 +4999,10 @@ static inline struct callback_head *splice_balance_callbacks(struct rq *rq)
return head;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - TODO
+ */
static void __balance_callbacks(struct rq *rq)
{
do_balance_callbacks(rq, splice_balance_callbacks(rq));
@@ -4994,6 +5036,10 @@ static inline void balance_callbacks(struct rq *rq, struct callback_head *head)
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - switch 직전 lock관련 처리. finish_lock_switch()와 한쌍이다.
+ */
static inline void
prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf)
{
@@ -5003,6 +5049,13 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf
* of the scheduler it's an obvious special-case), so we
* do an early lockdep release here:
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * runqueue 잠금은 다음 작업에 의해 해제되기 때문에(유효하지
+ * 않은 잠금 작업이지만 스케줄러의 경우에는 명백한 특수 사례임)
+ * 여기에서 초기 lockdep 해제를 수행합니다.
+ */
rq_unpin_lock(rq, rf);
spin_release(&__rq_lockp(rq)->dep_map, _THIS_IP_);
#ifdef CONFIG_DEBUG_SPINLOCK
@@ -5011,6 +5064,10 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf
#endif
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - prepare_lock_switch()와 한쌍이다.
+ */
static inline void finish_lock_switch(struct rq *rq)
{
/*
@@ -5035,6 +5092,12 @@ static inline void finish_lock_switch(struct rq *rq)
# define finish_arch_post_lock_switch() do { } while (0)
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - KMAP
+ * 32bit에서 사용한다.
+ * highmam을 mapping하기 위한 방식.
+ */
static inline void kmap_local_sched_out(void)
{
#ifdef CONFIG_KMAP_LOCAL
@@ -5043,6 +5106,12 @@ static inline void kmap_local_sched_out(void)
#endif
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - KMAP
+ * 32bit에서 사용한다.
+ * highmam을 mapping하기 위한 방식.
+ */
static inline void kmap_local_sched_in(void)
{
#ifdef CONFIG_KMAP_LOCAL
@@ -5064,6 +5133,23 @@ static inline void kmap_local_sched_in(void)
* prepare_task_switch sets up locking and calls architecture specific
* hooks.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * prepare_task_switch - 작업 전환 준비
+ * @rq: 전환을 준비하는 런큐
+ * @prev: 전환 중인 현재 작업
+ * @next: 전환할 작업.
+ * 이것은 rq 잠금이 유지되고 인터럽트가 꺼진 상태에서 호출됩니다.
+ * 컨텍스트 전환 후 후속 finish_task_switch와 쌍을 이루어야 합니다.
+ * prepare_task_switch는 잠금을 설정하고 아키텍처별 후크를 호출합니다.
+ *
+ * - 1. sched_info update.
+ * 2. kcov, perf등 debug 처리.
+ * 3. fire sched out등 notify 처리
+ * 4. rseq systemcall을 위한 처리.
+ * 5. on_cpu set.
+ */
static inline void
prepare_task_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next)
@@ -5071,6 +5157,11 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
kcov_prepare_switch(prev);
sched_info_switch(rq, prev, next);
perf_event_task_sched_out(prev, next);
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - Gitblame 참고 (restartable sequences system call)
+ */
rseq_preempt(prev);
fire_sched_out_preempt_notifiers(prev, next);
kmap_local_sched_out();
@@ -5097,6 +5188,27 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
* past. prev == current is still correct but we need to recalculate this_rq
* because prev may have moved to another CPU.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * finish_task_switch - 작업 전환 후 정리
+ * @prev: 방금 전환한 스레드입니다.
+ *
+ * finish_task_switch는 컨텍스트 전환 이후에 호출되어야 하며, 컨텍스트 전환
+ * 전에는 prepare_task_switch 호출과 쌍을 이루어야 합니다.
+ * finish_task_switch는 prepare_task_switch에 의해 설정된 잠금을 조정하고
+ * 다른 아키텍처별 정리 작업을 수행합니다.
+ *
+ * context_switch()에서 mm 삭제를 지연했을 수 있습니다. 그렇다면 실행 대기열
+ * 잠금 외부에서 여기에서 완료합니다. (잠금이 유지된 상태에서 작업을
+ * 수행하면 교착 상태가 발생할 수 있습니다. 자세한 내용은 schedule()을
+ * 참조하십시오.) 컨텍스트 스위치는 이전에 이 작업이 schedule()을 호출할 때
+ * 저장된 로컬 변수를 복원했습니다. prev == current는 여전히 정확하지만
+ * prev가 다른 CPU로 이동했을 수 있으므로 this_rq를 다시 계산해야 합니다.
+ *
+ * - prev task에 대한 context 정리를 한다. prev task가 TASK_DEAD라면
+ * 자료구조까지 정리해준다.
+ */
static struct rq *finish_task_switch(struct task_struct *prev)
__releases(rq->lock)
{
@@ -5133,10 +5245,28 @@ static struct rq *finish_task_switch(struct task_struct *prev)
* running on another CPU and we could rave with its RUNNING -> DEAD
* transition, resulting in a double drop.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * task 구조체에는 현재로 사용할 참조가 하나 있습니다.
+ * task가 종료되면 tsk->state에서 TASK_DEAD를 설정하고 마지막으로
+ * schedule을 호출합니다. 일정 호출은 반환되지 않으며 예약된 작업은
+ * 해당 참조를 삭제해야 합니다.
+ *
+ * 우리는 prev->on_cpu를 지우기 전에(finish_task에서) prev->state를
+ * 관찰해야 합니다. 그렇지 않으면 동시 웨이크업이 다른 CPU에서 prev
+ * 실행될 수 있고 우리는 RUNNING -> DEAD 전환으로 격찬하여 더블
+ * 드롭을 초래할 수 있습니다.
+ */
prev_state = READ_ONCE(prev->__state);
vtime_task_switch(prev);
perf_event_task_sched_in(prev, current);
finish_task(prev);
+/*
+ * IAMROOT, 2023.01.28:
+ * - task가 switch가 됬다는게 nohz full이 아니라는 상태이므로 nohz
+ * full이면 해제한다.
+ */
tick_nohz_task_switch();
finish_lock_switch(rq);
finish_arch_post_lock_switch();
@@ -5163,10 +5293,20 @@ static struct rq *finish_task_switch(struct task_struct *prev)
* provided by mmdrop(),
* - a sync_core for SYNC_CORE.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev mm이 존재하면 mm에대한 ref drop.
+ */
if (mm) {
membarrier_mm_sync_core_before_usermode(mm);
mmdrop(mm);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev task가 완전히 죽으면서 context switch를 한상태다.
+ * task_dead를 호출하여 prev를 current가 정리해주는 개념이다.
+ */
if (unlikely(prev_state == TASK_DEAD)) {
if (prev->sched_class->task_dead)
prev->sched_class->task_dead(prev);
@@ -5178,6 +5318,10 @@ static struct rq *finish_task_switch(struct task_struct *prev)
kprobe_flush_task(prev);
/* Task is done with its stack. */
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev stack제거
+ */
put_task_stack(prev);
put_task_struct_rcu_user(prev);
@@ -5214,6 +5358,12 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev)
/*
* context_switch - switch to the new MM and the new thread's register state.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - 1. mm switch
+ * 같은 가상주소를 사용하고있으면 할필요없지만 아닌경우 해야된다.
+ * 2. process context switch
+ */
static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next, struct rq_flags *rf)
@@ -5234,15 +5384,45 @@ context_switch(struct rq *rq, struct task_struct *prev,
* kernel -> user switch + mmdrop() active
* user -> user switch
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - mm
+ * 유저 process인 경우 자신의 mm
+ * 유저 thread인 경우 해당 부모 프로세스의 mm
+ * kernel thread : NULL
+ * - active_mm
+ * 유저 process인 경우 자신의 mm
+ * 유저 thread인 경우 해당 부모 프로세스의 mm
+ * kernel thread : 이전 유전 프로세스의 mm을 전달받아 사용한다.
+ *
+ * - mm == NULL : kernel
+ * mm != NULL : user
+ */
if (!next->mm) { // to kernel
enter_lazy_tlb(prev->active_mm, next);
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev -> next로 update. active_mm는 항상 user task mm이 들어가 있다.
+ * 인계하는 개념.
+ */
next->active_mm = prev->active_mm;
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev가 user였으면 active_mm ref count를 증가시키고,
+ * prev가 kernel이였으면 prev의 active_mm이
+ * next로 active_mm으로 넘어갔으므로 prev active_mm을 지운다.
+ */
if (prev->mm) // from user
mmgrab(prev->active_mm);
else
prev->active_mm = NULL;
} else { // to user
+/*
+ * IAMROOT, 2023.01.28:
+ * - user공간에서는 mm간의 간섭을 막기위해 membarrier 처리를한다.
+ */
membarrier_switch_mm(rq, prev->active_mm, next->mm);
/*
* sys_membarrier() requires an smp_mb() between setting
@@ -5252,8 +5432,24 @@ context_switch(struct rq *rq, struct task_struct *prev,
* case 'prev->active_mm == next->mm' through
* finish_task_switch()'s mmdrop().
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * sys_membarrier()는 rq->curr / membarrier_switch_mm() 설정과 사용자
+ * 공간으로 돌아가는 사이에 smp_mb()가 필요합니다.
+ *
+ * 아래는 switch_mm()을 통해 또는 'prev->active_mm == next->mm'인 경우
+ * finish_task_switch()의 mmdrop()을 통해 이를 제공합니다.
+ *
+ * - @next로 mm을 교체한다.
+ */
switch_mm_irqs_off(prev->active_mm, next->mm, next);
+/*
+ * IAMROOT, 2023.01.28:
+ * - kernel 인경우 prev->active_mm을 rq->prev_mm으로 옮긴다.
+ * prev->active_mm은 초기화한다.
+ */
if (!prev->mm) { // from kernel
/* will mmdrop() in finish_task_switch(). */
rq->prev_mm = prev->active_mm;
@@ -5881,6 +6077,11 @@ static inline void schedule_debug(struct task_struct *prev, bool preempt)
schedstat_inc(this_rq()->sched_count);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - TODO
+ */
static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
struct rq_flags *rf)
{
@@ -5908,7 +6109,8 @@ static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
*/
/*
* IAMROOT, 2023.01.27:
- * - ING
+ * - @prev가 cfs이고 @rq 소속이 전부 cfs라면 pick_next_task_fair로 next task를 선택한다.
+ * 그게 아니면 sched class 우선순위로 next task를 선택한다.
*/
static inline struct task_struct *
__pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
@@ -5950,6 +6152,11 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
if (unlikely(p == RETRY_TASK))
goto restart;
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - next가 없는 즉 할게없는 상황. idle task를 선택한다.
+ */
/* Assume the next prioritized class is idle_sched_class */
if (!p) {
put_prev_task(rq, prev);
@@ -5960,14 +6167,29 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
}
restart:
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - load balancing
+ */
put_prev_task_balance(rq, prev, rf);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 우선순위별로 rt task 선택.
+ */
for_each_class(class) {
p = class->pick_next_task(rq);
if (p)
return p;
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - dl, rt, cfs_rq, idle 등의 순으로 선택을해봤는데도 없는 경우는 존재하지 않는다 최소한
+ * idle이 선택되기때문이다.
+ */
/* The idle class should always have a runnable task: */
BUG();
}
@@ -6487,7 +6709,7 @@ static inline void sched_core_cpu_dying(unsigned int cpu) {}
/*
* IAMROOT, 2023.01.27:
- * - ING
+ * - next task를 선택한다.
*/
static struct task_struct *
pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
@@ -6600,7 +6822,11 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
* - 인터럽트 핸들러에서 사용자 공간으로 복귀
*
* 경고: 선점을 비활성화한 상태로 호출해야 합니다!.
- * - TODO
+ * - 1. local irq disable
+ * 2. 자발적 / 비자발적유무에 따른 deactivate_task 처리
+ * 3. next task를 선택 및 설정한다.
+ * 4. mm switch 수행.
+ * 5. context switch 수행.
*/
static void __sched notrace __schedule(unsigned int sched_mode)
{
@@ -6765,6 +6991,10 @@ static void __sched notrace __schedule(unsigned int sched_mode)
rq->last_seen_need_resched_ns = 0;
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - @prev가 변경됬다는것이므로 switch가 이뤄졌다.
+ */
if (likely(prev != next)) {
rq->nr_switches++;
/*
@@ -6786,6 +7016,18 @@ static void __sched notrace __schedule(unsigned int sched_mode)
* - switch_to() for arm64 (weakly-ordered, spin_unlock
* is a RELEASE barrier),
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * membarrier 시스템 호출은 각 아키텍처가 rq->curr를 업데이트한 후 사용자
+ * 공간으로 돌아가기 전에 전체 메모리 장벽을 갖도록 요구합니다.
+ * 다음은 다양한 아키텍처에 대한 장벽을 제공하는 체계입니다.
+ *
+ * - mm ? switch_mm() : x86, s390, sparc, PowerPC용 mmdrop().
+ * switch_mm()은 PowerPC의 membarrier_arch_switch_mm()에 의존합니다.
+ * - spin_unlock이 전체 장벽인 weak order의 아키텍처에 대한 finish_lock_switch(),
+ * - arm64에 대한 switch_to()(약한 순서, spin_unlock은 RELEASE 장벽임).
+ */
++*switch_count;
migrate_disable_switch(rq, prev);
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 013fc579ec54..d5c1549f97fd 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -761,6 +761,10 @@ void vtime_account_idle(struct task_struct *tsk)
account_idle_time(get_vtime_delta(&tsk->vtime));
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - vtime(virtual time) accounting
+ */
void vtime_task_switch_generic(struct task_struct *prev)
{
struct vtime *vtime = &prev->vtime;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 10c2fdca813a..f97323486f3a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -89,6 +89,16 @@ unsigned int sysctl_sched_child_runs_first __read_mostly;
*
* (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * SCHED_OTHER 깨우기 세분성입니다.
+ *
+ * 이 옵션은 분리된 워크로드의 선점 효과를 지연시키고 과도한 스케줄링을 줄입니다.
+ * 동기식 워크로드에는 여전히 즉각적인 깨우기/절전 대기 시간이 있습니다.
+ *
+ * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ */
unsigned int sysctl_sched_wakeup_granularity = 1000000UL;
static unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL;
@@ -537,6 +547,10 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
leaf_cfs_rq_list)
/* Do the two (enqueued) entities belong to the same group ? */
+/*
+ * IAMROOT, 2023.01.28:
+ * - 같은 cfs_rq 소속인지 확인한다.
+ */
static inline struct cfs_rq *
is_same_group(struct sched_entity *se, struct sched_entity *pse)
{
@@ -679,6 +693,10 @@ static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
return min_vruntime;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - a가 b보다 vruntime이 작다면 return true;
+ */
static inline bool entity_before(struct sched_entity *a,
struct sched_entity *b)
{
@@ -787,11 +805,19 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b)
/*
* Enqueue an entity into the rb-tree:
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - cfs_rq에 넣는다.
+ */
static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
rb_add_cached(&se->run_node, &cfs_rq->tasks_timeline, __entity_less);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - cfs_rq에서 제거한다.
+ */
static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
rb_erase_cached(&se->run_node, &cfs_rq->tasks_timeline);
@@ -1158,6 +1184,10 @@ static void update_curr_fair(struct rq *rq)
update_curr(cfs_rq_of(&rq->curr->se));
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - schedule stat 처리
+ */
static inline void
update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@@ -1176,6 +1206,11 @@ update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
__schedstat_set(se->statistics.wait_start, wait_start);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - stats 처리.
+ */
static inline void
update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@@ -5218,6 +5253,10 @@ static inline int task_fits_capacity(struct task_struct *p, long capacity)
return fits_capacity(uclamp_task_util(p), capacity);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - TODO
+ */
static inline void update_misfit_status(struct task_struct *p, struct rq *rq)
{
if (!static_branch_unlikely(&sched_asym_cpucapacity))
@@ -5281,6 +5320,10 @@ static inline void update_misfit_status(struct task_struct *p, struct rq *rq) {}
#endif /* CONFIG_SMP */
+/*
+ * IAMROOT, 2023.01.28:
+ * - debug.
+ */
static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
#ifdef CONFIG_SCHED_DEBUG
@@ -5622,9 +5665,22 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
resched_curr(rq_of(cfs_rq));
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - 1. @se에 대한 buddy정보를 다 지운다.
+ * 2. on_rq일시 cfs_rq에서 @se를 dequeue한다.
+ * 3. load avg재계산.
+ * 4. @se를 curr로 선택한다.
+ * 5. stats 및 debug처리.
+ * 6. prev_sum_exec_runtime update.
+ */
static void
set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
+/*
+ * IAMROOT, 2023.01.28:
+ * - @se에 대한 정보를 다 지운다.
+ */
clear_buddies(cfs_rq, se);
/* 'current' is not kept within the tree. */
@@ -5647,6 +5703,12 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
* least twice that of our own weight (i.e. dont track it
* when there are only lesser-weight tasks around):
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * CPU 부하가 자체 무게의 두 배 이상인 경우 최대 슬라이스 길이를 추적합니다(즉, 주변에 더
+ * 가벼운 작업만 있는 경우 추적하지 않음).
+ */
if (schedstat_enabled() &&
rq_of(cfs_rq)->cfs.load.weight >= 2*se->load.weight) {
schedstat_set(se->statistics.slice_max,
@@ -5667,6 +5729,21 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
* 3) pick the "last" process, for cache locality
* 4) do not run the "skip" process, if something else is available
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 이러한 사항을 염두에 두고 다음 순서로 다음 프로세스를 선택합니다.
+ *
+ * 1) 프로세스/작업 그룹 간에 일을 공정하게 유지
+ * 2) 누군가가 실제로 실행하기를 원하기 때문에 다음 프로세스를 선택하십시오.
+ * 3) 캐시 지역성을 위해 마지막 프로세스를 선택합니다.
+ * 4) 다른 것을 사용할 수 있는 경우 건너뛰기 프로세스를 실행하지 마십시오.
+ *
+ * - @curr의 next를 고른다.
+ * 1. curr의 left인것을 찾는다.
+ * 2. next -> last -> skip고려 순으로 se를 선택한다.
+ * 3. 3개가 전부 없으면 left가 선택될것이다.
+ */
static struct sched_entity *
pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
@@ -5677,6 +5754,14 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
* If curr is set we have to see if its left of the leftmost entity
* still in the tree, provided there was anything in the tree at all.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * curr이 설정되어 있으면 트리에 아무 것도 없는 경우 가장 왼쪽 엔터티의 왼쪽이 여전히
+ * 트리에 있는지 확인해야 합니다.
+ *
+ * - curr가 left보다 왼쪽인지 확인한다. 더 왼쪽이면 left = curr.
+ */
if (!left || (curr && entity_before(curr, left)))
left = curr;
@@ -5686,26 +5771,58 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
* Avoid running the skip buddy, if running something else can
* be done without getting too unfair.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 너무 불공평하지 않고 다른 것을 실행할 수 있다면 스킵 버디를 실행하지 마십시오.
+ * - skip 지정이 되있고, se가 skip에 해당된다면 차선책을 찾는다.
+ * curr보다 이전인것을 고르려고 노력한다.
+ */
if (cfs_rq->skip && cfs_rq->skip == se) {
struct sched_entity *second;
+/*
+ * IAMROOT, 2023.01.28:
+ * - se(skip)이 curr면은 가장작은것을 찾아 second로 고른다.
+ * se이 curr가 아니면, se의 next를 고른다.
+ */
if (se == curr) {
second = __pick_first_entity(cfs_rq);
} else {
second = __pick_next_entity(se);
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - next를 골라봤는데도 불구하고, next가 없거나, curr가 next의 이전이라면
+ * curr를 second를 사용한다.
+ */
if (!second || (curr && entity_before(curr, second)))
second = curr;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - second가 wakeup_gran보다 너무 앞서있는 경우만 아니면 se를 second로 선택한다.
+ * 최대한 이전을 골라봤는데도 앞서있을수있는데, wakeup_gran만큼은 허용한다는뜻이다.
+ */
if (second && wakeup_preempt_entity(second, left) < 1)
se = second;
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - next를 가장 높은 우선순위로 고려한다.
+ * - next가 left 보다 너무 앞서있는경우가 아니면 se를 next로 선택한다.
+ */
if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) {
/*
* Someone really wants this to run. If it's not unfair, run it.
*/
se = cfs_rq->next;
+/*
+ * IAMROOT, 2023.01.28:
+ * - last도 next처럼 고려한다.
+ */
} else if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1) {
/*
* Prefer last buddy, try to return the CPU to a preempted task.
@@ -5718,12 +5835,25 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq);
+/*
+ * IAMROOT, 2023.01.28:
+ * - 1. @prev가 cfs_rq에 있으면 update_curr()
+ * 2. cfs_bandwidth처리
+ * 3. debug및 통계처리
+ * 4. cfs_rq에 enqueue.
+ * 5. load avg 재계산.
+ * 6. curr를 NULL로 update.
+ */
static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
{
/*
* If still on the runqueue then deactivate_task()
* was not called and update_curr() has to be done:
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - rq에 들어가있엇으면 시간갱신을 해준다.
+ */
if (prev->on_rq)
update_curr(cfs_rq);
@@ -6677,6 +6807,10 @@ static void sync_throttle(struct task_group *tg, int cpu)
}
/* conditionally throttle active cfs_rq's from put_prev_entity() */
+/*
+ * IAMROOT, 2023.01.28:
+ * - cfs_bandwidth 미지원이면 return false.
+ */
static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
{
if (!cfs_bandwidth_used())
@@ -6992,6 +7126,11 @@ static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
*/
#ifdef CONFIG_SCHED_HRTICK
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev에서 slice만큼 동작했는지 확인한다. slice만큼 동작했고 p가 current라면 resched요청을
+ * 하고 그게 아니면 delta후에 hrtick이 동작하도록 조정한다.
+ */
static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{
struct sched_entity *se = &p->se;
@@ -8536,6 +8675,10 @@ balance_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
}
#endif /* CONFIG_SMP */
+/*
+ * IAMROOT, 2023.01.28:
+ * - @se의 weight를 적용한 gran값을 구한다.
+ */
static unsigned long wakeup_gran(struct sched_entity *se)
{
unsigned long gran = sysctl_sched_wakeup_granularity;
@@ -8553,6 +8696,17 @@ static unsigned long wakeup_gran(struct sched_entity *se)
* This is especially important for buddies when the leftmost
* task is higher priority than the buddy.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 이제 curr가 실행되기 때문에 gran을 실시간에서 가상 시간으로 단위로 변환하십시오.
+ *
+ * 'curr' 대신 'se'를 사용하여 가벼운 작업에 페널티를 주어 더 쉽게 선점할 수 있습니다.
+ * 즉, 'se' < 'curr'이면 결과 gran이 더 커지므로 더 가벼운 작업에 페널티를 주고,
+ * otoh 'se' > 'curr'이면 결과 gran이 더 작아지므로 더 가벼운 작업에 페널티를 줍니다.
+ *
+ * 이것은 가장 왼쪽 작업이 버디보다 우선순위가 높을 때 버디에게 특히 중요합니다.
+ */
return calc_delta_fair(gran, se);
}
@@ -8570,6 +8724,22 @@ static unsigned long wakeup_gran(struct sched_entity *se)
* w(c, s3) = 1
*
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - @return -1 : curr의 vruntime이 se vruntime 보다 작다
+ * 1 : @se gran값보다 diff가 크면, 즉 충분한 시간차가 있으면
+ * 0 : @se gran값보다 diff가 작으면, 즉 gran 이내의 시간이면(너무 짧은시간)
+ *
+ * ------------
+ *
+ * - curr | se : -1
+ *
+ * - gran
+ * se | curr | : 0
+ *
+ * - gran
+ * se | | curr : 1
+ */
static int
wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
{
@@ -8746,6 +8916,11 @@ static struct task_struct *pick_task_fair(struct rq *rq)
}
#endif
+/*
+ * IAMROOT, 2023.01.28:
+ * - cfs_rq의 curr의 next를 선택한다. 선택이 되면 @prev를 put, 선택된 next를 curr로 계층구조로
+ * 순환하며 설정한다. 선택된 next의 task를 return한다.
+ */
struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{
@@ -8769,7 +8944,18 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* Therefore attempt to avoid putting and setting the entire cgroup
* hierarchy, only change the part that actually changes.
*/
-
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * dequeue_task_fair()의 set_next_buddy() 때문에 다음 작업이 현재 작업과 동일한 cgroup에서
+ * 나올 가능성이 높습니다.
+ *
+ * 따라서 전체 cgroup 계층 구조를 넣거나 설정하는 것을 피하고 실제로 변경되는 부분만
+ * 변경하십시오.
+ *
+ * - 계층구조로 내려가면서 curr의 next를 순회한다. 최종적으로 마지막 next로 선택된것을
+ * se로 선택될것이고, 이것은 task가 된다.
+ */
do {
struct sched_entity *curr = cfs_rq->curr;
@@ -8779,7 +8965,19 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* entity, update_curr() will update its vruntime, otherwise
* forget we've ever seen it.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * put_prev_entity()를 수행하지 않고 여기에 왔기 때문에 cfs_rq->curr도 고려해야 합니다.
+ * 여전히 실행 가능한 엔터티인 경우 update_curr()는 vruntime을 업데이트하고, 그렇지 않으면
+ * 우리가 본 적이 있다는 사실을 잊어버립니다.
+ */
if (curr) {
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - curr entity가 rq에 안들어가있으면 null로 설정.
+ */
if (curr->on_rq)
update_curr(cfs_rq);
else
@@ -8791,6 +8989,14 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* Therefore the nr_running test will indeed
* be correct.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * check_cfs_rq_runtime()에 대한 이 호출은 스로틀링을 수행하고 상위 항목의 대기열에서
+ * 제외합니다.
+ * 따라서 nr_running 테스트는 실제로 정확합니다.
+ * - throttle인지 확인한다.
+ */
if (unlikely(check_cfs_rq_runtime(cfs_rq))) {
cfs_rq = &rq->cfs;
@@ -8812,23 +9018,83 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* is a different task than we started out with, try and touch the
* least amount of cfs_rqs.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 아직 put_prev_entity를 수행하지 않았고 선택한 작업이 시작과 다른 작업인 경우 최소량의
+ * cfs_rq를 터치해 봅니다.
+ *
+ * - 선택한 p(se)가 @prev가 다르다면 prev se를 put하고, 새로운 p(se)를 set한다.
+ */
if (prev != p) {
struct sched_entity *pse = &prev->se;
+/*
+ * IAMROOT, 2023.01.28:
+ * - se, pse가 같은 cfs_rq소속일때까지 반복하며
+ * pse를 cfs_rq에 enqueue, se를 cfs_rq에서 dequeue를 하고, se를 curr로 update한다.
+ *
+ * O
+ * / \
+ * O <----same_group
+ * / \
+ * O se
+ * / \
+ * pse ..
+ */
while (!(cfs_rq = is_same_group(se, pse))) {
int se_depth = se->depth;
int pse_depth = pse->depth;
+ p
+/*
+ * IAMROOT, 2023.01.28:
+ * - pse가 se보다 더 깊거나 같은 위치. pse를 put해준다.
+ * - ex)
+ * O
+ * / \
+ * O <----same_group
+ * / \
+ * O se
+ * / \
+ * pse ..
+ */
if (se_depth <= pse_depth) {
+/*
+ * IAMROOT, 2023.01.28:
+ * - prev se를 cfs_rq로 enqueue.
+ */
put_prev_entity(cfs_rq_of(pse), pse);
pse = parent_entity(pse);
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - se가 pse보다 더 깊거나 같은 위치. curr를 update해준다.
+ * - ex)
+ * O
+ * / \
+ * O <----same_group
+ * / \
+ * O pse
+ * / \
+ * se ..
+ */
if (se_depth >= pse_depth) {
+/*
+ * prifri, 2023.01.28:
+ * - cfs_rq에 se를 dequeue하고 se를 curr로 설정한다.
+ */
set_next_entity(cfs_rq_of(se), se);
se = parent_entity(se);
}
}
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - 최종적으로 same_group에서 만낫을때. pse, se의 처리.
+ */
put_prev_entity(cfs_rq, pse);
set_next_entity(cfs_rq, se);
}
@@ -8836,10 +9102,19 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
goto done;
simple:
#endif
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - simple인 경우는 계층구조 처리가 필요없어 간단히 처리하고 넘어간다.
+ */
if (prev)
put_prev_task(rq, prev);
do {
+/*
+ * IAMROOT, 2023.01.28:
+ * - next를 pick하고 set한다.
+ */
se = pick_next_entity(cfs_rq, NULL);
set_next_entity(cfs_rq, se);
cfs_rq = group_cfs_rq(se);
@@ -8854,6 +9129,11 @@ done: __maybe_unused;
* the list, so our cfs_tasks list becomes MRU
* one.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 다음 실행 작업을 목록의 맨 앞으로 이동하여 cfs_tasks 목록이 MRU 목록이 되도록 합니다.
+ */
list_move(&p->se.group_node, &rq->cfs_tasks);
#endif
@@ -8862,6 +9142,10 @@ done: __maybe_unused;
update_misfit_status(p, rq);
+/*
+ * IAMROOT, 2023.01.28:
+ * - next의 task가 return된다.
+ */
return p;
idle:
@@ -12247,6 +12531,11 @@ static inline void nohz_newidle_balance(struct rq *this_rq) { }
* 0 - failed, no new tasks
* > 0 - success, new (fair) tasks present
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - TODO
+ * 다른 cpu에서 task를 가져온다.
+ */
static int newidle_balance(struct rq *this_rq, struct rq_flags *rf)
{
unsigned long next_balance = jiffies + HZ;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 2f3a9b38e115..a88d19125128 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -726,6 +726,13 @@ struct cfs_rq {
* 'curr' points to currently running entity on this cfs_rq.
* It is set to NULL otherwise (i.e when none are currently running).
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - set 함수 정리.
+ * next : set_next_buddy(check_preempt_wakeup(), yield_to_task_fair(), dequeue_task_fair())
+ * last : set_last_buddy(check_preempt_wakeup())
+ * skip : set_skip_buddy(yield_to_task_fair())
+ */
struct sched_entity *curr;
struct sched_entity *next;
struct sched_entity *last;
@@ -1304,6 +1311,10 @@ struct rq {
int cpu;
int online;
+/*
+ * IAMROOT, 2023.01.28:
+ * - 현재 rq에서 runable하고있는 task들.
+ */
struct list_head cfs_tasks;
struct sched_avg avg_rt;
@@ -1790,6 +1801,10 @@ static inline void assert_clock_updated(struct rq *rq)
SCHED_WARN_ON(rq->clock_update_flags < RQCF_ACT_SKIP);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - return clock
+ */
static inline u64 rq_clock(struct rq *rq)
{
lockdep_assert_rq_held(rq);
@@ -2906,6 +2921,10 @@ static inline int hrtick_enabled(struct rq *rq)
return hrtimer_is_hres_active(&rq->hrtick_timer);
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - sched HRTICK 지원 확인.
+ */
static inline int hrtick_enabled_fair(struct rq *rq)
{
if (!sched_feat(HRTICK))
@@ -3501,15 +3520,33 @@ static inline bool sched_energy_enabled(void) { return false; }
* - store to rq->membarrier_state and following user-space memory accesses.
* In the same way it provides those guarantees around store to rq->curr.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * - 스케줄러는 다음 사이에 membarrier에 필요한 메모리 배리어를 제공합니다.
+ * - 이전 사용자 공간 메모리 액세스 및 rq->membarrier_state 저장,
+ * - rq->membarrier_state에 저장하고 사용자 공간 메모리 액세스를 따릅니다.
+ * 같은 방식으로 저장소 주변에서 rq->curr에 대한 보증을 제공합니다.
+ *
+ * - user공간에서는 mm간의 간섭을 막기위해 membarrier 처리를한다.
+ */
static inline void membarrier_switch_mm(struct rq *rq,
struct mm_struct *prev_mm,
struct mm_struct *next_mm)
{
int membarrier_state;
+/*
+ * IAMROOT, 2023.01.28:
+ * - mm이 안바꼇으면 switch할필요없다.
+ */
if (prev_mm == next_mm)
return;
+/*
+ * IAMROOT, 2023.01.28:
+ * - rq의 membarrier_state를 next로 갱신한다.
+ */
membarrier_state = atomic_read(&next_mm->membarrier_state);
if (READ_ONCE(rq->membarrier_state) == membarrier_state)
return;
diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h
index fe22cb00d8f0..c160d4137b54 100644
--- a/kernel/sched/stats.h
+++ b/kernel/sched/stats.h
@@ -5,6 +5,10 @@
/*
* Expects runqueue lock to be held for atomicity of update
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - sched stats처리.
+ */
static inline void
rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
{
@@ -17,6 +21,10 @@ rq_sched_info_arrive(struct rq *rq, unsigned long long delta)
/*
* Expects runqueue lock to be held for atomicity of update
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - sched stats처리.
+ */
static inline void
rq_sched_info_depart(struct rq *rq, unsigned long long delta)
{
@@ -130,6 +138,10 @@ static inline void psi_ttwu_dequeue(struct task_struct *p)
}
}
+/*
+ * IAMROOT, 2023.01.28:
+ * - psi 처리
+ */
static inline void psi_sched_switch(struct task_struct *prev,
struct task_struct *next,
bool sleep)
@@ -184,14 +196,31 @@ static inline void sched_info_dequeue(struct rq *rq, struct task_struct *t)
* long it was waiting to run. We also note when it began so that we
* can keep stats on how long its timeslice is.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 작업이 마침내 CPU에 도달하면 호출됩니다. 이제 실행 대기 시간을
+ * 계산할 수 있습니다. 또한 타임슬라이스의 길이에 대한 통계를 유지할
+ * 수 있도록 언제 시작되었는지 기록합니다.
+ * - 대기큐에 있다가 cpu로 올라가는상황. sched_info 정보를 기록한다.
+ */
static void sched_info_arrive(struct rq *rq, struct task_struct *t)
{
unsigned long long now, delta = 0;
+/*
+ * IAMROOT, 2023.01.28:
+ * - 대기큐에 돌아갈때 set되엇을것이다.
+ */
if (!t->sched_info.last_queued)
return;
now = rq_clock(rq);
+
+/*
+ * IAMROOT, 2023.01.28:
+ * - 기다렸던 시간.
+ */
delta = now - t->sched_info.last_queued;
t->sched_info.last_queued = 0;
t->sched_info.run_delay += delta;
@@ -206,6 +235,14 @@ static void sched_info_arrive(struct rq *rq, struct task_struct *t)
* the timestamp if it is already not set. It's assumed that
* sched_info_dequeue() will clear that stamp when appropriate.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 작업이 마침내 CPU에 도달하면 호출됩니다. 이제 실행 대기 시간을 계산할
+ * 수 있습니다. 또한 타임슬라이스의 길이에 대한 통계를 유지할 수 있도록
+ * 언제 시작되었는지 기록합니다.
+ * - rq의 queueing했을대의 시각을 last_queued에 등록한다.
+ */
static inline void sched_info_enqueue(struct rq *rq, struct task_struct *t)
{
if (!t->sched_info.last_queued)
@@ -220,8 +257,22 @@ static inline void sched_info_enqueue(struct rq *rq, struct task_struct *t)
* sched_info_enqueue() to mark that it has now again started waiting on
* the runqueue.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 일반적으로 시간 조각 만료로 인해 프로세스가 비자발적으로 활성 실행
+ * 프로세스가 되는 것을 중단할 때 호출됩니다(유휴 작업으로 전환할 때도 호출될
+ * 수 있음). 이제 우리는 얼마나 오래 달렸는지 계산할 수 있습니다.
+ * 또한 프로세스가 여전히 TASK_RUNNING 상태인 경우 sched_info_enqueue()를
+ * 호출하여 이제 다시 실행 대기열에서 대기하기 시작했음을 표시합니다.
+ * - @t sched_info의 last_queued를 rq clock으로 update.
+ */
static inline void sched_info_depart(struct rq *rq, struct task_struct *t)
{
+/*
+ * IAMROOT, 2023.01.28:
+ * - delat는 대기큐에 있는동안의 시간이 될것이다.
+ */
unsigned long long delta = rq_clock(rq) - t->sched_info.last_arrival;
rq_sched_info_depart(rq, delta);
@@ -235,6 +286,14 @@ static inline void sched_info_depart(struct rq *rq, struct task_struct *t)
* their time slice. (This may also be called when switching to or from
* the idle task.) We are only called when prev != next.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * 작업이 일반적으로 타임 슬라이스 만료로 인해 비자발적으로 전환될 때
+ * 호출됩니다. (유휴 작업으로 전환하거나 전환할 때 호출될 수도 있습니다.)
+ * prev != next일 때만 호출됩니다.
+ * - prev, next 각각의 cpu에서의 제거, 등록에 따른 sched_info를 기록한다.
+ */
static inline void
sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
{
@@ -243,6 +302,13 @@ sched_info_switch(struct rq *rq, struct task_struct *prev, struct task_struct *n
* stats about how efficient we were at scheduling the idle
* process, however.
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - papago
+ * prev는 이제 CPU를 떠납니다. 그러나 유휴 프로세스를 예약하는 데 얼마나
+ * 효율적이었는지에 대한 통계를 기록하는 것은 흥미롭지 않습니다.
+ * - prev, next가 idle task가 아니라면 해당 동작들을 한다.
+ */
if (prev != rq->idle)
sched_info_depart(rq, prev);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index ed53d11a8dc5..234af0505042 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -577,6 +577,12 @@ void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bi
* It might need the tick due to per task/process properties:
* perf events, posix CPU timers, ...
*/
+/*
+ * IAMROOT, 2023.01.28:
+ * - nohz full은 보통 task가 한개일때의 얘기가 된다.
+ * tick이 멈춰있는 상태이다.
+ * - nohz full을 해제한다.
+ */
void __tick_nohz_task_switch(void)
{
struct tick_sched *ts;
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 629 |
188 | [커널 19차] 43, 44 주차 | 이태백 | 2023.03.26 | 184 |
187 | [커널 18차] 95주차 | kkr | 2023.03.20 | 123 |
186 | [커널 19차] 41 주차 | 이태백 | 2023.03.04 | 101 |
185 | [커널 18차] 93주차 | kkr | 2023.03.04 | 54 |
184 | [커널 18차] 91주차 | kkr | 2023.02.18 | 98 |
183 | [커널 19차] 39 주차 | Min | 2023.02.18 | 53 |
182 | [커널 18차] 90주차 | kkr | 2023.02.13 | 63 |
181 | [커널 19차] 38 주차 | Min | 2023.02.11 | 45 |
180 | [커널 19차] 37 주차 | Min | 2023.02.04 | 479 |
179 | [커널 19차] 36 주차 | Min | 2023.01.28 | 85 |
» | [커널 18차] 88주차 | kkr | 2023.01.28 | 55 |
177 | [커널 19차] 35 주차 | Min | 2023.01.14 | 93 |
176 | [커널 17차] 120 ~ 121주차 | ㅇㅇㅇ | 2023.01.08 | 111 |
175 | [커널 18차] 85주차 | kkr | 2023.01.07 | 53 |
174 | [커널 19차] 34 주차 | Min | 2023.01.07 | 42 |
173 | [커널 18차] 84주차 | kkr | 2022.12.31 | 104 |
172 | [커널 19차] 33 주차 | Min | 2022.12.31 | 51 |
171 | [커널 17차] 117 ~ 119주차 | ㅇㅇㅇ | 2022.12.25 | 63 |
170 | [커널 19차] 31 주차 | Min | 2022.12.17 | 63 |
169 | [커널 19차] 30 주차 | Min | 2022.12.10 | 61 |
.