[커널 18차] 52주차
2022.05.21 22:21
git : https://github.com/iamroot18/5.10/commit/bfaeb8db2feff86ed33ad9737add56b36ea44aa5
git : https://github.com/iamroot18/5.10/commit/25c5b2f6fef886bdf48bab668e09baa92d4aeda0
diff --git a/README.md b/README.md
index 4f170062ee5d..a8aa1a0f909f 100644
--- a/README.md
+++ b/README.md
@@ -236,3 +236,7 @@
- 2022.05.14, Zoom 온라인(6명 참석)
- alloc_pages_vma() 진행중
+### 52주차
+- 2022.05.21, Zoom 온라인(5명 참석)
+- sys_mmap() 진행중
+
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index d5ffaaab31a7..ed17c7ac20e7 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -18,6 +18,43 @@
#include <asm/cpufeature.h>
#include <asm/syscall.h>
+/*
+ * IAMROOT, 2022.05.21:
+ * - arm64 sys_mmap
+ *
+ * ex) user에서 malloc을 사용했을때 strace 사용결과
+ * sh) strace ./test
+ * == strace
+ * mmap(NULL, 1000001536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb4af7ee000
+ *
+ * == smaps log(heap 측 부분)
+ * 7fb4af7ee000-7fb4eb19b000 rw-p 00000000 00:00 0
+ * Size: 976564 kB
+ * KernelPageSize: 4 kB
+ * MMUPageSize: 4 kB
+ * Rss: 976564 kB
+ * Pss: 976564 kB
+ * Shared_Clean: 0 kB
+ * Shared_Dirty: 0 kB
+ * Private_Clean: 0 kB
+ * Private_Dirty: 976564 kB
+ * Referenced: 976564 kB
+ * Anonymous: 976564 kB
+ * LazyFree: 0 kB
+ * AnonHugePages: 0 kB
+ * ShmemPmdMapped: 0 kB
+ * FilePmdMapped: 0 kB
+ * Shared_Hugetlb: 0 kB
+ * Private_Hugetlb: 0 kB
+ * Swap: 0 kB
+ * SwapPss: 0 kB
+ * Locked: 0 kB
+ * THPeligible: 0
+ * VmFlags: rd wr mr(may read) mw(may write) me(may execute) ac sd
+ *
+ * read, write 권한이 있는 vma라는것을 알수있다.
+ * malloc을 호출하면 항상 위와같은 prot, flag를 사용한다.
+ */
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, off)
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 2c68a545ffa7..c7eb4a0d855b 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -498,6 +498,11 @@ static inline void tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *
#endif
#ifndef tlb_end_vma
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - tlb flush
+ */
static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
{
if (tlb->fullmm)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 771445153c27..a782ddc7723b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2842,6 +2842,11 @@ extern struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned lon
* Returns: The first VMA within the provided range, %NULL otherwise. Assumes
* start_addr < end_addr.
*/
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - 겹치는 vma를 찾아온다.
+ */
static inline
struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
unsigned long start_addr,
@@ -2872,6 +2877,10 @@ struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)
return vma;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - @vma가 아래로 내려가는 stack인 경우 보정.
+ */
static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
{
unsigned long vm_start = vma->vm_start;
@@ -2884,6 +2893,10 @@ static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
return vm_start;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - @vma가 위로 올라가는 stack인 경우 보정.
+ */
static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
{
unsigned long vm_end = vma->vm_end;
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6b18fa566f15..685cdb6268f1 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -434,6 +434,13 @@ struct vm_area_struct {
* VMAs below us in the VMA rbtree and its ->vm_prev. This helps
* get_unmapped_area find a free area of the right size.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - 이 VMA의 왼쪽에 있는 최대 사용 가능한 메모리 간격(바이트)입니다.
+ * 이 VMA와 vma->vm_prev 사이 또는 VMArbtree에서 아래 VMA 중 하나와
+ * 해당 ->vm_prev 사이입니다. 이렇게 하면 get_unmapped_area가 올바른
+ * 크기의 빈 영역을 찾을 수 있습니다.
+ */
unsigned long rb_subtree_gap;
/* Second cache line starts here. */
@@ -594,6 +601,11 @@ struct mm_struct {
unsigned long total_vm; /* Total pages mapped */
unsigned long locked_vm; /* Pages that have PG_mlocked set */
atomic64_t pinned_vm; /* Refcount permanently increased */
+/*
+ * IAMROOT, 2022.05.21:
+ * - data공간이라 하면 주석과 같이 not stack, not shared를 의미한다.
+ * (is_data_mapping() 참고)
+ */
unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
unsigned long stack_vm; /* VM_STACK */
diff --git a/include/linux/mman.h b/include/linux/mman.h
index b66e91b8176c..3837d952a6b1 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -130,6 +130,10 @@ static inline bool arch_validate_flags(unsigned long flags)
* but this version is faster.
* ("bit1" and "bit2" must be single bits)
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - bit1이 있으면 bit2 return 이라는뜻.
+ */
#define _calc_vm_trans(x, bit1, bit2) \
((!(bit1) || !(bit2)) ? 0 : \
((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \
@@ -138,6 +142,16 @@ static inline bool arch_validate_flags(unsigned long flags)
/*
* Combine the mmap "prot" argument into "vm_flags" used internally.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - prot flag를 vm flag로 변환하고 arch 에 따른 flag 추가가 있으면
+ * 추가 한다.
+ * - PROT_READ -> VM_READ
+ * PROT_WRITE -> VM_WRITE
+ * PROT_EXEC -> VM_EXEC
+ * PROT_BTI -> VM_ARM64_BTI
+ * PROT_MTE -> VM_MTE
+ */
static inline unsigned long
calc_vm_prot_bits(unsigned long prot, unsigned long pkey)
{
@@ -150,6 +164,14 @@ calc_vm_prot_bits(unsigned long prot, unsigned long pkey)
/*
* Combine the mmap "flags" argument into "vm_flags" used internally.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - map flags를 vm flags로 변환한다.
+ * - MAP_GROWSDOWN -> VM_GROWSDOWN
+ * MAP_LOCKED -> VM_LOCKED
+ * MAP_SYNC -> VM_SYNC
+ * MAP_ANONYMOUS -> VM_MTE_ALLOWED
+ */
static inline unsigned long
calc_vm_flag_bits(unsigned long flags)
{
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index b21041b8a292..79fd1b9a2ca5 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -751,6 +751,10 @@ static inline unsigned long task_rlimit_max(const struct task_struct *task,
return READ_ONCE(task->signal->rlim[limit].rlim_max);
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - 해당 task가 @limit에 해당하는 제한 값을 읽어온다.
+ */
static inline unsigned long rlimit(unsigned int limit)
{
return task_rlimit(current, limit);
diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index 1567a3294c3d..7964669e1fa5 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -19,12 +19,27 @@
/* 0x01 - 0x03 are defined in linux/mman.h */
#define MAP_TYPE 0x0f /* Mask for type of mapping */
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - 가상공간의 특정영역에 고정시키고 싶을때 사용한다.
+ */
#define MAP_FIXED 0x10 /* Interpret addr exactly */
#define MAP_ANONYMOUS 0x20 /* don't use a file */
/* 0x0100 - 0x4000 flags are defined in asm-generic/mman.h */
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - mapping을 바로 하고싶을때 사용한다.
+ */
#define MAP_POPULATE 0x008000 /* populate (prefault) pagetables */
#define MAP_NONBLOCK 0x010000 /* do not block on IO */
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - user stack만들때 brk를 호출하거나 MAP_STACK을 사용해서 sys_mmap을 호출에서 사용하게 될것이다.
+ */
#define MAP_STACK 0x020000 /* give out an address that is best suited for process/thread stacks */
#define MAP_HUGETLB 0x040000 /* create a huge page mapping */
#define MAP_SYNC 0x080000 /* perform synchronous page faults for the mapping */
diff --git a/include/uapi/asm-generic/resource.h b/include/uapi/asm-generic/resource.h
index f12db7a0da64..e854ec0bb9e7 100644
--- a/include/uapi/asm-generic/resource.h
+++ b/include/uapi/asm-generic/resource.h
@@ -13,6 +13,10 @@
* then it defines them prior including asm-generic/resource.h. )
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - resource 제한에 대한것들.
+ */
#define RLIMIT_CPU 0 /* CPU time in sec */
#define RLIMIT_FSIZE 1 /* Maximum filesize */
#define RLIMIT_DATA 2 /* max data size */
diff --git a/mm/internal.h b/mm/internal.h
index 41a80aa78fdb..50d666dccaee 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -467,6 +467,11 @@ static inline bool is_stack_mapping(vm_flags_t flags)
/*
* Data area - private, writable, not stack
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * stack을 제외한 data 공간.
+ * Data area - private, writable, not stack
+ */
static inline bool is_data_mapping(vm_flags_t flags)
{
return (flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE;
diff --git a/mm/memory.c b/mm/memory.c
index a894b8b93500..362aee2c067e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1539,6 +1539,10 @@ static inline unsigned long zap_p4d_range(struct mmu_gather *tlb,
return addr;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - 해당 영역의 정규 mapping을 unmap
+ */
void unmap_page_range(struct mmu_gather *tlb,
struct vm_area_struct *vma,
unsigned long addr, unsigned long end,
@@ -1556,10 +1560,17 @@ void unmap_page_range(struct mmu_gather *tlb,
continue;
next = zap_p4d_range(tlb, vma, pgd, addr, next, details);
} while (pgd++, addr = next, addr != end);
+/*
+ * IAMROOT, 2022.05.21:
+ * - @vma에 대한 tlb flush
+ */
tlb_end_vma(tlb, vma);
}
-
+/*
+ * IAMROOT, 2022.05.21:
+ * - @vma unmmap
+ */
static void unmap_single_vma(struct mmu_gather *tlb,
struct vm_area_struct *vma, unsigned long start_addr,
unsigned long end_addr,
@@ -1621,6 +1632,33 @@ static void unmap_single_vma(struct mmu_gather *tlb,
* ensure that any thus-far unmapped pages are flushed before unmap_vmas()
* drops the lock and schedules.
*/
+
+/*
+ * IAMROOT, 2022.05.21:
+ *
+ * ^ ---- vm_end
+ * | <- vma4
+ * | --- end
+ * | ^ <- vma3->next = vma4
+ * v ---- vm_start |
+ * |
+ * ... ..
+ *
+ * ^ ---- vm_end |
+ * | |
+ * | | <- vma2->next = vma3
+ * v ---- vm_start |
+ * |
+ * ... ..
+ * |
+ * ^ ---- vm_end |
+ * | v <- vma->next = vma2
+ * | --- start
+ * | <-- prev
+ * v ---- vm_start
+ *
+ * vma부터 ~ vma4까지 unmap될것이다.(unmap_vmas())
+ */
void unmap_vmas(struct mmu_gather *tlb,
struct vm_area_struct *vma, unsigned long start_addr,
unsigned long end_addr)
@@ -3717,6 +3755,10 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
* but allow concurrent faults), and pte mapped but not yet locked.
* We return with mmap_lock still held, but pte unmapped and unlocked.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - anon page fault시 이 함수로 진입하게 될것이다.
+ */
static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index f6374420b604..d729ac325cf4 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1840,6 +1840,10 @@ nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy)
* policy_node() is always coupled with policy_nodemask(), which
* secures the nodemask limit for 'bind' and 'prefer-many' policy.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - @policy->mode 가 MPOL_PREFERRED인 경우 first node를 return한다.
+ */
static int policy_node(gfp_t gfp, struct mempolicy *policy, int nd)
{
if (policy->mode == MPOL_PREFERRED) {
@@ -2193,6 +2197,14 @@ static struct page *alloc_pages_preferred_many(gfp_t gfp, unsigned int order,
*
* Return: The page on success or NULL if allocation fails.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - numa Policy는 주로 app을 위한 정책이다. policy에 따라 alloc_pages를 호출한다.
+ *
+ * ---
+ * - kernel같은 경우은 local이 preferred 인 개념이되고(나머지는 cost순),
+ * app같은 경우엔 사용자가 설정한 node policy에 따르게 된다.
+ */
struct page *alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
unsigned long addr, int node, bool hugepage)
{
@@ -2218,6 +2230,10 @@ struct page *alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
goto out;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - PASS
+ */
if (unlikely(IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && hugepage)) {
int hpage_node = node;
diff --git a/mm/mmap.c b/mm/mmap.c
index 88dcc5c25225..5fbaec5b13dd 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -175,6 +175,10 @@ void unlink_file_vma(struct vm_area_struct *vma)
/*
* Close a vm structure and free it, returning the next.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - @vma를 해제하고 return next vma
+ */
static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
{
struct vm_area_struct *next = vma->vm_next;
@@ -526,6 +530,39 @@ anon_vma_interval_tree_post_update_vma(struct vm_area_struct *vma)
anon_vma_interval_tree_insert(avc, &avc->anon_vma->rb_root);
}
+/*
+ * IAMROOT, 2022.05.21:
+ * @pprev[out] 새로 생길 lead node의 prev node
+ * @rb_link[out] 새로 생길 leaf node가 연결될 parent의 left or right pointer.
+ * @rb_parent[out] rb_link의 parent
+ *
+ * - @addr ~ end까지 겹치는 vma가 있다면 error. 그렇지 않다면 vma가 위치할
+ * null pointer를 찾아 새로 생길 leaf node의 자리를 구하고(rb_link)
+ * 해당 node의 parent(rb_parent)와 before node(pprev)를 구하고 return 0.
+ *
+ * --- ()를 rb_link로 찾았다고 했을때.
+ * 1)
+ *
+ * A
+ * / \
+ * B C
+ * / \
+ * D ()
+ * () -> *rb_link
+ * B -> rb_parent, pprev
+ *
+ * 2)
+ *
+ * A
+ * / \
+ * B C
+ * / /\
+ * D () ..
+ *
+ * () -> *rb_link
+ * C -> rb_parent
+ * A -> pprev
+ */
static int find_vma_links(struct mm_struct *mm, unsigned long addr,
unsigned long end, struct vm_area_struct **pprev,
struct rb_node ***rb_link, struct rb_node **rb_parent)
@@ -542,12 +579,21 @@ static int find_vma_links(struct mm_struct *mm, unsigned long addr,
__rb_parent = *__rb_link;
vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb);
+/*
+ * IAMROOT, 2022.05.21:
+ * - 요청 영역과 겹치는 vma가 있으면 error.
+ */
if (vma_tmp->vm_end > addr) {
/* Fail if an existing vma overlaps the area */
if (vma_tmp->vm_start < end)
return -ENOMEM;
__rb_link = &__rb_parent->rb_left;
} else {
+/*
+ * IAMROOT, 2022.05.21:
+ * - rb_tree에서 right측을 이동하게되는 마지막 pnode가 새로 생길
+ * leaf node의 before value node가 된다.
+ */
rb_prev = __rb_parent;
__rb_link = &__rb_parent->rb_right;
}
@@ -593,12 +639,21 @@ static inline struct vm_area_struct *vma_next(struct mm_struct *mm,
*
* Returns: -ENOMEM on munmap failure or 0 on success.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - start에서 len만큼의 공간에 대한 vma를 할당할수있는지 확인한다.
+ * 영역에 vma가 존재하면 모두 unmap후 제거한다.
+ */
static inline int
munmap_vma_range(struct mm_struct *mm, unsigned long start, unsigned long len,
struct vm_area_struct **pprev, struct rb_node ***link,
struct rb_node **parent, struct list_head *uf)
{
-
+/*
+ * IAMROOT, 2022.05.21:
+ * - vma가 겹친경우 do_munmap을 시도한다. 겹친 vma가 여러개일 경우 여러번
+ * 시도될수있다.
+ */
while (find_vma_links(mm, start, start + len, pprev, link, parent))
if (do_munmap(mm, start, len, uf))
return -ENOMEM;
@@ -1467,6 +1522,10 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
* to. we assume access permissions have been handled by the open
* of the memory object, so we don't do any here.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - prot, flags를 vm_flags로 변환하여 추가한다.
+ */
vm_flags = calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
@@ -1547,6 +1606,11 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
pgoff = 0;
vm_flags |= VM_SHARED | VM_MAYSHARE;
break;
+/*
+ * IAMROOT, 2022.05.21:
+ * - anon page
+ * MAP_PRIVATE|MAP_ANONYMOUS
+ */
case MAP_PRIVATE:
/*
* Set pgoff according to addr for anon_vma.
@@ -1580,6 +1644,12 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
return addr;
}
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - user에서 호출한 malloc인 경우 if문 해당사항이 없어(file이 아닌경우)
+ * vm_mmap_pgoff를 바로 호출할것이다.
+ */
unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
@@ -1738,6 +1808,10 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
return -ENOMEM;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - 영역내에 있는 vma들을 unmap후 해제 한다.
+ */
/* Clear old maps, set up prev, rb_link, rb_parent, and uf */
if (munmap_vma_range(mm, addr, len, &prev, &rb_link, &rb_parent, uf))
return -ENOMEM;
@@ -1889,6 +1963,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
return error;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * @return 찾은 빈공간의 align적용된 시작 주소. or error
+ * - 이진탐색으로 low_limit ~ high_limit 범위내에 vma들 사이에서
+ * gap(prev vma ~ current vma 사이의 공간)을 찾는다.
+ */
static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
{
/*
@@ -1904,6 +1984,12 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
unsigned long length, low_limit, high_limit, gap_start, gap_end;
/* Adjust search length to account for worst case alignment overhead */
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - info->align_mask
+ * length보다 크게(align에 맞춰서) 할당하겠다는것.
+ */
length = info->length + info->align_mask;
if (length < info->length)
return -ENOMEM;
@@ -1924,9 +2010,31 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
if (vma->rb_subtree_gap < length)
goto check_highest;
+/*
+ * IAMROOT, 2022.05.21:
+ *
+ * A
+ * / \
+ * B C
+ * / \ / \
+ * D E F G
+ *
+ * 1. B,F의 rb_subtree_gap < length, 나머지는 true
+ * 0x00 ULONG_MAX
+ * D B E A F C G
+ * 1 2
+ * ^found
+ * A -> B subtree false -> 1(E_A check) -> C -> F subtree false -> 2(F_C check)
+ */
while (true) {
/* Visit left subtree if it looks promising */
gap_end = vm_start_gap(vma);
+/*
+ * IAMROOT, 2022.05.21:
+ * - left subtree_gap의 공간이 있으면 left로 계속 내려간다.
+ * 단 low_limit 밑으로 내려가지 못한다.
+ *
+ */
if (gap_end >= low_limit && vma->vm_rb.rb_left) {
struct vm_area_struct *left =
rb_entry(vma->vm_rb.rb_left,
@@ -1942,11 +2050,21 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
/* Check if current node has a suitable gap */
if (gap_start > high_limit)
return -ENOMEM;
+/*
+ * IAMROOT, 2022.05.21:
+ * - current vma와 prev vma 사이에 gap이 충분한지 검사한다.
+ * 공간이 충분하면 found.
+ */
if (gap_end >= low_limit &&
gap_end > gap_start && gap_end - gap_start >= length)
goto found;
/* Visit right subtree if it looks promising */
+/*
+ * IAMROOT, 2022.05.21:
+ * - left에 gap이 없었다는것은 right tree쪽에 gap이 있을수도있다.
+ * right 이동이 가능하면 right로 이동한다.
+ */
if (vma->vm_rb.rb_right) {
struct vm_area_struct *right =
rb_entry(vma->vm_rb.rb_right,
@@ -1957,6 +2075,11 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
}
}
+/*
+ * IAMROOT, 2022.05.21:
+ * - left, right에서 gap을 못찾앗으므로 parent로 올라가고
+ * check_current로 goto한다. 올라간 parent 기준으로 검사를 수행한다.
+ */
/* Go back up the rbtree to find next candidate node */
while (true) {
struct rb_node *prev = &vma->vm_rb;
@@ -1974,8 +2097,17 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
check_highest:
/* Check highest gap, which does not precede any rbtree node */
+/*
+ * IAMROOT, 2022.05.21:
+ * - 범위내에서 못찾았다면 highest로 cache되잇는걸 start로 잡는다.
+ * 가장 높은 주소에 있는 빈공간이니 end도 끝점이될것이다.
+ */
gap_start = mm->highest_vm_end;
gap_end = ULONG_MAX; /* Only for VM_BUG_ON below */
+/*
+ * IAMROOT, 2022.05.21:
+ * - 가장 끝에 있는데 high_limit을 넘어서면 범위초과이므로 fail
+ */
if (gap_start > high_limit)
return -ENOMEM;
@@ -2100,6 +2232,11 @@ static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
* - is at least the desired size.
* - satisfies (begin_addr & align_mask) == (align_offset & align_mask)
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * @info에서 요청한 범위에서 vma를 할당할수있는 빈 공간 시작주소를
+ * 얻어온다.
+ */
unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info)
{
unsigned long addr;
@@ -2133,6 +2270,10 @@ unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info)
* This function "knows" that -ENOMEM has the bits set.
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
+/*
+ * IAMROOT, 2022.05.21:
+ * - 요청 인자에 따라 vma를 할당할 addr를 구해온다.
+ */
unsigned long
arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -2145,12 +2286,46 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (len > mmap_end - mmap_min_addr)
return -ENOMEM;
+/*
+ * IAMROOT, 2022.05.21:
+ * - MAP_FIXED면 검색도 안하고 그냥 들어온 인자로 결정된다.
+ */
if (flags & MAP_FIXED)
return addr;
if (addr) {
addr = PAGE_ALIGN(addr);
vma = find_vma_prev(mm, addr, &prev);
+/*
+ * IAMROOT, 2022.05.21:
+ * - find_vma_prev를 통해서 즉시 vma가 할당이 안된 빈 공간을 찾을수있는
+ * 지 확인한다.
+ * - addr은 유효범위 이지만 vma를 못찾앗거나 찾아온 vma가 vm범위를 넘고.
+ * prev가 없거나 addr이 vm_end_gap 이상이면 return addr.
+ *
+ * ---
+ *
+ * addr(vma안에 있을수있고, prev ~ vma 사이에 있을수도있음)
+ * v
+ * +-------+
+ * v v
+ * | prev | | vma |
+ * ^----^
+ * 이 공간안에 len이 충분한지 확인한다.
+ *
+ * ---
+ * - mmap_end - len >= addr && addr >= mmap_min_addr
+ * mmap공간내에 addr이 유효한지만 판단.
+ *
+ * - prev, vma가 둘다 있다고 가정하면, prev, vma 사이에 gap이 충분한지
+ * 확인한다.
+ *
+ * - prev == NULL, vma == NULL
+ * memory에 vma에 하나도 없는경우 이므로 어디에나 할당가능
+ *
+ * - prev != NULL, vma == NULL
+ * addr측에 존재하는 vma가 없다
+ */
if (mmap_end - len >= addr && addr >= mmap_min_addr &&
(!vma || addr + len <= vm_start_gap(vma)) &&
(!prev || addr >= vm_end_gap(prev)))
@@ -2225,6 +2400,10 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
}
#endif
+/*
+ * IAMROOT, 2022.05.21:
+ * - 인자에 따라 vma를 할당할 주소를 return한다.
+ */
unsigned long
get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
@@ -2240,6 +2419,13 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
if (len > TASK_SIZE)
return -ENOMEM;
+/*
+ * IAMROOT, 2022.05.21:
+ * - file인 경우 f_op에 되있는걸 사용하고, shared인경우엔 shmem_get_unmapped_area를
+ * 사용한다. 그 외의 경우엔 current->mm->get_unmapped_area를 사용하며,
+ * 아마 함수는 arch_get_unmapped_area일 것이다.
+ * (setup_new_exec(), arch_pick_mmap_layout() 참고)
+ */
get_area = current->mm->get_unmapped_area;
if (file) {
if (file->f_op->get_unmapped_area)
@@ -2270,6 +2456,26 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
EXPORT_SYMBOL(get_unmapped_area);
/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
+/*
+ * IAMROOT, 2022.05.21:
+ * @return 1. cache에서 바로 찾아지면 경우
+ * 2. rbtree에서 찾아진경우
+ * 3. rbtree에서 못찾은 경우
+ * 3-1 addr보다 큰 vm_end를 가진것들중에서 가장 addr에 가까운 vm_end값을
+ * 가진 vma
+ * 3-2 addr보다 큰 vm_end를 가진 vma가 없으면 NULL
+ *
+ * - cache에서 먼저 찾아보고 아니면 rb에서 이진탐색한다.
+ *
+ * ---
+ * A
+ * / \
+ * B C
+ *
+ * .. | B | .. | A | .. | C |
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ * B B B A A A A C C C C NULL <-return
+ */
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
struct rb_node *rb_node;
@@ -2289,7 +2495,16 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
if (tmp->vm_end > addr) {
+/*
+ * IAMROOT, 2022.05.21:
+ * - addr보다 큰 vm_end를 가진 것들중에서 가장 addr에 가까운 vm_end값을 가진
+ * vma를 고른다.
+ */
vma = tmp;
+/*
+ * IAMROOT, 2022.05.21:
+ * - start <= addr < end 이경우. 즉 addr이 vma에 포함되서 찾아짐.
+ */
if (tmp->vm_start <= addr)
break;
rb_node = rb_node->rb_left;
@@ -2307,6 +2522,25 @@ EXPORT_SYMBOL(find_vma);
/*
* Same as find_vma, but also return a pointer to the previous VMA in *pprev.
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - 1. vma가 찾아진경우
+ * return vma (찾아진 vma)
+ * prev = vma의 prev.
+ * 2. vma가 못찾아진경우
+ * return vma == NULL
+ * prev = last vma or NULL
+ *
+ * ---
+ * A
+ * / \
+ * B C
+ *
+ * .. | B | .. | A | .. | C |
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ * B B B A A A A C C C C NULL <- vma
+ * N N N B B B B A A A A C <- pprev
+ */
struct vm_area_struct *
find_vma_prev(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct **pprev)
@@ -2315,10 +2549,19 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr,
vma = find_vma(mm, addr);
if (vma) {
+/*
+ * IAMROOT, 2022.05.21:
+ * - vma prev를 저장.
+ */
*pprev = vma->vm_prev;
} else {
struct rb_node *rb_node = rb_last(&mm->mm_rb);
+/*
+ * IAMROOT, 2022.05.21:
+ * - last가 있으면 prev는 last를 가져온다. return은 NULL이 된다.
+ */
+
*pprev = rb_node ? rb_entry(rb_node, struct vm_area_struct, vm_rb) : NULL;
}
return vma;
@@ -2540,6 +2783,10 @@ int expand_downwards(struct vm_area_struct *vma,
}
/* enforced gap between the expanding stack and other mappings. */
+/*
+ * IAMROOT, 2022.05.21:
+ * - 1MB
+ */
unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
static int __init cmdline_parse_stack_guard_gap(char *p)
@@ -2793,6 +3040,11 @@ unlock_range(struct vm_area_struct *start, unsigned long limit)
* work. This now handles partial unmappings.
* Jeremy Fitzhardinge <jeremy@goop.org>
*/
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - @start에서 len만큼의 영역에 있는 vma들을 해제한다.(split, unmap, detach, free)
+ */
int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
struct list_head *uf, bool downgrade)
{
@@ -2847,10 +3099,89 @@ int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
/* Does it split the last one? */
last = find_vma(mm, end);
if (last && end > last->vm_start) {
+
+/*
+ * IAMROOT, 2022.05.21:
+ *
+ * 1) vma 한개에 영역이 다 있는 경우
+ *
+ * ----------- vm_end
+ * ^
+ * | ^ ---- end
+ * | |
+ * |vma |
+ * | v ---- start
+ * v
+ * ----------- vm_start
+ *
+ * 이런경우 split가 두번되야될것이다.
+ *
+ * 2) 영역에 vma가 여러 개있는 경우
+ *
+ * ^ ---- vm_end
+ * |
+ * | --- end
+ * | ^
+ * v ---- vm_start |
+ * |
+ * ... ..
+ *
+ * ^ ---- vm_end |
+ * | |
+ * | |
+ * v ---- vm_start |
+ * |
+ * ... ..
+ * |
+ * ^ ---- vm_end |
+ * | v
+ * | --- start
+ * |
+ * v ---- vm_start
+ *
+ * 이경우 start와 겹치는 vma와 end와 겹치는 vma가 각각 splite 될것이다.
+ */
int error = __split_vma(mm, last, end, 1);
if (error)
return error;
}
+
+/*
+ * IAMROOT, 2022.05.21:
+ *
+ * ----------- vm_end
+ * ^
+ * | ^ ---- end
+ * | | |
+ * |vma | | <-- vma
+ * | v ---- start
+ * v | <-- prev
+ * ----------- vm_start
+ *
+ * ----
+ * ^ ---- vm_end
+ * | <- vma4
+ * | --- end
+ * | ^ <- vma3->next = vma4
+ * v ---- vm_start |
+ * |
+ * ... ..
+ *
+ * ^ ---- vm_end |
+ * | |
+ * | | <- vma2->next = vma3
+ * v ---- vm_start |
+ * |
+ * ... ..
+ * |
+ * ^ ---- vm_end |
+ * | v <- vma->next = vma2
+ * | --- start
+ * | <-- prev
+ * v ---- vm_start
+ *
+ * vma부터 ~ vma4까지 unmap될것이다.(unmap_vmas())
+ */
vma = vma_next(mm, prev);
if (unlikely(uf)) {
@@ -2874,6 +3205,10 @@ int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
if (mm->locked_vm)
unlock_range(vma, end);
+/*
+ * IAMROOT, 2022.05.21:
+ * - 영역 내에 있는 vma만 list에서 제외한다.
+ */
/* Detach vmas from rbtree */
if (!detach_vmas_to_be_unmapped(mm, vma, prev, end))
downgrade = false;
@@ -3305,6 +3640,12 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
* Return true if the calling process may expand its vm space by the passed
* number of pages
*/
+/*
+ * IAMROOT, 2022.05.21:
+ * - 가상공간이나 data limit을 초과한 경우 false.
+ * - 단 data limit의 경우 , valgrind를 사용중이거나 ignore 되있는 경우 그냥
+ * true로 한다.
+ */
bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
{
if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
diff --git a/mm/util.c b/mm/util.c
index 463719f072b4..4e11aca574cb 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -520,6 +520,10 @@ unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,
&uf);
mmap_write_unlock(mm);
userfaultfd_unmap_complete(mm, &uf);
+/*
+ * IAMROOT, 2022.05.21:
+ * - populate값이 있으면 mapping을 한다.
+ */
if (populate)
mm_populate(ret, populate);
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 465865412100..6827fdf6c123 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -403,6 +403,11 @@ static int process_measurement(struct file *file, const struct cred *cred,
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - sys_mmap은 mmap이나 malloc을 통해서 들어온다.
+ */
int ima_file_mmap(struct file *file, unsigned long prot)
{
u32 secid;
diff --git a/security/security.c b/security/security.c
index 9ffa9e9c5c55..9c7ee2a55478 100644
--- a/security/security.c
+++ b/security/security.c
@@ -731,6 +731,11 @@ static int lsm_superblock_alloc(struct super_block *sb)
P->hook.FUNC(__VA_ARGS__); \
} while (0)
+
+/*
+ * IAMROOT, 2022.05.21:
+ * - 등록된 security hook 가 있으면 호출한다.
+ */
#define call_int_hook(FUNC, IRC, ...) ({ \
int RC = IRC; \
do { \
@@ -1574,6 +1579,11 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
return prot;
}
+/*
+ * IAMROOT, 2022.05.21:
+ * LSM(linux security model)
+ * - memory 할당시 security callback.
+ */
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 623 |
125 | [커널 18차] 54주차 | kkr | 2022.06.04 | 81 |
124 | [커널 19차] 3주차 | 리턴 | 2022.06.04 | 216 |
123 | [커널 18차] 53주차 | kkr | 2022.05.29 | 93 |
122 | [커널 17차] 91주차 | ㅇㅇㅇ | 2022.05.28 | 64 |
121 | [커널 19차] 2주차 | 리턴 | 2022.05.28 | 169 |
120 | [커널 17차] 90주차 | ㅇㅇㅇ | 2022.05.22 | 149 |
» | [커널 18차] 52주차 | kkr | 2022.05.21 | 123 |
118 | [커널 19차] 1주차 | 리턴 | 2022.05.16 | 455 |
117 | [커널 17차] 89주차 | ㅇㅇㅇ | 2022.05.15 | 63 |
116 | [커널 18차] 51주차 | kkr | 2022.05.14 | 159 |
115 | [커널 18차] 50주차 | kkr | 2022.05.10 | 204 |
114 | [커널 17차] 88주차 | ㅇㅇㅇ | 2022.05.08 | 101 |
113 | [커널 19차] 0주차 - 오리엔테이션 | 리턴 | 2022.05.07 | 598 |
112 | [커널 17차] 86~87주차 | ㅇㅇㅇ | 2022.04.30 | 101 |
111 | [커널 17차] 84~85주차 | JSYoo5B | 2022.04.16 | 86 |
110 | [커널 17차] 83주차 | ㅇㅇㅇ | 2022.04.03 | 92 |
109 | [커널 17차] 82주차 | ㅇㅇㅇ | 2022.03.27 | 65 |
108 | [커널 17차] 81주차 | ㅇㅇㅇ | 2022.03.19 | 131 |
107 | [커널 17차] 77 ~ 80주차 | ㅇㅇㅇ | 2022.03.13 | 102 |
106 | [커널 17차] 76주차 [1] | ㅇㅇㅇ | 2022.02.19 | 139 |
.