[커널 18차] 109주차
2023.06.24 23:12
numa fault 진행중
git : https://github.com/iamroot18/5.10/commit/95e3f7b9dbb6cc641f098a38f10bbe63c627c047
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 35cd749a4eeb..73d6c8f8b005 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -273,6 +273,10 @@
#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */
#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */
#define PTE_GP (_AT(pteval_t, 1) << 50) /* BTI guarded */
+/*
+ * IAMROOT, 2023.06.24:
+ * - cpu가 관리한다.
+ */
#define PTE_DBM (_AT(pteval_t, 1) << 51) /* Dirty Bit Management */
#define PTE_CONT (_AT(pteval_t, 1) << 52) /* Contiguous range */
#define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 64544e167464..23ac7ffdea8f 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -13,6 +13,10 @@
/*
* Software defined PTE bits definition.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - PTE_DBM은 hw, PTE_DIRTY은 sw(원래부터 kernel이 관리하는 flag)
+ */
#define PTE_WRITE (PTE_DBM) /* same as DBM (51) */
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 899ed2b35ead..983efea73003 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -169,6 +169,18 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
(__boundary - 1 < (end) - 1) ? __boundary : (end); \
})
+/*
+ * IAMROOT, 2023.06.24:
+ * - dirty flag가 설정되었는지 여부를 알아온다. (write flag == dirty flag)
+ * - DBM (Dirty Bit Management)
+ * 예전에서는 kernel이 어떤 물리페이지에 접근했는지 cpu가 몰랐다.
+ * 하지만 현재는 cpu가 알게 하기위해 fault를 발생하기 위해 mapping을 끊고
+ * page access의 시도를 알게 한다.
+ * arm 8.2부터는 DBM이라는 개념을 넣어 access page에(tlb cache) dirty flag에
+ * hw가 기록한다. 이렇게 함으로써 mapping을 지우지 않아도 접근여부를
+ * 알수있게됬다.
+ * dirty상태면 메모리에 아직 기록이 안됬다는것을 알수있을것이다.
+ */
#define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
#define pte_sw_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY))
#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte))
@@ -254,12 +266,17 @@ static inline pte_t pte_mkclean(pte_t pte)
/*
* IAMROOT, 2022.06.04:
- * - @pte에 PTE_DIRTY bit를 set한다.
+ * - @pte에 PTE_DIRTY bit(sw dirty)를 set한다.
*/
static inline pte_t pte_mkdirty(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
+/*
+ * IAMROOT, 2023.06.24:
+ * - wr와 rdonly는 공존이 안된다. wr이 set되있으면
+ * rdonly는 그냥 한번 지워주는 개념인듯하다.
+ */
if (pte_write(pte))
pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
@@ -965,18 +982,39 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
#define pgd_clear_fixmap() clear_fixmap(FIX_PGD)
+/*
+ * IAMROOT, 2023.06.24:
+ * - 1. @pte가 hw dirty이면 sw dirty set한다.
+ * 2. @pte에서 mask를 제외한 부분 유지하고, @newprot에서 mask에 해당하는
+ * 것만 추가해서 return한다.
+ */
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
/*
* Normal and Normal-Tagged are two different memory types and indices
* in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * Normal 및 Normal-Tagged는 MAIR_EL1의 두 가지 메모리 유형 및
+ * 인덱스입니다. 아래 마스크는 PTE_ATTRINDX_MASK를 포함해야 합니다.
+ */
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
PTE_ATTRINDX_MASK;
/* preserve the hardware dirty information */
+/*
+ * IAMROOT, 2023.06.24:
+ * - hw dirty여부를 알아온다 hw dirty라면. sw dirty도 set한다.
+ */
if (pte_hw_dirty(pte))
pte = pte_mkdirty(pte);
+/*
+ * IAMROOT, 2023.06.24:
+ * - @pte에서 mask를 뺀것은 그대로 유지하고, @newprot의 mask에 있는것만
+ * 추가한다.
+ */
pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
return pte;
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2e77d1b9be74..bc6bf60bc2f0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -591,6 +591,10 @@ struct vm_fault {
* the 'address'
*/
union {
+/*
+ * IAMROOT, 2023.06.24:
+ * - fault 당시의 pte, pmd entry value
+ */
pte_t orig_pte; /* Value of PTE at the time of fault */
pmd_t orig_pmd; /* Value of PMD at the time of fault,
* used by PMD fault only.
@@ -1632,6 +1636,10 @@ static inline int page_to_nid(const struct page *page)
#endif
#ifdef CONFIG_NUMA_BALANCING
+/*
+ * IAMROOT, 2023.06.24:
+ * - cpuid 생성
+ */
static inline int cpu_pid_to_cpupid(int cpu, int pid)
{
return ((cpu & LAST__CPU_MASK) << LAST__PID_SHIFT) | (pid & LAST__PID_MASK);
@@ -1652,6 +1660,10 @@ static inline int cpupid_to_nid(int cpupid)
return cpu_to_node(cpupid_to_cpu(cpupid));
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @cpupid가 아직 unset인지 확인한다.
+ */
static inline bool cpupid_pid_unset(int cpupid)
{
return cpupid_to_pid(cpupid) == (-1 & LAST__PID_MASK);
@@ -1662,11 +1674,19 @@ static inline bool cpupid_cpu_unset(int cpupid)
return cpupid_to_cpu(cpupid) == (-1 & LAST__CPU_MASK);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @task_pid 와 cpupid에서 각각 pid를 추출해 비교한다.
+ */
static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid)
{
return (task_pid & LAST__PID_MASK) == cpupid_to_pid(cpupid);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @task_pid 와 cpupid에서 각각 pid를 추출해 비교한다.
+ */
#define cpupid_match_pid(task, cpupid) __cpupid_match_pid(task->pid, cpupid)
/*
* IAMROOT, 2021.12.11:
@@ -2165,6 +2185,13 @@ extern unsigned long move_page_tables(struct vm_area_struct *vma,
* for now all the callers are only use one of the flags at the same
* time.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * change_protection()에서 사용하는 플래그입니다. 지금은 매개변수처럼
+ * 여러 플래그를 전달할 수 있도록 비트맵으로 만듭니다. 그러나 지금은
+ * 모든 호출자가 동시에 플래그 중 하나만 사용합니다.
+ */
/* Whether we should allow dirty bit accounting */
#define MM_CP_DIRTY_ACCT (1UL << 0)
/* Whether this protection change is for NUMA hints */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index e57daee4042b..02c75c577581 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -340,6 +340,11 @@ struct page {
#endif /* WANT_PAGE_VIRTUAL */
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+/*
+ * IAMROOT, 2023.06.24:
+ * - page를 마지막으로 썻던 cpu + pid
+ * - 초기값 / reset = -1 & LAST_CPUPID_MASK
+ */
int _last_cpupid;
#endif
} _struct_page_alignment;
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 2df8f7577807..93cec82a9cab 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -149,6 +149,11 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address)
pte_index((address)))
#define pte_unmap(pte) kunmap_atomic((pte))
#else
+/*
+ * IAMROOT, 2023.06.24:
+ * - 64bit
+ * address에 해당하는 pte page table entry주소를 가져온다.
+ */
#define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
#define pte_unmap(pte) ((void)(pte)) /* NOP */
#endif
@@ -975,6 +980,10 @@ static inline pte_t __ptep_modify_prot_start(struct vm_area_struct *vma,
return ptep_get_and_clear(vma->vm_mm, addr, ptep);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - pte entry(@ptep)에 @pte값을 기록한다.
+ */
static inline void __ptep_modify_prot_commit(struct vm_area_struct *vma,
unsigned long addr,
pte_t *ptep, pte_t pte)
@@ -1034,6 +1043,13 @@ static inline pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
* Commit an update to a pte, leaving any hardware-controlled bits in
* the PTE unmodified.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * PTE에 대한 업데이트를 커밋하고 PTE의 모든 하드웨어 제어 비트를 수정하지
+ * 않은 상태로 둡니다.
+ * - pte entry(@ptep)에 @pte값을 기록한다.
+ */
static inline void ptep_modify_prot_commit(struct vm_area_struct *vma,
unsigned long addr,
pte_t *ptep, pte_t old_pte, pte_t pte)
@@ -1115,6 +1131,22 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
* case, this is required so that preemption is disabled, and in the SMP case,
* it must synchronize the delayed page table writes properly on other CPUs.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * lazy MMU 일괄 처리를 제공하는 기능입니다. 이렇게 하면 lazy MMU 모드를
+ * 종료하라는 호출이 발행될 때까지 PTE 업데이트 및 페이지 무효화를 지연할 수
+ * 있습니다. 일부 아키텍처는 이 작업을 통해 이점을 얻을 수 있으며 이 기간 동안
+ * 발생하는 PTE 업데이트를 일괄 처리할 수 있는 섀도우 및 dirty mode hypervisor
+ * 모두에 유용합니다. 이 인터페이스를 사용하려면 코드에서 읽기 위험을 제거해야
+ * 합니다. 읽기 위험은 페이지 테이블에 대한 실제 쓰기가 아직 발생하지 않았을 수
+ * 있으므로 수정된 후 원시 PTE 포인터를 통한 읽기가 최신 상태임을 보장하지 않기
+ * 때문에 dirty mode hypervisor 사례에서 발생할 수 있습니다. 이 모드는 수정될
+ * 수 있는 모든 페이지 테이블에 대한 페이지 테이블 잠금의 보호 하에서만 들어갈
+ * 수 있고 남을 수 있습니다. UP의 경우 선점을 비활성화하기 위해 필요하며,
+ * SMP의 경우 다른 CPU에서 지연된 페이지 테이블 쓰기를 적절하게 동기화해야 합니다.
+ * - sparc, x86, powerpc
+ */
#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
#define arch_enter_lazy_mmu_mode() do {} while (0)
#define arch_leave_lazy_mmu_mode() do {} while (0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 6deed9d32ea3..4f4b4b41d385 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1657,6 +1657,7 @@ struct task_struct {
* IAMROOT, 2023.06.17:
* - 계산된 task(thread)기준의 node scan 간격(msec)
* 실제 scan은 mm->numa_next_scan
+ * task_numa_work()에서 scan후, task 실행시간의 최대 3%로 제한한다.
*/
u64 node_stamp;
u64 last_task_numa_placement;
@@ -1691,6 +1692,19 @@ struct task_struct {
* during the current scan window. When the scan completes, the counts
* in faults_memory and faults_cpu decay and these values are copied.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * numa_faults는 4개의 영역으로 분할된 배열입니다.
+ * faults_memory, faults_cpu, faults_memory_buffer, faults_cpu_buffer 이 정확한 순서대로.
+ *
+ * faults_memory: 노드당 기준으로 결함의 기하급수적 감쇠 평균. 일정 배치
+ * 결정은 이러한 수를 기반으로 이루어집니다. 값은 PTE 스캔 기간 동안 정적
+ * 상태로 유지됩니다.
+ * faults_cpu: NUMA 힌트 오류가 발생했을 때 프로세스가 실행 중인 노드를 추적합니다.
+ * faults_memory_buffer 및 faults_cpu_buffer: 현재 스캔 기간 동안 노드당 오류를 기록합니다.
+ * 스캔이 완료되면 faults_memory 및 faults_cpu의 카운트가 감소하고 이러한 값이 복사됩니다.
+ */
unsigned long *numa_faults;
unsigned long total_numa_faults;
@@ -1700,6 +1714,15 @@ struct task_struct {
* period is adapted based on the locality of the faults with different
* weights depending on whether they were shared or private faults
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * numa_faults_locality는 마지막 스캔 기간 동안 기록된 결함이
+ * 원격/로컬인지 또는 마이그레이션에 실패했는지 추적합니다. 태스크
+ * 스캔 기간은 공유 결함인지 개인 결함인지에 따라 가중치가 다른 결함의
+ * 위치에 따라 조정됩니다.
+ * - remote / local / fail
+ */
unsigned long numa_faults_locality[3];
unsigned long numa_pages_migrated;
diff --git a/include/linux/sched/numa_balancing.h b/include/linux/sched/numa_balancing.h
index 3988762efe15..59c246d30e87 100644
--- a/include/linux/sched/numa_balancing.h
+++ b/include/linux/sched/numa_balancing.h
@@ -9,6 +9,11 @@
#include <linux/sched.h>
+/*
+ * IAMROOT, 2023.06.24:
+ * - TNF(task numa fault)
+ * TNF_NO_GROUP : rdonly에서는 group화 하지 않는다.(do_numa_page() 참고)
+ */
#define TNF_MIGRATED 0x01
#define TNF_NO_GROUP 0x02
#define TNF_SHARED 0x04
diff --git a/include/uapi/linux/mempolicy.h b/include/uapi/linux/mempolicy.h
index 5428de7f0161..1e53c1d14b8b 100644
--- a/include/uapi/linux/mempolicy.h
+++ b/include/uapi/linux/mempolicy.h
@@ -82,6 +82,10 @@ enum {
*/
#define MPOL_F_SHARED (1 << 0) /* identify shared policies */
#define MPOL_F_MOF (1 << 3) /* this policy wants migrate on fault */
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa balaning에서 사용하는 flag
+ */
#define MPOL_F_MORON (1 << 4) /* Migrate On protnone Reference On Node */
/*
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fb7a0f5eb579..27ebfeca2818 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -1564,12 +1564,24 @@ struct numa_group {
struct rcu_head rcu;
unsigned long total_faults;
+/*
+ * IAMROOT, 2023.06.24:
+ * - 전체 노드에 대해서 fault cpu를 더해놓은 통계값.
+ */
unsigned long max_faults_cpu;
/*
* Faults_cpu is used to decide whether memory should move
* towards the CPU. As a consequence, these stats are weighted
* more by CPU use than by memory faults.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * Faults_cpu는 메모리가 CPU 쪽으로 이동해야 하는지 여부를 결정하는
+ * 데 사용됩니다. 결과적으로 이러한 통계는 메모리 fault보다 CPU 사용에
+ * 더 많은 가중치를 부여합니다.
+ * - numa_faults 참고
+ */
unsigned long *faults_cpu;
unsigned long faults[];
};
@@ -1586,7 +1598,7 @@ static struct numa_group *deref_task_numa_group(struct task_struct *p)
/*
* IAMROOT, 2023.06.17:
- * - @p의 numa_group을 가져온다.
+ * - @p가 curr인경우에만 @p의 numa_group을 가져온다.
*/
static struct numa_group *deref_curr_numa_group(struct task_struct *p)
{
@@ -1616,7 +1628,7 @@ static unsigned int task_nr_scan_windows(struct task_struct *p)
* IAMROOT, 2023.06.17:
* - papago
* 존재하지 않는 빈 페이지로 RSS를 기반으로 하는 계산은 PTE 스캐너에서
- * 건너뛰고 NUMA 힌트 오류는 상주 페이지를 기반으로 트랩되어야 합니다.
+ * 건너뛰고 NUMA 힌트 fault는 상주 페이지를 기반으로 트랩되어야 합니다.
* - ex) PAGE_SIZE = 12
* nr_scan_pages * 2^8 = 256 * 256 = 65536 = 64kb = 2^16
*/
@@ -1833,7 +1845,7 @@ pid_t task_numa_group_id(struct task_struct *p)
/*
* IAMROOT, 2023.06.17:
* - papago
- * 평균 통계, 공유 및 개인, 메모리 및 CPU가 어레이의 전반부를 차지합니다.
+ * 평균 통계, 공유 및 private, 메모리 및 CPU가 어레이의 전반부를 차지합니다.
* 배열의 두 번째 절반은 task_numa_placement에 의해 첫 번째 세트로
* 평균화되는 현재 카운터용입니다.
*
@@ -1854,6 +1866,10 @@ static inline unsigned long task_faults(struct task_struct *p, int nid)
p->numa_faults[task_faults_idx(NUMA_MEM, nid, 1)];
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @group에 대한 @nid의 전체 memory node fault값(private + shared fault)
+ */
static inline unsigned long group_faults(struct task_struct *p, int nid)
{
struct numa_group *ng = deref_task_numa_group(p);
@@ -1865,6 +1881,10 @@ static inline unsigned long group_faults(struct task_struct *p, int nid)
ng->faults[task_faults_idx(NUMA_MEM, nid, 1)];
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @group에 대한 @nid의 전체 memory node fault cpu값(private + shared fault)
+ */
static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
{
return group->faults_cpu[task_faults_idx(NUMA_MEM, nid, 0)] +
@@ -1908,8 +1928,22 @@ static inline unsigned long group_faults_shared(struct numa_group *ng)
* considered part of a numa group's pseudo-interleaving set. Migrations
* between these nodes are slowed down, to allow things to settle down.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 최대값의 1/3보다 많은 NUMA 결함을 트리거하는 노드는 numa 그룹의
+ * 의사 인터리빙 세트의 일부로 간주됩니다. 이러한 노드 간의
+ * 마이그레이션은 속도가 느려지므로 문제가 해결됩니다.
+ */
#define ACTIVE_NODE_FRACTION 3
+/*
+ * IAMROOT, 2023.06.24:
+ * - max_faults_cpu의 1/3배 초과로 cpu fault가 많이 일어난경우.
+ * 즉 @ng fault개수에서 @nid의 fault cpu 비중이 많은경우이다.
+ * - 전체 노드대비 비율로 되기때문에 acitve인 node가 있고, inactive인 node가 있을것이다.
+ * - 비율상 active node는 최대 2개.
+ */
static bool numa_is_active_node(int nid, struct numa_group *ng)
{
return group_faults_cpu(ng, nid) * ACTIVE_NODE_FRACTION > ng->max_faults_cpu;
@@ -2025,6 +2059,16 @@ static inline unsigned long group_weight(struct task_struct *p, int nid,
return 1000 * faults / total_faults;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @dst_cpu로 numa migrate가 가능한지 확인한다.
+ * 1. scan 횟수가 적은경우 true
+ * 2.
+ * 3. private fault인경우 true.
+ * 4. dst_nid의 fault cpu이 src_nid fault cpu보다 3배초과인경우 true
+ * 5. fault cpu / falut mem의 비율이 dst가 1.33배이상 많은경우 true.
+ * 아니면 false
+ */
bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
int src_nid, int dst_cpu)
{
@@ -2041,6 +2085,16 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
* two full passes of the "multi-stage node selection" test that is
* executed below.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 첫 번째 fault 또는 private fault가 task lifetime 초기에 즉시 마이그레이션되도록
+ * 허용합니다. 매직 넘버 4는 아래에서 실행되는 다단계 노드 선택 테스트의
+ * 두 번의 전체 패스를 기다리는 것을 기반으로 합니다.
+ * - 초기에는(numa_scan 횟수 2번이하), 설정이 안됬거나, @p가 last_cpuid로 설정되있다면
+ * return true.
+ *
+ */
if ((p->numa_preferred_nid == NUMA_NO_NODE || p->numa_scan_seq <= 4) &&
(cpupid_pid_unset(last_cpupid) || cpupid_match_pid(p, last_cpupid)))
return true;
@@ -2062,15 +2116,42 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
* This quadric squishes small probabilities, making it less likely we
* act on an unlikely task<->page relation.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 다단계 노드 선택은 임시 작업<->페이지 관계를 구축하기 위해 주기적
+ * 마이그레이션 fault와 함께 사용됩니다. 2단계 필터를 사용하여 짧거나
+ * 가능성이 없는 관계를 제거합니다. 빈도주의자 확률에 따라
+ * P(p) ~ n_p / n_t를 사용하여 이 페이지의 총 사용량(n_t)당 특정
+ * 페이지의 작업 사용량(n_p)을 확률과 동일시할 수 있습니다.
+ *
+ * 주기적인 fault은 이 확률을 샘플링하고 이러한 샘플이 완전히 독립적인
+ * 경우 연속으로 두 번 동일한 결과를 얻고 샘플 기간이 사용 패턴에 비해
+ * 충분히 짧은 경우 P(n)^2로 제공됩니다.
+ *
+ * 이 2차 함수는 작은 확률을 찌그러뜨려 우리가 있을 법하지 않은
+ * 작업<->페이지 관계에서 행동할 가능성을 줄입니다.
+ *
+ * - last_cpupid가 설정되있었고, 그게 dst_nid가 아니라면 return false
+ */
if (!cpupid_pid_unset(last_cpupid) &&
cpupid_to_nid(last_cpupid) != dst_nid)
return false;
/* Always allow migrate on private faults */
+/*
+ * IAMROOT, 2023.06.24:
+ * - @p의 last pid와 @page의 lastpid가 같으면 private fault라고 판단하여
+ * return true.
+ */
if (cpupid_match_pid(p, last_cpupid))
return true;
/* A shared fault, but p->numa_group has not been set up yet. */
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa group이 아직 설정이 안됬으면 그냥 migrate 수행.
+ */
if (!ng)
return true;
@@ -2078,6 +2159,10 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
* Destination node is much more heavily used than the source
* node? Allow migration.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - @ng dst_nid가 src_nid보다 3배초과로 fault cpu 가 많이 발생했으면 옮긴다.
+ */
if (group_faults_cpu(ng, dst_nid) > group_faults_cpu(ng, src_nid) *
ACTIVE_NODE_FRACTION)
return true;
@@ -2090,6 +2175,18 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
* --------------- * - > ---------------
* faults_mem(dst) 4 faults_mem(src)
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 불필요한 메모리 마이그레이션을 방지하기 위해 3/4 히스테리시스를
+ * 사용하여 각 노드의 CPU 및 메모리 사용에 따라 메모리를 분배합니다.
+ *
+ * faults_cpu(dst) 3 faults_cpu(src)
+ * --------------- * - > ---------------
+ * faults_mem(dst) 4 faults_mem(src)
+ *
+ * - dst의 fault가 src보다 1.33배 이상 많다면 dst로 옮긴다.
+ */
return group_faults_cpu(ng, dst_nid) * group_faults(p, src_nid) * 3 >
group_faults_cpu(ng, src_nid) * group_faults(p, dst_nid) * 4;
}
@@ -3086,6 +3183,12 @@ static inline void put_numa_group(struct numa_group *grp)
kfree_rcu(grp, rcu);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - @p 요청
+ * tsk : @cpupid(page)의 cpu에서 동작중인 curr
+ * cpupid의 pid : @cpupid)를 마지막에 썻던 task
+ */
static void task_numa_group(struct task_struct *p, int cpupid, int flags,
int *priv)
{
@@ -3095,7 +3198,16 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
int cpu = cpupid_to_cpu(cpupid);
int i;
+/*
+ * IAMROOT, 2023.06.24:
+ * - first access시 grp를 만든다. @p의 값을 초기값으로 해서 생성한다.
+ * ING
+ */
if (unlikely(!deref_curr_numa_group(p))) {
+/*
+ * IAMROOT, 2023.06.24:
+ * - mem shared, mem priv, cpu shard, cpu priv 이렇게해서 4쌍
+ */
unsigned int size = sizeof(struct numa_group) +
4*nr_node_ids*sizeof(unsigned long);
@@ -3109,9 +3221,17 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
spin_lock_init(&grp->lock);
grp->gid = p->pid;
/* Second half of the array tracks nids where faults happen */
+/*
+ * IAMROOT, 2023.06.24:
+ * - faults 뒤에 address를 계산하여 faults_cpu에 넣는것.
+ */
grp->faults_cpu = grp->faults + NR_NUMA_HINT_FAULT_TYPES *
nr_node_ids;
+/*
+ * IAMROOT, 2023.06.24:
+ * - task것을 초기값으로 가져온다.
+ */
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
grp->faults[i] = p->numa_faults[i];
@@ -3122,11 +3242,24 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
}
rcu_read_lock();
+/*
+ * IAMROOT, 2023.06.24:
+ * - cpupid의 cpu에서 동작중인 task를 가져온다.
+ */
tsk = READ_ONCE(cpu_rq(cpu)->curr);
+/*
+ * IAMROOT, 2023.06.24:
+ * - 해당 page를 마지막에 접근했던 task와 page를 사용했던 cpu의 curr와
+ * 동일한지 비교한다.
+ */
if (!cpupid_match_pid(tsk, cpupid))
goto no_join;
+/*
+ * IAMROOT, 2023.06.24:
+ * - tsk(cpupid의 curr)의 ng가 없으면 return.
+ @*/
grp = rcu_dereference(tsk->numa_group);
if (!grp)
goto no_join;
@@ -3139,16 +3272,28 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
* Only join the other group if its bigger; if we're the bigger group,
* the other task will join us.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - my_grp -> grp로 옮길려고한다. my_grp이 작은데 괜히 옮길 필욘 없을것이다.
+ */
if (my_grp->nr_tasks > grp->nr_tasks)
goto no_join;
/*
* Tie-break on the grp address.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - 같다면, grp가 address가 큰경우에만 움직인다.
+ */
if (my_grp->nr_tasks == grp->nr_tasks && my_grp > grp)
goto no_join;
/* Always join threads in the same process. */
+/*
+ * IAMROOT, 2023.06.24:
+ * - 같은 process면 무조건 join
+ */
if (tsk->mm == current->mm)
join = true;
@@ -3159,6 +3304,10 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
/* Update priv based on whether false sharing was detected */
*priv = !join;
+/*
+ * IAMROOT, 2023.06.24:
+ * - grp로 get ref한다.
+ */
if (join && !get_numa_group(grp))
goto no_join;
@@ -3170,6 +3319,10 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
BUG_ON(irqs_disabled());
double_lock_irq(&my_grp->lock, &grp->lock);
+/*
+ * IAMROOT, 2023.06.24:
+ * - @p(current)에 대한 값들을 my_group -> grp으로 옮긴다.
+ */
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) {
my_grp->faults[i] -= p->numa_faults[i];
grp->faults[i] += p->numa_faults[i];
@@ -3183,8 +3336,16 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
spin_unlock(&my_grp->lock);
spin_unlock_irq(&grp->lock);
+/*
+ * IAMROOT, 2023.06.24:
+ * - 최종적으로 curr를 grp로 옮긴다.
+ */
rcu_assign_pointer(p->numa_group, grp);
+/*
+ * IAMROOT, 2023.06.24:
+ * - grp로 다 옮겨졌고, my_group은 ref down한다.
+ */
put_numa_group(my_grp);
return;
@@ -3236,6 +3397,10 @@ void task_numa_free(struct task_struct *p, bool final)
/*
* Got a PROT_NONE fault for a page on @node.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * -
+ */
void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
{
struct task_struct *p = current;
@@ -3253,6 +3418,10 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
return;
/* Allocate buffer to track faults on a per-node basis */
+/*
+ * IAMROOT, 2023.06.24:
+ * - 최초 memory 할당.
+ */
if (unlikely(!p->numa_faults)) {
int size = sizeof(*p->numa_faults) *
NR_NUMA_HINT_FAULT_BUCKETS * nr_node_ids;
@@ -3269,10 +3438,18 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
* First accesses are treated as private, otherwise consider accesses
* to be private if the accessing pid has not changed
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - first access는 priv 으로 처리.
+ */
if (unlikely(last_cpupid == (-1 & LAST_CPUPID_MASK))) {
priv = 1;
} else {
priv = cpupid_match_pid(p, last_cpupid);
+/*
+ * IAMROOT, 2023.06.24:
+ * - shared고, no group요청이 없엇으면 group화 한다.
+ */
if (!priv && !(flags & TNF_NO_GROUP))
task_numa_group(p, last_cpupid, flags, &priv);
}
@@ -3283,6 +3460,19 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
* actively using should be counted as local. This allows the
* scan rate to slow down when a workload has settled down.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 워크로드가 여러 NUMA 노드에 걸쳐 있는 경우 워크로드가 적극적으로
+ * 사용하는 노드 세트 내에서 전적으로 발생하는 공유 fault은 로컬로
+ * 계산되어야 합니다. 이렇게 하면 워크로드가 안정되었을 때 스캔
+ * 속도가 느려질 수 있습니다.
+ *
+ * - shared fault가 local로 처리가 되야되는 경우에 대한 처리.
+ * 1. workload가 여러 numa node에 걸쳐있다.
+ * 2. active node가 많다.
+ * 3. 그중에서도 cpu node, mem node 둘다 활성화되있다.
+ */
ng = deref_curr_numa_group(p);
if (!priv && !local && ng && ng->active_nodes > 1 &&
numa_is_active_node(cpu_node, ng) &&
@@ -3293,6 +3483,14 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
* Retry to migrate task to preferred node periodically, in case it
* previously failed, or the scheduler moved us.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 이전에 실패했거나 스케줄러가 이동한 경우 주기적으로 작업을 기본
+ * 노드로 마이그레이션을 다시 시도하십시오.
+ * - 실패했을경우 이번에 다시 한번 한다는 개념인듯
+ * - ING
+ */
if (time_after(jiffies, p->numa_migrate_retry)) {
task_numa_placement(p);
numa_migrate_preferred(p);
@@ -3344,6 +3542,13 @@ static void reset_ptenuma_scan(struct task_struct *p)
* - papago
* numa 마이그레이션의 비용이 많이 드는 부분은 task_work 컨텍스트에서 수행됩니다.
* task_tick_numa()에서 트리거됩니다.
+ *
+ * - 1. next scan 시간 갱신
+ * 2. 이미 scan 중이라고 판단되면 return
+ * 3. scan 갯수만큼의 pages를 vma를 순회하며 numa fault 시킨다.
+ * 4. scan 완료 next scan offset 갱신
+ * - 이 함수에서 numa fault의해서 mapping해제된 page는 fault 발생시
+ * handle_pte_fault()에서 do_numa_page()를 통해 수행할것이다.
*/
static void task_numa_work(struct callback_head *work)
{
@@ -3448,6 +3653,10 @@ static void task_numa_work(struct callback_head *work)
start = 0;
vma = mm->mmap;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - vma를 순회하며 pages개수만큼 numa fault 시킨다.
+ */
for (; vma; vma = vma->vm_next) {
/*
* IAMROOT, 2023.06.17:
@@ -3473,7 +3682,7 @@ static void task_numa_work(struct callback_head *work)
* - papago
* 여러 프로세스에 의해 매핑된 공유 라이브러리 페이지는 캐시 복제될 것으로
* 예상되므로 마이그레이션되지 않습니다. 읽기 전용 파일 지원 매핑 또는
- * vdso에서 힌트 결함을 피하십시오. 페이지를 마이그레이션하는 것이 약간의
+ * vdso에서 힌트 fault을 피하십시오. 페이지를 마이그레이션하는 것이 약간의
* 이점이 있을 것입니다.
*
* - library(readonly file)은 안한다. 주석내용확인.
@@ -3489,10 +3698,18 @@ static void task_numa_work(struct callback_head *work)
if (!vma_is_accessible(vma))
continue;
+/*
+ * IAMROOT, 2023.06.24:
+ * - HPAGE_SIZE단위로 ALIGN을 한 범위를 순회하며 numa fault시킨다.
+ */
do {
start = max(start, vma->vm_start);
end = ALIGN(start + (pages << PAGE_SHIFT), HPAGE_SIZE);
end = min(end, vma->vm_end);
+/*
+ * IAMROOT, 2023.06.24:
+ * - start ~ end까지 PAGE_NONE으로 numa fault식으로 update한다.
+ */
nr_pte_updates = change_prot_numa(vma, start, end);
/*
@@ -3511,11 +3728,15 @@ static void task_numa_work(struct callback_head *work)
* VMA에 사용되지 않았거나 이미 prot_numa PTE로 가득 찬 영역이
* 포함된 경우 해당 영역을 더 빨리 건너뛰려면 virtpages까지
* 스캔하십시오.
+ * - 남은것을 pages, virtpages에 기록한다.
*/
if (nr_pte_updates)
pages -= (end - start) >> PAGE_SHIFT;
virtpages -= (end - start) >> PAGE_SHIFT;
-
+/*
+ * IAMROOT, 2023.06.24:
+ * - 범위갱신
+ */
start = end;
if (pages <= 0 || virtpages <= 0)
goto out;
@@ -3559,6 +3780,7 @@ static void task_numa_work(struct callback_head *work)
* 확인하십시오.
* 일반적으로 update_task_scan_period는 스캔 속도를 충분히 늦춥니다.
* 오버로드된 시스템에서는 작업별로 오버헤드를 제한해야 합니다.
+ * - ex) numa fault하는 데 1초 걸렸으면, 최소 32초후에 하겠다는 의미.
*/
if (unlikely(p->se.sum_exec_runtime != runtime)) {
u64 diff = p->se.sum_exec_runtime - runtime;
@@ -3653,8 +3875,10 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
* IAMROOT, 2023.06.17:
* - callstack
* task_tick_fair() -> task_tick_numa()
+ *
* - numa scan시간이 됬으면 task work(task_numa_work)를 add한다.
* 즉 work수행요청.
+ * - numa balance time은 최대 task의 실행시간의 3%로 제한된다.
*/
static void task_tick_numa(struct rq *rq, struct task_struct *curr)
{
@@ -8847,7 +9071,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
/*
* IAMROOT. 2023.06.10:
* - google-translate
- * 우리가 바쁘다면 마지막 유휴 기간이 미래를 예측한다는 가정에 결함이
+ * 우리가 바쁘다면 마지막 유휴 기간이 미래를 예측한다는 가정에 fault이
* 있습니다. 남은 예상 유휴 시간을 에이징합니다.
*
* - 틱으로 wake_avg_idle을 반감시킨다.
@@ -16399,7 +16623,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
/*
* IAMROOT, 2023.06.17:
- * - numa balance
+ * - numa balance수행한다. 내부에서 numa balance시간이 도래했으면 수행하고 아니면
+ * 아무것도 안할것이다.
*/
if (static_branch_unlikely(&sched_numa_balancing))
task_tick_numa(rq, curr);
diff --git a/mm/memory.c b/mm/memory.c
index 865f113e9be8..62dcf6270c5d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4797,6 +4797,14 @@ static vm_fault_t do_fault(struct vm_fault *vmf)
return ret;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - local이면 이전이랑 같은 node에서 fault됬다는 의미이다.
+ * TNF_FAULT_LOCAL를 표시한다.
+ *
+ * - @return NUMA_NO_NODE : 이전 node유지
+ * != NUMA_NO_NODE : 추천 migrate node.
+ */
int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
unsigned long addr, int page_nid, int *flags)
{
@@ -4811,6 +4819,11 @@ int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
return mpol_misplaced(page, vma, addr);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa fault(task_numa_work() 참고)
+ * -
+ */
static vm_fault_t do_numa_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
@@ -4827,7 +4840,18 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
* validation through pte_unmap_same(). It's of NUMA type but
* the pfn may be screwed if the read is non atomic.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 이때 pte는 pte_unmap_same()을 통한 유효성 검사 없이는 안전하게
+ * 사용할 수 없습니다. NUMA 유형이지만 읽기가 원자적이지 않으면
+ * pfn이 망가질 수 있습니다.
+ */
vmf->ptl = pte_lockptr(vma->vm_mm, vmf->pmd);
+/*
+ * IAMROOT, 2023.06.24:
+ * - lock을 걸어서 확인.
+ */
spin_lock(vmf->ptl);
if (unlikely(!pte_same(*vmf->pte, vmf->orig_pte))) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
@@ -4836,6 +4860,11 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
/* Get the normal PTE */
old_pte = ptep_get(vmf->pte);
+/*
+ * IAMROOT, 2023.06.24:
+ * - fault를 시켜놨던 page다. 다시 정상으로 만들어주기 위해 원래의 prot로
+ * 원복을 시켜준다.
+ */
pte = pte_modify(old_pte, vma->vm_page_prot);
page = vm_normal_page(vma, vmf->address, pte);
@@ -4854,6 +4883,17 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
* pte_dirty has unpredictable behaviour between PTE scan updates,
* background writeback, dirty balancing and application behaviour.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 일반적으로 RO 페이지에서 그룹화하지 마십시오. RO 페이지는 공유 캐시
+ * 상태에 있을 수 있으므로 어쨌든 많이 손상되지 않아야 합니다.
+ * 이는 매핑이 쓰기 가능하지만 프로세스가 매핑에 쓰지 않지만 보호
+ * 업데이트 중에 pte_write가 지워지고 pte_dirty가 PTE 스캔 업데이트,
+ * 백그라운드 쓰기 저장, 더티 밸런싱 및 애플리케이션 동작 간에 예측할
+ * 수 없는 동작을 하는 경우를 놓치고 있습니다.
+ * - readonly page에서는 group하지 말라는것.
+ */
if (!was_writable)
flags |= TNF_NO_GROUP;
@@ -4861,13 +4901,28 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
* Flag if the page is shared between multiple address spaces. This
* is later used when determining whether to group tasks together
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 페이지가 여러 주소 공간 간에 공유되는 경우 플래그를 지정합니다.
+ * 이것은 나중에 작업을 함께 그룹화할지 여부를 결정할 때 사용됩니다.
+ * - user가 여러명이다. shared page라는것을 표시한다.
+ */
if (page_mapcount(page) > 1 && (vma->vm_flags & VM_SHARED))
flags |= TNF_SHARED;
last_cpupid = page_cpupid_last(page);
page_nid = page_to_nid(page);
+/*
+ * IAMROOT, 2023.06.24:
+ * - mpol 및 fault count를 비교하여 추천 nid를 알아온다.
+ */
target_nid = numa_migrate_prep(page, vma, vmf->address, page_nid,
&flags);
+/*
+ * IAMROOT, 2023.06.24:
+ * - 이전 node 유지면 별거 안한다.
+ */
if (target_nid == NUMA_NO_NODE) {
put_page(page);
goto out_map;
@@ -4876,12 +4931,24 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
/* Migrate to the requested node */
if (migrate_misplaced_page(page, vma, target_nid)) {
+/*
+ * IAMROOT, 2023.06.24:
+ * - migrate가 전부 성공
+ */
page_nid = target_nid;
flags |= TNF_MIGRATED;
} else {
+/*
+ * IAMROOT, 2023.06.24:
+ * - migrate 실패(전부 실패 or 일부만 성공)
+ */
flags |= TNF_MIGRATE_FAIL;
vmf->pte = pte_offset_map(vmf->pmd, vmf->address);
spin_lock(vmf->ptl);
+/*
+ * IAMROOT, 2023.06.24:
+ * - fault당시 pte와 현재 pte를 비교해서 변경이 생겼으면 out.
+ */
if (unlikely(!pte_same(*vmf->pte, vmf->orig_pte))) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
goto out;
@@ -4890,9 +4957,19 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)
}
out:
+/*
+ * IAMROOT, 2023.06.24:
+ * - 1.
+ * - migrate를 성공했다면 page_nid는 target_nid,
+ * 아니라면 원래 자신의 nid를 가리킨다.
+ */
if (page_nid != NUMA_NO_NODE)
task_numa_fault(last_cpupid, page_nid, 1, flags);
return 0;
+/*
+ * IAMROOT, 2023.06.24:
+ * - 아무것도 안하고 나가는겨ㅓㅇ우
+ */
out_map:
/*
* Make it present again, depending on how arch implements
@@ -5056,13 +5133,23 @@ static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
/*
* IAMROOT, 2022.06.04:
* - vmf->pte가 있지만 present가 안된. 즉 invalid. swap 상태라는의미.
+ * - 즉 mapping이 없는 상태.
*/
if (!pte_present(vmf->orig_pte))
return do_swap_page(vmf);
/*
* IAMROOT, 2022.06.04:
+ * - fault는 일반적으로 mapping이 없다. 하지만 이 이후는 mapping이 있어도
+ * fault가 발생한 page들이다. 여기에 대한 case를 진행한다.
+ * 대표적으로 2개의 case가 있다.
+ * 1. numa fault
+ * 2. write protect
+ *
+ * - numa fault(task_numa_work() 참고)
* - numa_balancing으로 fault가 발생한지 확인한다.
+ * numa fault시 PTE_PROT_NONE으로 설정했었다. 그렇기 때문에 prot none인지
+ * 확인하는것이다.
*/
if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))
return do_numa_page(vmf);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index aeccfb8b90b9..8b3941c2d946 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -649,7 +649,7 @@ static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask,
*
* 이것은 NUMA fault가 PROT_NONE을 사용하여 처리된다고 가정합니다.
* 아키텍처가 다른 선택을 하면 코어에 추가 변경이 필요합니다.
- * -
+ * - @addr ~ @end까지 numa fault방법(MM_CP_PROT_NUMA)으로 PAGE_NONE를 적용한다.
*/
unsigned long change_prot_numa(struct vm_area_struct *vma,
unsigned long addr, unsigned long end)
@@ -1951,7 +1951,7 @@ unsigned int mempolicy_slab_node(void)
*/
/*
* IAMROOT, 2022.05.14:
- * - @p에 따라 node를 선택한다.
+ * - @pol에 따라 node를 선택한다.
*/
static unsigned offset_il_node(struct mempolicy *pol, unsigned long n)
{
@@ -2563,6 +2563,30 @@ static void sp_free(struct sp_node *n)
* Return: NUMA_NO_NODE if the page is in a node that is valid for this
* policy, or a suitable node ID to allocate a replacement page from.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * mpol_misplaced - 현재 페이지 노드가 정책에서 유효한지 확인합니다.
+ *
+ * @page: 확인할 페이지.
+ * @vma: 페이지가 매핑된 vm 영역.
+ * @addr: 페이지가 매핑된 가상 주소.
+ *
+ * vma,addr에 대한 현재 정책 노드 ID를 조회하고 페이지의 노드 ID와
+ * 비교합니다. 정책 결정은 alloc_page_vma()를 모방합니다.
+ * vma 및 결함 주소를 알고 있는 결함 경로에서 호출됩니다.
+ *
+ * Return: 페이지가 이 정책에 유효한 노드에 있는 경우 NUMA_NO_NODE
+ * 또는 교체 페이지를 할당하는 데 적합한 노드 ID입니다.
+ *
+ * - return NUMA_NO_NODE : @vma의 mpol 정책에 유효한 상황. 이전 nid유지
+ * 특정 node : @vma의 mpol에 적당한 node 번호.
+ * - mpol에 따른 node 번호를 가져온다.
+ * - 아래의 상황에따라 node를 선택한다.
+ * 1. 이전 node 유지(return NUMA_NO_NODE)
+ * 2. 특수한 상황 this node로 강제설정(MPOL_F_MORON이 있고, mpol, fault count비교등)
+ * 3. mpol에 따라 새로 선택한 node.
+ */
int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long addr)
{
struct mempolicy *pol;
@@ -2575,9 +2599,26 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
int ret = NUMA_NO_NODE;
pol = get_vma_policy(vma, addr);
+/*
+ * IAMROOT, 2023.06.24:
+ * - MOF면 못옮긴다. 즉 그냥 써야된다. 그런 의미에서 현재 node가 유효하다는
+ * 의미로 return NUMA_NO_NODE.
+ */
if (!(pol->flags & MPOL_F_MOF))
goto out;
+/*
+ * IAMROOT, 2023.06.24:
+ * - MPOL_F_MORON이 설정되있을경우(즉 thisnid로 강제설정 및 fault count 비교)
+ * MPOL_INTERLEAVE -> MPOL_F_MORON
+ * MPOL_PREFERRED -> 1. curnid가 pol에 소속 O -> curnid선택
+ * 2. MPOL_F_MORON
+ * MPOL_LOCAL -> MPOL_F_MORON
+ * MPOL_BIND -> 1. thisnid가 pol에 소속 O -> MPOL_F_MORON
+ * 2. NUMA_NO_NODE
+ * MPOL_PREFERRED_MANY -> 1. curnid가 pol에 소속 O-> NUMA_NO_NODE
+ * 2. MPOL_F_MORON
+ */
switch (pol->mode) {
case MPOL_INTERLEAVE:
pgoff = vma->vm_pgoff;
@@ -2624,6 +2665,10 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
}
/* Migrate the page towards the node whose CPU is referencing it */
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa policy였을경우 위 MPOL에 상관없이 thisnid로 교체한다.
+ */
if (pol->flags & MPOL_F_MORON) {
polnid = thisnid;
@@ -2631,6 +2676,10 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
goto out;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - 그전에 있었던 node와 새로 구한 node가 일치지 않은 경우만 return값 갱신
+ */
if (curnid != polnid)
ret = polnid;
out:
diff --git a/mm/migrate.c b/mm/migrate.c
index 11fc031394b8..7d49fc0e1666 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2385,6 +2385,15 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
* Returns true if this is a safe migration target node for misplaced NUMA
* pages. Currently it only checks the watermarks which crude
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 잘못 배치된 NUMA 페이지에 대한 안전한 마이그레이션 대상 노드인 경우
+ * true를 반환합니다. 현재는 조잡한 워터마크만 확인합니다.
+ *
+ * - @nr_migrate_pages만큼 migrate할 page가 있는지 확인한다. 있다면
+ * return true.
+ */
static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
unsigned long nr_migrate_pages)
{
@@ -2407,6 +2416,12 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
return false;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - migrate_misplaced_page() 참고
+ * - @nid에서만 할당. movable(user용 memory) page할당. reclaim 및 retry
+ * 할필요없음등의 조건을 사용하여 할당을 받아온다.
+ */
static struct page *alloc_misplaced_dst_page(struct page *page,
unsigned long data)
{
@@ -2422,6 +2437,10 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
return newpage;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - PASS
+ */
static struct page *alloc_misplaced_dst_page_thp(struct page *page,
unsigned long data)
{
@@ -2439,6 +2458,13 @@ static struct page *alloc_misplaced_dst_page_thp(struct page *page,
return newpage;
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - lru list에서 @page를 isolate한다.
+ *
+ * - return 0 : isolate 실패
+ * 1 : isolate성공.
+ */
static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
{
int page_lru;
@@ -2466,6 +2492,12 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
* caller's reference can be safely dropped without the page
* disappearing underneath us during migration.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 페이지를 분리하면 다른 참조가 있으므로 마이그레이션 중에 페이지가
+ * 사라지지 않고 호출자의 참조를 안전하게 삭제할 수 있습니다.
+ */
put_page(page);
return 1;
}
@@ -2475,6 +2507,15 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
* node. Caller is expected to have an elevated reference count on
* the page that will be dropped by this function before returning.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 잘못 배치된 페이지를 지정된 대상 노드로 마이그레이션하려고
+ * 시도합니다. 호출자는 반환하기 전에 이 함수에 의해 삭제될
+ * 페이지에서 높은 참조 횟수를 가질 것으로 예상됩니다.
+ *
+ * - lru page에서 isolate후 @node로 migrate한다.
+ */
int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
int node)
{
@@ -2491,6 +2532,13 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
* be either base page or THP. And it must be head page if it is
* THP.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * PTE 매핑된 THP 또는 HugeTLB 페이지는 여기에 도달할 수 없으므로
+ * 페이지는 기본 페이지 또는 THP일 수 있습니다. 그리고 THP라면 반드시
+ * 헤드페이지여야 합니다.
+ */
compound = PageTransHuge(page);
if (compound)
@@ -2502,6 +2550,13 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
* Don't migrate file pages that are mapped in multiple processes
* with execute permissions as they are probably shared libraries.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 실행 권한이 있는 여러 프로세스에서 매핑된 파일 페이지는 아마도
+ * 공유 라이브러리일 수 있으므로 마이그레이션하지 마십시오.
+ * - 실행가능한 공유라이브러리는 옮기지 않는다.
+ */
if (page_mapcount(page) != 1 && page_is_file_lru(page) &&
(vma->vm_flags & VM_EXEC))
goto out;
@@ -2510,6 +2565,14 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
* Also do not migrate dirty pages as not all filesystems can move
* dirty pages in MIGRATE_ASYNC mode which is a waste of cycles.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * 또한 모든 파일 시스템이 순환 낭비인 MIGRATE_ASYNC 모드에서
+ * 더티 페이지를 이동할 수 있는 것은 아니므로 더티 페이지를
+ * 마이그레이션하지 마십시오.
+ * - 쓰기 기록중인 file page는 옮기지 않는다.
+ */
if (page_is_file_lru(page) && PageDirty(page))
goto out;
@@ -2520,6 +2583,11 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
list_add(&page->lru, &migratepages);
nr_remaining = migrate_pages(&migratepages, *new, NULL, node,
MIGRATE_ASYNC, MR_NUMA_MISPLACED, NULL);
+/*
+ * IAMROOT, 2023.06.24:
+ * - migrate 못한것들은 원래 있던 lru로 복귀 시킨다.
+ * 일부만 성공했을경우 실패로 간주한다.
+ */
if (nr_remaining) {
if (!list_empty(&migratepages)) {
list_del(&page->lru);
diff --git a/mm/mmzone.c b/mm/mmzone.c
index 6685914eef24..ff33ba41d5a3 100644
--- a/mm/mmzone.c
+++ b/mm/mmzone.c
@@ -95,6 +95,10 @@ void lruvec_init(struct lruvec *lruvec)
}
#if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS)
+/*
+ * IAMROOT, 2023.06.24:
+ * - @cpupid로 교체하면서 oldcpuid를 가져온다.
+ */
int page_cpupid_xchg_last(struct page *page, int cpupid)
{
unsigned long old_flags, flags;
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 82d0b941c8ea..9eebd7c11665 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -40,6 +40,10 @@
* - numa fault page 전환인 경우(change_prot_numa() 확인)
* @cp_flags MM_CP_PROT_NUMA.
* @newprot PAGE_NONE
+ * @addr부터 @end까지에 대해 다음을 처리한다.
+ * 1. old를 가져오면서 0 clear를 한다.(modify중 잠깐)
+ * 2. hw dirty가 발생했을경우 sw dirty를 기록해준다.
+ * 3. @newprot(PTE_PROT_NONE)를 설정해준다.(기존 oldpte중에 일부 bit는 가져온다.)
*/
static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
unsigned long addr, unsigned long end, pgprot_t newprot,
@@ -94,6 +98,13 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
flush_tlb_batched_pending(vma->vm_mm);
arch_enter_lazy_mmu_mode();
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa fault인 경우
+ * 1. old를 가져오면서 0 clear를 한다.
+ * 2. hw dirty가 발생했을경우 sw dirty를 기록해준다.
+ * 3. @newprot(PTE_PROT_NONE)중 pte_modity()의 mask에 해당하는 부분들을 old에서 update한다.
+ */
do {
oldpte = *pte;
/*
@@ -177,14 +188,29 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
/*
* IAMROOT, 2023.06.17:
- * - old를 가져오면서 0clear를 한다.
- * - ING
+ * - old를 가져오면서 0 clear를 한다.
*/
oldpte = ptep_modify_prot_start(vma, addr, pte);
+/*
+ * IAMROOT, 2023.06.24:
+ * - mask (PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
+ * PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
+ * PTE_ATTRINDX_MASK)에서 @newprot에 포함된것들을 oldpte에
+ * 추가해서 가져온다. 그리고 oldpte가 hw dirty라면 sw dirty를
+ * 추가한다.
+ */
ptent = pte_modify(oldpte, newprot);
+/*
+ * IAMROOT, 2023.06.24:
+ * - numa fault면서 hw dirty였으면 rdonly를 지우는 개념으로 해준다.
+ */
if (preserve_write)
ptent = pte_mk_savedwrite(ptent);
+/*
+ * IAMROOT, 2023.06.24:
+ * - uffd pass
+ */
if (uffd_wp) {
ptent = pte_wrprotect(ptent);
ptent = pte_mkuffd_wp(ptent);
@@ -199,11 +225,19 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
}
/* Avoid taking write faults for known dirty pages */
+/*
+ * IAMROOT, 2023.06.24:
+ * - dirty account pass
+ */
if (dirty_accountable && pte_dirty(ptent) &&
(pte_soft_dirty(ptent) ||
!(vma->vm_flags & VM_SOFTDIRTY))) {
ptent = pte_mkwrite(ptent);
}
+/*
+ * IAMROOT, 2023.06.24:
+ * - pte에 ptent를 최종적으로 기록한다.
+ */
ptep_modify_prot_commit(vma, addr, pte, oldpte, ptent);
pages++;
} else if (is_swap_pte(oldpte)) {
@@ -288,7 +322,7 @@ static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd)
/*
* IAMROOT, 2023.06.17:
- * -
+ * - pte를 순회한다.
*/
static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
pud_t *pud, unsigned long addr, unsigned long end,
@@ -372,7 +406,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
/*
* IAMROOT, 2023.06.17:
- * -
+ * - pmd를 순회한다.
*/
static inline unsigned long change_pud_range(struct vm_area_struct *vma,
p4d_t *p4d, unsigned long addr, unsigned long end,
@@ -396,7 +430,7 @@ static inline unsigned long change_pud_range(struct vm_area_struct *vma,
/*
* IAMROOT, 2023.06.17:
- * -
+ * - pud를 순회한다
*/
static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
pgd_t *pgd, unsigned long addr, unsigned long end,
@@ -420,7 +454,7 @@ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
/*
* IAMROOT, 2023.06.17:
- * -
+ * - p4d를 순회한다.
*/
static unsigned long change_protection_range(struct vm_area_struct *vma,
unsigned long addr, unsigned long end, pgprot_t newprot,
@@ -454,7 +488,7 @@ static unsigned long change_protection_range(struct vm_area_struct *vma,
/*
* IAMROOT, 2023.06.17:
- * -
+ * - @start ~ @end까지 @newprot를 적용한다.
*/
unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
unsigned long end, pgprot_t newprot,
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 20265b0a24bb..7e370330f2e3 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2617,6 +2617,34 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
* (2) the lru_lock must not be held.
* (3) interrupts must be enabled.
*/
+/*
+ * IAMROOT, 2023.06.24:
+ * - papago
+ * isolate_lru_page - LRU 목록에서 페이지를 분리하려고 시도합니다.
+ * @page: LRU 목록에서 격리할 페이지
+ *
+ * LRU 목록에서 @page를 분리하고 PageLRU를 지우고 페이지가 있던
+ * LRU 목록에 해당하는 vmstat 통계를 조정합니다.
+ *
+ * 페이지가 LRU 목록에서 제거된 경우 0을 반환합니다.
+ * 페이지가 LRU 목록에 없으면 -EBUSY를 반환합니다.
+ *
+ * 반환된 페이지는 PageLRU()가 지워집니다. 활성 목록에서 찾은 경우
+ * PageActive가 설정됩니다. 제거할 수 없는 목록에서 찾은 경우
+ * PageUnevictable 비트가 설정됩니다. 해당 플래그는 페이지를
+ * 이동하기 전에 호출자가 지워야 할 수 있습니다.
+ *
+ * 페이지가 발견된 목록에 해당하는 vmstat 통계가 감소합니다.
+ *
+ * 제한:
+ * (1) 페이지에서 높은 refcount로 호출해야 합니다. 이것은
+ * isolate_lru_pages(안정적인 참조 없이 호출됨)와 근본적인 차이점입니다.
+ * (2) lru_lock을 보유하지 않아야 합니다.
+ * (3) 인터럽트를 활성화해야 합니다.
+ * - lru list에서 page를 분리한다.
+ *
+ * return 0 : lru page에서 삭제 성공.
+ */
int isolate_lru_page(struct page *page)
{
int ret = -EBUSY;
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 627 |
228 | [커널 20차] 20주차 [2] | 이민찬 | 2023.09.17 | 182 |
227 | [커널 20차] 19주차 | 이민찬 | 2023.09.10 | 103 |
226 | [커널 20차] 18주차 | 이민찬 | 2023.09.03 | 85 |
225 | [커널 20차] 17주차 | 이민찬 | 2023.08.27 | 129 |
224 | [커널 20차] 16주차 | 이민찬 | 2023.08.20 | 132 |
223 | [커널 19차] 64 주차 | Min | 2023.08.19 | 91 |
222 | [커널 20차] 15주차 | 이민찬 | 2023.08.13 | 126 |
221 | [커널 19차] 63 주차 | Min | 2023.08.12 | 60 |
220 | [커널 19차] 62 주차 | Min | 2023.08.05 | 79 |
219 | [커널 20차] 13주차 | 이민찬 | 2023.07.30 | 106 |
218 | [커널 19차] 61 주차 | Min | 2023.07.30 | 45 |
217 | [커널 20차] 12주차 | 이민찬 | 2023.07.22 | 87 |
216 | [커널 19차] 59 ~ 60 주차 | Min | 2023.07.22 | 37 |
215 | [커널 18차] 113주차 | kkr | 2023.07.22 | 78 |
214 | [커널20차] 11주차 | 이경재 | 2023.07.15 | 86 |
213 | [커널20차] 10주차 | 이경재 | 2023.07.09 | 90 |
212 | [커널20차] 9주차 | 이경재 | 2023.07.02 | 85 |
211 | [커널 19차] 58 주차 | Min | 2023.07.01 | 41 |
210 | [커널 19차] 56 ~ 57 주차 | Min | 2023.06.25 | 40 |
» | [커널 18차] 109주차 | kkr | 2023.06.24 | 33 |
.