๏ปฟ# mremap ๐
๊ด๋ จ ์์ค:mm/mremap.c,mm/internal.h,include/uapi/linux/mman.h
๊ฐ์ (Overview)
mremap()๋ ๊ธฐ์กด ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ(VMA)์ ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋ค๋ฅธ ๊ฐ์ ์ฃผ์๋ก ์ด๋ํ๋ ์์คํ ํธ์ถ์ ๋๋ค. ์ด ์์คํ ํธ์ถ์ ๋ฉ๋ชจ๋ฆฌ ๋งคํ์ ํ์ฅ, ์ถ์, ์ด๋์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ฉฐ, ๋ฆฌ๋ ์ค ์ปค๋์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์๋ธ์์คํ ์์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
์ผ์ ๋น์ : mremap()๋ ์ํํธ๋ฅผ ๋ฆฌ๋ชจ๋ธ๋งํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. ๋ฐฉ์ ํฌ๊ธฐ๋ฅผ ํค์ฐ๊ฑฐ๋(ํ์ฅ), ์ค์ด๊ฑฐ๋(์ถ์), ์์ ๋ค๋ฅธ ์ธต์ผ๋ก ์ฎ๊ธฐ๋(์ด๋) ๊ฒ๊ณผ ๋น์ทํฉ๋๋ค. ์ปค๋์ ์ด ์์ ์ ์ํํ ๋ ํ์ด์ง ํ ์ด๋ธ์ ์กฐ์ ํ์ฌ ํ๋ก์ธ์ค๊ฐ ๊ณ์ํด์ ๋์ผํ ๊ฐ์ ์ฃผ์๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
mremap()๋ ์ธ ๊ฐ์ง ๊ธฐ๋ณธ ์ฐ์ฐ์ ์ง์ํฉ๋๋ค: in-place ํ์ฅ(in-place expansion), in-place ์ถ์(in-place shrinking), ๊ทธ๋ฆฌ๊ณ VMA ์ด๋(VMA moving). ๊ฐ ์ฐ์ฐ์ ์๋ก ๋ค๋ฅธ ์๋๋ฆฌ์ค์์ ์ฌ์ฉ๋๋ฉฐ, ์ปค๋์ ์ต์ ์ ๋ฐฉ๋ฒ์ ์๋์ผ๋ก ์ ํํฉ๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก:
mm/mremap.c # ๋ฉ์ธ ๊ตฌํ (1998์ค)
mm/internal.h # pagetable_move_control ๊ตฌ์กฐ์ฒด ์ ์
include/uapi/linux/mman.h # MREMAP ํ๋๊ทธ ์ ์
mremap ํธ์ถ ํ๋ฆ
mremap ํต์ฌ ์๋ฃ๊ตฌ์กฐ ๊ด๊ณ๋
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# 1. mremap ์์คํ
ํธ์ถ ํธ์ถ ํ์ ํ์ธ
cat /proc/kstat | grep mremap
# 2. ํ์ฌ ํ๋ก์ธ์ค์ VMA ๋งต ํ์ธ
cat /proc/self/maps | head -20
# 3. mremap ๊ด๋ จ ์ปค๋ ํต๊ณ ํ์ธ
cat /proc/vmstat | grep -i mremap
# 4. mremap ์คํจ ํ์ ํ์ธ (dmesg์์)
dmesg | grep -i "mremap" | tail -10
# 5. ํน์ ํ๋ก์ธ์ค์ VMA ๋ณ๊ฒฝ ์ถ์
strace -e mremap <ํ๋ก์ธ์ค๋ช
>
# 6. mremap ํ๋๊ทธ ํ์ธ
grep -r "MREMAP_" /usr/include/linux/mman.h
# 7. ์ปค๋ mremap ๊ด๋ จ ๋ชจ๋ ํ์ธ
lsmod | grep -i mremap
# 8. mremap ๊ด๋ จ ์ปค๋ ํ๋ผ๋ฏธํฐ ํ์ธ
sysctl -a | grep -i mremap
# 9. mremap ํธ์ถ ์ VMA ๋ณ๊ฒฝ ์ถ์
perf trace -e mremap <ํ๋ก์ธ์ค๋ช
>
# 10. mremap ๊ด๋ จ ์ปค๋ ๋ก๊ทธ ํ์ธ
journalctl -k | grep -i mremap
# 11. VMA ๋งต ์ ํ์ธ (mremap ์คํจ ์์ธ ์ง๋จ)
cat /proc/self/status | grep -i vmsize
# 12. ๋ฉ๋ชจ๋ฆฌ ๋งคํ ํต๊ณ ํ์ธ
cat /proc/vmstat | grep -i mmap
# 13. ํ์ด์ง ํ
์ด๋ธ ํต๊ณ ํ์ธ
cat /proc/vmstat | grep -i pte
# 14. TLB ํ๋ฌ์ ํต๊ณ ํ์ธ
cat /proc/vmstat | grep -i tlb
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
1. vma_remap_struct
mremap() ์ฐ์ฐ ์ ์ฒด๋ฅผ ์ค๋ช ํ๋ ๋ฉ์ธ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
/* mm/mremap.c:50-73 */
struct vma_remap_struct {
/* ์ฌ์ฉ์ ์ ๊ณต ์ํ */
unsigned long addr; /* ๋ฆฌ๋งคํํ ์๋ณธ ๊ฐ์ ์ฃผ์ */
unsigned long old_len; /* ๋ฆฌ๋งคํํ ๋ฒ์์ ๊ธฐ์กด ๊ธธ์ด */
unsigned long new_len; /* ์ํ๋ ์ ๊ธธ์ด */
const unsigned long flags; /* MREMAP_* ํ๋๊ทธ */
unsigned long new_addr; /* ์ ํ์ ์ ์ฃผ์ */
/* uffd ์ํ */
struct vm_userfaultfd_ctx *uf;
struct list_head *uf_unmap_early;
struct list_head *uf_unmap;
/* VMA ์ํ - do_mremap()์์ ๊ฒฐ์ */
struct vm_area_struct *vma;
/* ๋ด๋ถ ์ํ - do_mremap()์์ ๊ฒฐ์ */
unsigned long delta; /* old_len๊ณผ new_len์ ์ ๋ ์ฐจ์ด */
bool populate_expand; /* mlock()๋ ํ์ฅ ์์ญ, populate ํ์ */
enum mremap_type remap_type; /* expand, shrink ๋ฑ */
bool mmap_locked; /* ํ์ฌ mm์ด ์ฐ๊ธฐ ์ ๊ธ ์ํ์ธ์ง */
unsigned long charged; /* VM_ACCOUNT์ธ ๊ฒฝ์ฐ, ์ฒญ๊ตฌํ ํ์ด์ง ์ */
bool vmi_needs_invalidate; /* VMA ๋ฐ๋ณต์๊ฐ ๋ฌดํจํ๋์๋์ง */
};
2. pagetable_move_control
ํ์ด์ง ํ ์ด๋ธ ์ด๋ ์ฐ์ฐ์ ์ ์ดํ๋ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
/* mm/internal.h:46-56 */
struct pagetable_move_control {
struct vm_area_struct *old; /* ์์ค VMA */
struct vm_area_struct *new; /* ๋์ VMA */
unsigned long old_addr; /* ์ด๋์ด ์์๋๋ ์ฃผ์ */
unsigned long old_end; /* ๊ธฐ์กด ๋ฒ์๊ฐ ๋๋๋ ์ฃผ์ (ํฌํจ๋์ง ์์) */
unsigned long new_addr; /* ํ์ด์ง ํ
์ด๋ธ์ ์ด๋ํ ์ฃผ์ */
unsigned long len_in; /* ์ฌ์ฉ์๊ฐ ์ง์ ํ ๋ฆฌ๋งคํํ ๋ฐ์ดํธ ์ */
bool need_rmap_locks; /* rmap ์ ๊ธ์ด ํ์ํ์ง */
bool for_stack; /* ์ด๊ธฐ ์์ ์คํ์ ์ด๋ ์ค์ธ์ง */
};
/* PAGETABLE_MOVE ๋งคํฌ๋ก๋ก ์ด๊ธฐํ */
/* mm/internal.h:58-66 */
#define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_) \
struct pagetable_move_control name = { \
.old = old_, \
.new = new_, \
.old_addr = old_addr_, \
.old_end = (old_addr_) + (len_), \
.new_addr = new_addr_, \
.len_in = len_, \
}
3. mremap_type ์ด๊ฑฐํ
๋ฆฌ๋งคํ ์ฐ์ฐ ์ ํ์ ๋ถ๋ฅํฉ๋๋ค.
/* mm/mremap.c:36-41 */
enum mremap_type {
MREMAP_INVALID, /* ์ด๊ธฐ ์ํ */
MREMAP_NO_RESIZE, /* old_len == new_len, ์ด๋ํ์ง ์์ผ๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์์ */
MREMAP_SHRINK, /* old_len > new_len */
MREMAP_EXPAND, /* old_len < new_len */
};
4. MREMAP ํ๋๊ทธ
/* include/uapi/linux/mman.h:9-11 */
#define MREMAP_MAYMOVE 1 /* ์ด๋ ํ์ฉ */
#define MREMAP_FIXED 2 /* ๊ณ ์ ์ฃผ์๋ก ์ด๋ */
#define MREMAP_DONTUNMAP 4 /* ์๋ณธ ๋งคํ ์ ์ง (๋ณต์ฌ ํ ์ด๋) */
MREMAP_MAYMOVE: mremap๊ฐ ์ ์ฃผ์์์ ๋งคํ์ ํ์ฉํฉ๋๋ค. in-place ํ์ฅ/์ถ์๊ฐ ๋ถ๊ฐ๋ฅํ ๋ ์ด๋์ด ํ์ํฉ๋๋ค.
MREMAP_FIXED: ์ง์ ๋ ์ฃผ์(new_addr)๋ก ์ด๋ํฉ๋๋ค. ๊ธฐ์กด ๋งคํ์ด ์์ผ๋ฉด ๋จผ์ ์ ๊ฑฐ๋ฉ๋๋ค. MREMAP_MAYMOVE๊ฐ ํจ๊ป ์ค์ ๋์ด์ผ ํฉ๋๋ค.
MREMAP_DONTUNMAP: ์๋ณธ ๋งคํ์ ์ ์งํ๋ฉด์ ์ ์์น์ ๋ณต์ฌํฉ๋๋ค. ํ๋ก์ธ์ค ๊ฐ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ์ ์ฌ์ฉ๋ฉ๋๋ค.
ํต์ฌ ํจ์
1. SYSCALL_DEFINE5(mremap)
mremap() ์์คํ ํธ์ถ์ ์ง์ ์ ์ ๋๋ค.
/* mm/mremap.c:1965-1998 */
SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
unsigned long, new_len, unsigned long, flags,
unsigned long, new_addr)
{
struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
LIST_HEAD(uf_unmap_early);
LIST_HEAD(uf_unmap);
struct vma_remap_struct vrm = {
.addr = untagged_addr(addr), /* ARM64 ํ๊ทธ ์ ๊ฑฐ */
.old_len = old_len,
.new_len = new_len,
.flags = flags,
.new_addr = new_addr,
.uf = &uf,
.uf_unmap_early = &uf_unmap_early,
.uf_unmap = &uf_unmap,
.remap_type = MREMAP_INVALID,
};
return do_mremap(&vrm);
}
์ญํ : ์ฌ์ฉ์ ๊ณต๊ฐ์์ ์ ๋ฌ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฒ์ฆํ๊ณ vma_remap_struct๋ฅผ ์ด๊ธฐํํ ํ do_mremap()๋ฅผ ํธ์ถํฉ๋๋ค. ARM64 ํ๊ทธ ์ฃผ์ ์ฒ๋ฆฌ๋ฅผ ์ํด untagged_addr()์ ์ฌ์ฉํฉ๋๋ค.
2. do_mremap
mremap์ ๋ฉ์ธ ๋ก์ง์ ์ํํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1915-1956 */
static unsigned long do_mremap(struct vma_remap_struct *vrm)
{
struct mm_struct *mm = current->mm;
unsigned long res;
bool failed;
/* ๊ธธ์ด๋ฅผ ํ์ด์ง ํฌ๊ธฐ์ ์ ๋ ฌ */
vrm->old_len = PAGE_ALIGN(vrm->old_len);
vrm->new_len = PAGE_ALIGN(vrm->new_len);
/* ํ๋ผ๋ฏธํฐ ๊ฒ์ฆ */
res = check_mremap_params(vrm);
if (res)
return res;
/* mmap ์ฐ๊ธฐ ์ ๊ธ ํ๋ */
if (mmap_write_lock_killable(mm))
return -EINTR;
vrm->mmap_locked = true;
/* ์ด๋๋ง ํ๋ ๊ฒฝ์ฐ */
if (vrm_move_only(vrm)) {
res = remap_move(vrm);
} else {
/* VMA ์กฐํ ๋ฐ ๊ฒ์ฆ */
vrm->vma = vma_lookup(current->mm, vrm->addr);
res = check_prep_vma(vrm);
if (res)
goto out;
/* mremap ์คํ */
res = vrm_implies_new_addr(vrm) ? mremap_to(vrm) : mremap_at(vrm);
}
out:
failed = IS_ERR_VALUE(res);
if (vrm->mmap_locked)
mmap_write_unlock(mm);
/* mlock๋ ํ์ฅ ์์ญ populate */
if (!failed && vrm->populate_expand)
mm_populate(vrm->new_addr + vrm->old_len, vrm->delta);
/* userfaultfd ์๋ฆผ */
notify_uffd(vrm, failed);
return res;
}
์ญํ : ํ์ด์ง ์ ๋ ฌ๋ ๊ธธ์ด๋ฅผ ๊ณ์ฐํ๊ณ , ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฒ์ฆํ ํ, mmap ์ ๊ธ์ ํ๋ํฉ๋๋ค. ๊ทธ ๋ค์ ์ด๋ ์ ์ฉ ๊ฒฝ๋ก ๋๋ ์ผ๋ฐ ๊ฒฝ๋ก๋ฅผ ์ ํํ์ฌ ์คํํฉ๋๋ค.
3. check_mremap_params
mremap ํ๋ผ๋ฏธํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1756-1824 */
static unsigned long check_mremap_params(struct vma_remap_struct *vrm)
{
unsigned long addr = vrm->addr;
unsigned long flags = vrm->flags;
/* ์์์น ๋ชปํ ํ๋๊ทธ ๊ฐ ๋ฐฉ์ง */
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP))
return -EINVAL;
/* ์์ ์ฃผ์๋ ํ์ด์ง ์ ๋ ฌ์ด์ผ ํจ */
if (offset_in_page(addr))
return -EINVAL;
/* new_len์ด 0์ด๋ฉด ์๋จ */
if (!vrm->new_len)
return -EINVAL;
/* new_len์ด TASK_SIZE๋ฅผ ์ด๊ณผํ๋ฉด ์๋จ */
if (vrm->new_len > TASK_SIZE)
return -EINVAL;
/* ๊ณ ์ ์ฃผ์ ์ง์ ์ ์ถ๊ฐ ๊ฒ์ฆ */
if (!vrm_implies_new_addr(vrm))
return 0;
/* new_addr์ด TASK_SIZE - new_len์ ์ด๊ณผํ๋ฉด ์๋จ */
if (vrm->new_addr > TASK_SIZE - vrm->new_len)
return -EINVAL;
/* new_addr์ ํ์ด์ง ์ ๋ ฌ์ด์ผ ํจ */
if (offset_in_page(vrm->new_addr))
return -EINVAL;
/* ๊ณ ์ ์ฃผ์๋ MREMAP_MAYMOVE ํ์ */
if (!(flags & MREMAP_MAYMOVE))
return -EINVAL;
/* MREMAP_DONTUNMAP์ ํฌ๊ธฐ ๋ณ๊ฒฝ ๋ถ๊ฐ */
if (flags & MREMAP_DONTUNMAP && vrm->old_len != vrm->new_len)
return -EINVAL;
/* ๋์ VMA์ ์์ค VMA๊ฐ ๊ฒน์น๋ฉด ์๋จ */
if (vrm_overlaps(vrm))
return -EINVAL;
/* VMA ๋งต ์ ์ ํ ํ์ธ */
if ((current->mm->map_count + 2) >= sysctl_max_map_count - 3)
return -ENOMEM;
return 0;
}
์ญํ : ํ๋๊ทธ ์ ํจ์ฑ, ์ฃผ์ ์ ๋ ฌ, ํฌ๊ธฐ ์ ํ, VMA ๊ฒน์นจ ๋ฑ์ ๊ฒ์ฆํฉ๋๋ค.
4. check_prep_vma
VMA ์ด๋ ์ ์ค๋น ๊ฒ์ฆ์ ์ํํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1655-1750 */
static int check_prep_vma(struct vma_remap_struct *vrm)
{
struct vm_area_struct *vma = vrm->vma;
struct mm_struct *mm = current->mm;
unsigned long addr = vrm->addr;
unsigned long old_len, new_len, pgoff;
if (!vma)
return -EFAULT;
/* mseal()๋ VMA๋ mremap ๋ถ๊ฐ */
if (vma_is_sealed(vma))
return -EPERM;
/* HugeTLB ํ์ด์ง๋ ์ ๋ ฌ ํ์ */
if (is_vm_hugetlb_page(vma) && !align_hugetlb(vrm))
return -EINVAL;
vrm_set_delta(vrm);
vrm->remap_type = vrm_remap_type(vrm);
/* ์ ์ฃผ์๊ฐ ํ์ํ ๊ฒฝ์ฐ */
if (!vrm_implies_new_addr(vrm))
vrm->new_addr = addr;
if (!vrm_will_map_new(vrm))
return 0;
old_len = vrm->old_len;
new_len = vrm->new_len;
/* ๋น๊ณต์ ๋งคํ์ ๊ฒฝ์ฐ old_len=0 ํ์ฉ ์๋จ */
if (!old_len && !(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) {
pr_warn_once("%s (%d): attempted to duplicate a private mapping with mremap. This is not supported.\n",
current->comm, current->pid);
return -EINVAL;
}
/* MREMAP_DONTUNMAP์ VM_DONTEXPAND/VM_PFNMAP ๋ถ๊ฐ */
if ((vrm->flags & MREMAP_DONTUNMAP) &&
(vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)))
return -EINVAL;
/* ์ถ์ ์ old_len ์กฐ์ */
if (vrm->remap_type == MREMAP_SHRINK)
old_len = new_len;
/* old_len์ด VMA ๋ฒ์๋ฅผ ์ด๊ณผํ๋ฉด ์๋จ */
if (old_len > vma->vm_end - addr)
return -EFAULT;
if (new_len == old_len)
return 0;
/* mlock๋ VMA ํ์ฅ ์ populate ํ์ */
if (vma->vm_flags & VM_LOCKED)
vrm->populate_expand = true;
/* ํ์ด์ง ์ค๋ฒํ๋ก์ฐ ๊ฒ์ฌ */
pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
pgoff += vma->vm_pgoff;
if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
return -EINVAL;
/* VM_DONTEXPAND/VM_PFNMAP๋ ํ์ฅ ๋ถ๊ฐ */
if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
return -EFAULT;
if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, vrm->delta))
return -EAGAIN;
if (!may_expand_vm(mm, vma->vm_flags, vrm->delta >> PAGE_SHIFT))
return -ENOMEM;
return 0;
}
์ญํ : VMA ์ํ, mseal, HugeTLB ์ ๋ ฌ, ํ์ฅ ๊ฐ๋ฅ์ฑ์ ๊ฒ์ฆํฉ๋๋ค.
5. move_vma
VMA๋ฅผ ์ ์์น๋ก ์ด๋ํ๋ ํต์ฌ ํจ์์ ๋๋ค.
/* mm/mremap.c:1270-1321 */
static unsigned long move_vma(struct vma_remap_struct *vrm)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *new_vma;
unsigned long hiwater_vm;
int err;
/* ์ด๋ ์ ์ค๋น */
err = prep_move_vma(vrm);
if (err)
return err;
/* ๊ณ์ ์ฒ๋ฆฌ */
if (!vrm_calc_charge(vrm))
return -ENOMEM;
/* VMA ์ฐ๊ธฐ ์ ๊ธ ํ๋ */
vma_start_write(vrm->vma);
/* ๋ณต์ฌ ๋จ๊ณ ์ํ */
err = copy_vma_and_data(vrm, &new_vma);
if (err && !new_vma)
return err;
/* ํต๊ณ ๊ณ์ */
hiwater_vm = mm->hiwater_vm;
vrm_stat_account(vrm, vrm->new_len);
/* ์๋ณธ VMA ์ฒ๋ฆฌ */
if (unlikely(!err && (vrm->flags & MREMAP_DONTUNMAP)))
dontunmap_complete(vrm, new_vma);
else
unmap_source_vma(vrm);
mm->hiwater_vm = hiwater_vm;
return err ? (unsigned long)err : vrm->new_addr;
}
์ญํ : VMA๋ฅผ ์ ์์น๋ก ๋ณต์ฌํ๊ณ , ํ์ด์ง ํ ์ด๋ธ์ ์ด๋ํ ํ, ์๋ณธ VMA๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. MREMAP_DONTUNMAP ํ๋๊ทธ๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ ์๋ณธ์ ์ ์งํฉ๋๋ค.
6. move_page_tables
ํ์ด์ง ํ ์ด๋ธ์ ์ค์ ์ด๋ํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:795-879 */
unsigned long move_page_tables(struct pagetable_move_control *pmc)
{
unsigned long extent;
struct mmu_notifier_range range;
pmd_t *old_pmd, *new_pmd;
pud_t *old_pud, *new_pud;
struct mm_struct *mm = pmc->old->vm_mm;
if (!pmc->len_in)
return 0;
/* HugeTLB ํ์ด์ง์ ๊ฒฝ์ฐ ๋ณ๋ ์ฒ๋ฆฌ */
if (is_vm_hugetlb_page(pmc->old))
return move_hugetlb_page_tables(pmc->old, pmc->new, pmc->old_addr,
pmc->new_addr, pmc->len_in);
/* PMD ๊ฒฝ๊ณ์ ์ ๋ ฌํ์ฌ ์ฑ๋ฅ ํฅ์ */
try_realign_addr(pmc, PMD_MASK);
/* ์บ์ ํ๋ฌ์ ๋ฐ MMU ์๋ฆผ ์์ */
flush_cache_range(pmc->old, pmc->old_addr, pmc->old_end);
mmu_notifier_range_init(&range, MMU_NOTIFY_UNMAP, 0, mm,
pmc->old_addr, pmc->old_end);
mmu_notifier_invalidate_range_start(&range);
/* ํ์ด์ง ํ
์ด๋ธ ์ํ ๋ฐ ์ด๋ */
for (; !pmc_done(pmc); pmc_next(pmc, extent)) {
cond_resched();
/* PUD ๋ ๋ฒจ ์ด๋ ์๋ */
extent = get_extent(NORMAL_PUD, pmc);
old_pud = get_old_pud(mm, pmc->old_addr);
if (!old_pud)
continue;
new_pud = alloc_new_pud(mm, pmc->new_addr);
if (!new_pud)
break;
/* Huge PUD ์ด๋ */
if (pud_trans_huge(*old_pud)) {
if (extent == HPAGE_PUD_SIZE) {
move_pgt_entry(pmc, HPAGE_PUD, old_pud, new_pud);
continue;
}
} else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) {
if (move_pgt_entry(pmc, NORMAL_PUD, old_pud, new_pud))
continue;
}
/* PMD ๋ ๋ฒจ ์ด๋ ์๋ */
extent = get_extent(NORMAL_PMD, pmc);
old_pmd = get_old_pmd(mm, pmc->old_addr);
if (!old_pmd)
continue;
new_pmd = alloc_new_pmd(mm, pmc->new_addr);
if (!new_pmd)
break;
/* Huge PMD ์ด๋ */
if (pmd_is_huge(*old_pmd)) {
if (extent == HPAGE_PMD_SIZE &&
move_pgt_entry(pmc, HPAGE_PMD, old_pmd, new_pmd))
continue;
split_huge_pmd(pmc->old, old_pmd, pmc->old_addr);
} else if (IS_ENABLED(CONFIG_HAVE_MOVE_PMD) && extent == PMD_SIZE) {
if (move_pgt_entry(pmc, NORMAL_PMD, old_pmd, new_pmd))
continue;
}
/* PTE ๋ ๋ฒจ ์ด๋ */
if (pmd_none(*old_pmd))
continue;
if (pte_alloc(pmc->new->vm_mm, new_pmd))
break;
if (move_ptes(pmc, extent, old_pmd, new_pmd) < 0)
goto again;
}
mmu_notifier_invalidate_range_end(&range);
return pmc_progress(pmc);
}
์ญํ : ํ์ด์ง ํ ์ด๋ธ ๊ณ์ธต(PUDโPMDโPTE)์ ์ํํ๋ฉด์ ๊ฐ ์ํธ๋ฆฌ๋ฅผ ์ ์์น๋ก ์ด๋ํฉ๋๋ค. Huge ํ์ด์ง์ ์ผ๋ฐ ํ์ด์ง๋ฅผ ๊ตฌ๋ถํ์ฌ ์ฒ๋ฆฌํ๋ฉฐ, rmap ์ ๊ธ์ ๊ด๋ฆฌํฉ๋๋ค.
7. move_ptes
๊ฐ๋ณ PTE๋ฅผ ์ด๋ํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:197-319 */
static int move_ptes(struct pagetable_move_control *pmc,
unsigned long extent, pmd_t *old_pmd, pmd_t *new_pmd)
{
struct vm_area_struct *vma = pmc->old;
bool need_clear_uffd_wp = vma_has_uffd_without_event_remap(vma);
struct mm_struct *mm = vma->vm_mm;
pte_t *old_ptep, *new_ptep;
pte_t old_pte, pte;
pmd_t dummy_pmdval;
spinlock_t *old_ptl, *new_ptl;
bool force_flush = false;
unsigned long old_addr = pmc->old_addr;
unsigned long new_addr = pmc->new_addr;
unsigned long old_end = old_addr + extent;
unsigned long len = old_end - old_addr;
int max_nr_ptes;
int nr_ptes;
int err = 0;
/* rmap ์ ๊ธ ํ์์ ํ๋ */
if (pmc->need_rmap_locks)
take_rmap_locks(vma);
/* ์์ค PTE ์ ๊ธ */
old_ptep = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
if (!old_ptep) {
err = -EAGAIN;
goto out;
}
/* ๋์ PTE ๋งคํ */
new_ptep = pte_offset_map_rw_nolock(mm, new_pmd, new_addr, &dummy_pmdval,
&new_ptl);
if (!new_ptep) {
pte_unmap_unlock(old_ptep, old_ptl);
err = -EAGAIN;
goto out;
}
/* ์ค์ฒฉ ์ ๊ธ ์ฒ๋ฆฌ */
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
flush_tlb_batched_pending(vma->vm_mm);
lazy_mmu_mode_enable();
/* PTE ์ํ ๋ฐ ์ด๋ */
for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE,
new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) {
VM_WARN_ON_ONCE(!pte_none(*new_ptep));
nr_ptes = 1;
max_nr_ptes = (old_end - old_addr) >> PAGE_SHIFT;
old_pte = ptep_get(old_ptep);
if (pte_none(old_pte))
continue;
/* ์ ํจํ PTE์ธ ๊ฒฝ์ฐ TLB ํ๋ฌ์ ํ์ */
if (pte_present(old_pte)) {
nr_ptes = mremap_folio_pte_batch(vma, old_addr, old_ptep,
old_pte, max_nr_ptes);
force_flush = true;
}
/* PTE ์ด๋ */
pte = get_and_clear_ptes(mm, old_addr, old_ptep, nr_ptes);
pte = move_pte(pte, old_addr, new_addr);
pte = move_soft_dirty_pte(pte);
/* uffd-wp ์ฒ๋ฆฌ */
if (need_clear_uffd_wp && pte_is_uffd_wp_marker(pte))
pte_clear(mm, new_addr, new_ptep);
else {
if (need_clear_uffd_wp) {
if (pte_present(pte))
pte = pte_clear_uffd_wp(pte);
else
pte = pte_swp_clear_uffd_wp(pte);
}
set_ptes(mm, new_addr, new_ptep, pte, nr_ptes);
}
}
lazy_mmu_mode_disable();
if (force_flush)
flush_tlb_range(vma, old_end - len, old_end);
if (new_ptl != old_ptl)
spin_unlock(new_ptl);
pte_unmap(new_ptep - 1);
pte_unmap_unlock(old_ptep - 1, old_ptl);
out:
if (pmc->need_rmap_locks)
drop_rmap_locks(vma);
return err;
}
์ญํ : ๊ฐ๋ณ PTE๋ฅผ ์์ค์์ ๋์์ผ๋ก ์ด๋ํฉ๋๋ค. folio ๋ฐฐ์น ์ฒ๋ฆฌ, soft-dirty ๋นํธ ์ฒ๋ฆฌ, userfaultfd-wp ์ฒ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.
8. mremap_folio_pte_batch
large folio์ ๊ฒฝ์ฐ ์ฌ๋ฌ PTE๋ฅผ ํ ๋ฒ์ ๋ฐฐ์น ์ฒ๋ฆฌํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:178-195 */
static int mremap_folio_pte_batch(struct vm_area_struct *vma, unsigned long addr,
pte_t *ptep, pte_t pte, int max_nr)
{
struct folio *folio;
if (max_nr == 1)
return 1;
/* large folio๊ฐ ์๋๋ฉด ๋ฐฐ์น ๋ถ๊ฐ */
if (pte_batch_hint(ptep, pte) == 1)
return 1;
folio = vm_normal_folio(vma, addr, pte);
if (!folio || !folio_test_large(folio))
return 1;
return folio_pte_batch_flags(folio, NULL, ptep, &pte, max_nr, FPB_RESPECT_WRITE);
}
์ญํ : large folio์ ๊ฒฝ์ฐ ์ฌ๋ฌ PTE๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
9. move_soft_dirty_pte
soft-dirty ๋นํธ๋ฅผ ์ค์ ํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:159-176 */
static pte_t move_soft_dirty_pte(pte_t pte)
{
if (pte_none(pte))
return pte;
/* soft dirty ๋นํธ ์ค์ ํ์ฌ ์ฌ์ฉ์ ๊ณต๊ฐ์์ PTE ์ด๋ ๊ฐ์ง */
if (pgtable_supports_soft_dirty()) {
if (pte_present(pte))
pte = pte_mksoft_dirty(pte);
else
pte = pte_swp_mksoft_dirty(pte);
}
return pte;
}
์ญํ : PTE๊ฐ ์ด๋๋์์์ ์ฌ์ฉ์ ๊ณต๊ฐ์์ ๊ฐ์งํ ์ ์๋๋ก soft-dirty ๋นํธ๋ฅผ ์ค์ ํฉ๋๋ค.
10. mremap_to
์ง์ ๋ ์ฃผ์๋ก VMA๋ฅผ ๋ฆฌ๋งคํํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1367-1417 */
static unsigned long mremap_to(struct vma_remap_struct *vrm)
{
struct mm_struct *mm = current->mm;
unsigned long err;
/* MREMAP_FIXED์ธ ๊ฒฝ์ฐ ๋์ ์์ญ ๋จผ์ ์ ๊ฑฐ */
if (vrm->flags & MREMAP_FIXED) {
err = do_munmap(mm, vrm->new_addr, vrm->new_len,
vrm->uf_unmap_early);
vrm->vma = NULL;
vrm->vmi_needs_invalidate = true;
if (err)
return err;
/* VMA ์ฌ์กฐํ */
vrm->vma = vma_lookup(mm, vrm->addr);
if (!vrm->vma)
return -EFAULT;
}
/* ์ถ์ ์ฒ๋ฆฌ */
if (vrm->remap_type == MREMAP_SHRINK) {
err = shrink_vma(vrm, false);
if (err)
return err;
vrm->old_len = vrm->new_len;
}
/* MREMAP_DONTUNMAP์ ํ์ฅ ๊ฒ์ฆ */
if (vrm->flags & MREMAP_DONTUNMAP) {
vm_flags_t vm_flags = vrm->vma->vm_flags;
unsigned long pages = vrm->old_len >> PAGE_SHIFT;
if (!may_expand_vm(mm, vm_flags, pages))
return -ENOMEM;
}
/* ์ ์ฃผ์ ๊ฒฐ์ */
err = vrm_set_new_addr(vrm);
if (err)
return err;
return move_vma(vrm);
}
์ญํ : MREMAP_FIXED ํ๋๊ทธ๋ก ์ง์ ๋ ์ฃผ์๋ก VMA๋ฅผ ์ด๋ํฉ๋๋ค.
11. mremap_at
์ฃผ์ ์ง์ ์์ด VMA ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1554-1584 */
static unsigned long mremap_at(struct vma_remap_struct *vrm)
{
unsigned long res;
switch (vrm->remap_type) {
case MREMAP_INVALID:
break;
case MREMAP_NO_RESIZE:
/* ํฌ๊ธฐ ๋ณ๊ฒฝ ์์ - no-op */
return vrm->addr;
case MREMAP_SHRINK:
/* ์ถ์ - ํญ์ in-place ๊ฐ๋ฅ */
res = shrink_vma(vrm, true);
if (res)
return res;
return vrm->addr;
case MREMAP_EXPAND:
return expand_vma(vrm);
}
WARN_ON_ONCE(1);
return -EINVAL;
}
์ญํ : MREMAP_NO_RESIZE, MREMAP_SHRINK, MREMAP_EXPAND ์ ํ์ ๋ฐ๋ผ ์ ์ ํ ์ฒ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.
12. expand_vma
VMA๋ฅผ ํ์ฅํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1516-1548 */
static unsigned long expand_vma(struct vma_remap_struct *vrm)
{
unsigned long err;
/* in-place ํ์ฅ ๊ฐ๋ฅ ์ฌ๋ถ ํ์ธ */
if (vrm_can_expand_in_place(vrm)) {
err = expand_vma_in_place(vrm);
if (err)
return err;
return vrm->addr;
}
/* in-place ํ์ฅ ๋ถ๊ฐ๋ฅํ๋ฉด ์ด๋ ํ์ */
if (!(vrm->flags & MREMAP_MAYMOVE))
return -ENOMEM;
/* ์ ์ฃผ์ ๊ฒฐ์ */
err = vrm_set_new_addr(vrm);
if (err)
return err;
return move_vma(vrm);
}
์ญํ : in-place ํ์ฅ์ ์๋ํ๊ณ , ๋ถ๊ฐ๋ฅํ๋ฉด MREMAP_MAYMOVE ํ๋๊ทธ๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ ์ด๋์ ์ํํฉ๋๋ค.
13. expand_vma_in_place
VMA๋ฅผ in-place๋ก ํ์ฅํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1456-1484 */
static unsigned long expand_vma_in_place(struct vma_remap_struct *vrm)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma = vrm->vma;
VMA_ITERATOR(vmi, mm, vma->vm_end);
/* ๊ณ์ ์ฒ๋ฆฌ */
if (!vrm_calc_charge(vrm))
return -ENOMEM;
/* VMA ํ์ฅ ๋ฐ ๋ณํฉ */
vma = vma_merge_extend(&vmi, vma, vrm->delta);
if (!vma) {
vrm_uncharge(vrm);
return -ENOMEM;
}
vrm->vma = vma;
/* ํต๊ณ ๊ณ์ */
vrm_stat_account(vrm, vrm->delta);
return 0;
}
์ญํ : VMA๋ฅผ in-place๋ก ํ์ฅํ๊ณ , ์ธ์ VMA์ ๋ณํฉ์ ์๋ํฉ๋๋ค.
14. shrink_vma
VMA๋ฅผ ์ถ์ํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1330-1361 */
static unsigned long shrink_vma(struct vma_remap_struct *vrm,
bool drop_lock)
{
struct mm_struct *mm = current->mm;
unsigned long unmap_start = vrm->addr + vrm->new_len;
unsigned long unmap_bytes = vrm->delta;
unsigned long res;
VMA_ITERATOR(vmi, mm, unmap_start);
VM_BUG_ON(vrm->remap_type != MREMAP_SHRINK);
/* ์ถ์ ์์ญ ์ ๊ฑฐ */
res = do_vmi_munmap(&vmi, mm, unmap_start, unmap_bytes,
vrm->uf_unmap, drop_lock);
vrm->vma = NULL;
if (res)
return res;
/* ์ ๊ธ ํด์ ์ VMA ์ฌ์กฐํ */
if (drop_lock) {
vrm->mmap_locked = false;
} else {
vrm->vma = vma_lookup(mm, vrm->addr);
if (!vrm->vma)
return -EFAULT;
}
return 0;
}
์ญํ : VMA์ ๋๋ถ๋ถ์ ์ ๊ฑฐํ์ฌ ํฌ๊ธฐ๋ฅผ ์ถ์ํฉ๋๋ค.
15. remap_move
์ฌ๋ฌ VMA๋ฅผ ํ ๋ฒ์ ์ด๋ํ๋ ํจ์์ ๋๋ค.
/* mm/mremap.c:1826-1913 */
static unsigned long remap_move(struct vma_remap_struct *vrm)
{
struct vm_area_struct *vma;
unsigned long start = vrm->addr;
unsigned long end = vrm->addr + vrm->old_len;
unsigned long new_addr = vrm->new_addr;
unsigned long target_addr = new_addr;
unsigned long res = -EFAULT;
unsigned long last_end;
bool seen_vma = false;
VMA_ITERATOR(vmi, current->mm, start);
/* ๋ฒ์ ๋ด ๋ชจ๋ VMA ์ํ */
for_each_vma_range(vmi, vma, end) {
unsigned long addr = max(vma->vm_start, start);
unsigned long len = min(end, vma->vm_end) - addr;
unsigned long offset, res_vma;
bool multi_allowed;
/* ์์ ๋ถ๋ถ์ ๊ฐ๊ฒฉ ํ์ฉ ์๋จ */
if (!seen_vma && start < vma->vm_start)
return -EFAULT;
/* ๊ฐ๊ฒฉ ์ ์งํ์ฌ ์ด๋ */
offset = seen_vma ? vma->vm_start - last_end : 0;
last_end = vma->vm_end;
vrm->vma = vma;
vrm->addr = addr;
vrm->new_addr = target_addr + offset;
vrm->old_len = vrm->new_len = len;
multi_allowed = vma_multi_allowed(vma);
if (!multi_allowed) {
if (seen_vma)
return -EFAULT;
if (vma->vm_end < end)
return -EFAULT;
}
res_vma = check_prep_vma(vrm);
if (!res_vma)
res_vma = mremap_to(vrm);
if (IS_ERR_VALUE(res_vma))
return res_vma;
if (!seen_vma) {
VM_WARN_ON_ONCE(multi_allowed && res_vma != new_addr);
res = res_vma;
}
if (vrm->vmi_needs_invalidate) {
vma_iter_invalidate(&vmi);
vrm->vmi_needs_invalidate = false;
}
seen_vma = true;
target_addr = res_vma + vrm->new_len;
}
return res;
}
์ญํ : ์ฌ๋ฌ VMA๋ฅผ ํ ๋ฒ์ ์ด๋ํ ๋ ๊ฐ๊ฒฉ์ ์ ์งํ๋ฉด์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
ํธ์ถ ํ๋ฆ
SYSCALL_DEFINE5(mremap) โ ์ฌ์ฉ์ ์์คํ
ํธ์ถ ์ง์
์
โ
do_mremap() โ ๋ฉ์ธ ๋ก์ง ์ฒ๋ฆฌ
โโ check_mremap_params() # ํ๋ผ๋ฏธํฐ ๊ฒ์ฆ (ํ๋๊ทธ, ์ฃผ์, ํฌ๊ธฐ)
โโ mmap_write_lock_killable() # mmap ์ฐ๊ธฐ ์ ๊ธ ํ๋
โโ vrm_move_only()?
โ โโ YES โ remap_move() # ๋ค์ค VMA ์ด๋ (๊ฐ๊ฒฉ ์ ์ง)
โ โ โโ for_each_vma_range()
โ โ โโ check_prep_vma() # VMA ์ค๋น ๊ฒ์ฆ
โ โ โโ mremap_to() # ์ง์ ์ฃผ์๋ก ์ด๋
โ โ โโ do_munmap() # ๋์ ์์ญ ์ ๊ฑฐ
โ โ โโ vrm_set_new_addr() # ์ ์ฃผ์ ๊ฒฐ์
โ โ โโ move_vma()
โ โ โโ prep_move_vma() # VMA ๋ถํ ์ค๋น
โ โ โโ vrm_calc_charge() # ๊ณ์ ์ฒ๋ฆฌ
โ โ โโ copy_vma_and_data()
โ โ โ โโ copy_vma() # VMA ๋ณต์ฌ
โ โ โ โโ move_page_tables() # ํ์ด์ง ํ
์ด๋ธ ์ด๋
โ โ โ โโ try_realign_addr() # PMD ๊ฒฝ๊ณ ์ ๋ ฌ
โ โ โ โโ move_pgt_entry() # PUD/PMD ๋ ๋ฒจ ์ด๋
โ โ โ โโ move_ptes() # PTE ๋ ๋ฒจ ์ด๋
โ โ โ โโ mremap_folio_pte_batch() # large folio ๋ฐฐ์น
โ โ โโ vrm_stat_account() # ํต๊ณ ๊ณ์
โ โ โโ unmap_source_vma() # ์๋ณธ ์ ๊ฑฐ
โ โโ NO โ vma_lookup() # VMA ์กฐํ
โ โโ check_prep_vma() # VMA ์ค๋น ๊ฒ์ฆ
โ โโ mremap_to() ๋๋ mremap_at()
โ โโ mremap_to() # ๊ณ ์ ์ฃผ์๋ก ์ด๋
โ โ โโ do_munmap() # ๋์ ์์ญ ์ ๊ฑฐ
โ โ โโ shrink_vma() # ์ถ์ ์ฒ๋ฆฌ
โ โ โโ move_vma()
โ โโ mremap_at() # ์ฃผ์ ์ง์ ์์ด ์ด๋
โ โโ MREMAP_NO_RESIZE โ ์ฆ์ ๋ฐํ
โ โโ MREMAP_SHRINK โ shrink_vma()
โ โโ MREMAP_EXPAND โ expand_vma()
โ โโ vrm_can_expand_in_place()?
โ โ โโ YES โ expand_vma_in_place()
โ โ โ โโ vma_merge_extend()
โ โ โโ NO โ move_vma()
โโ mmap_write_unlock() # mmap ์ ๊ธ ํด์
ํ๋ฆ ์ค๋ช
1. ์ง์
์ : SYSCALL_DEFINE5(mremap)์ด ์ฌ์ฉ์๋ก๋ถํฐ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ vma_remap_struct๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
2. ํ๋ผ๋ฏธํฐ ๊ฒ์ฆ: check_mremap_params()๊ฐ ํ๋๊ทธ, ์ฃผ์ ์ ๋ ฌ, ํฌ๊ธฐ ์ ํ ๋ฑ์ ๊ฒ์ฆํฉ๋๋ค.
3. ์ ๊ธ ํ๋: mmap_write_lock_killable()๋ก mmap ์ฐ๊ธฐ ์ ๊ธ์ ํ๋ํฉ๋๋ค.
4. ๊ฒฝ๋ก ์ ํ:
- vrm_move_only()๊ฐ true์ด๋ฉด remap_move()๋ก ์ฌ๋ฌ VMA๋ฅผ ํ ๋ฒ์ ์ด๋ํฉ๋๋ค.
- ์๋๋ฉด ๋จ์ผ VMA ์ฒ๋ฆฌ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ฆ ๋๋ค.
5. VMA ์ฒ๋ฆฌ:
- mremap_to(): MREMAP_FIXED ํ๋๊ทธ๋ก ์ง์ ๋ ์ฃผ์๋ก ์ด๋
- mremap_at(): ์ฃผ์ ์ง์ ์์ด ํฌ๊ธฐ ๋ณ๊ฒฝ
6. ํ์ด์ง ํ
์ด๋ธ ์ด๋: move_page_tables()๊ฐ PUDโPMDโPTE ์์๋ก ํ์ด์ง ํ
์ด๋ธ์ ์ด๋ํฉ๋๋ค.
7. ์ฑ๋ฅ ์ต์ ํ:
- try_realign_addr(): PMD ๊ฒฝ๊ณ์ ์ ๋ ฌํ์ฌ ์ฒ๋ฆฌ ํจ์จ ํฅ์
- mremap_folio_pte_batch(): large folio์ ๊ฒฝ์ฐ ์ฌ๋ฌ PTE๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌ
8. ๋ง๋ฌด๋ฆฌ: mmap ์ ๊ธ ํด์ , userfaultfd ์๋ฆผ, mlock๋ ์์ญ populate ์ฒ๋ฆฌ
์กฐ๊ฑด๋ณ ๋น๊ต
1. MREMAP ํ๋๊ทธ๋ณ ๋์
| ํ๋๊ทธ | ๊ฐ | ๋์ | ์ฌ์ฉ ์๋๋ฆฌ์ค |
|---|---|---|---|
| MREMAP_MAYMOVE | 1 | ์ด๋ ํ์ฉ | ๊ธฐ๋ณธ mremap ์ฌ์ฉ ์ |
| MREMAP_FIXED | 2 | ๊ณ ์ ์ฃผ์๋ก ์ด๋ | ํน์ ์ฃผ์์ ๋งคํ ๊ฐ์ |
| MREMAP_DONTUNMAP | 4 | ์๋ณธ ์ ์ง | ํ๋ก์ธ์ค ๊ฐ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ |
2. ๋ฆฌ๋งคํ ํ์ ๋ณ ์ฒ๋ฆฌ
| ํ์ | ์กฐ๊ฑด | ์ฒ๋ฆฌ ๋ฐฉ๋ฒ | ๊ฒฐ๊ณผ |
|---|---|---|---|
| MREMAP_NO_RESIZE | old_len == new_len | ์ฆ์ ๋ฐํ | no-op |
| MREMAP_SHRINK | old_len > new_len | in-place ์ถ์ | ์ ์ฃผ์ ๋ฐํ |
| MREMAP_EXPAND | old_len < new_len | in-place ํ์ฅ ๋๋ ์ด๋ | ์ ์ฃผ์ ๋ฐํ |
3. ํ์ด์ง ํ ์ด๋ธ ์ด๋ ์ฐ์ ์์
| ๋ ๋ฒจ | ์กฐ๊ฑด | ์ด๋ ๋ฐฉ๋ฒ | ์ฑ๋ฅ |
|---|---|---|---|
| HPAGE_PUD | Huge PUD + ์ ๋ ฌ | move_huge_pud() | ๊ฐ์ฅ ๋น ๋ฆ |
| NORMAL_PUD | ์ผ๋ฐ PUD + ์ ๋ ฌ | move_normal_pud() | ๋น ๋ฆ |
| HPAGE_PMD | Huge PMD + ์ ๋ ฌ | move_huge_pmd() | ๋น ๋ฆ |
| NORMAL_PMD | ์ผ๋ฐ PMD + ์ ๋ ฌ | move_normal_pmd() | ๋ณดํต |
| PTE | ์ผ๋ฐ ํ์ด์ง | move_ptes() | ๊ฐ์ฅ ๋๋ฆผ |
4. ํน์ ์ฒ๋ฆฌ ์กฐ๊ฑด
| ์กฐ๊ฑด | ์ฒ๋ฆฌ | ์ค๋ช |
|---|---|---|
| HugeTLB ํ์ด์ง | move_hugetlb_page_tables() | ๋ณ๋์ huge page ํ ์ด๋ธ ์ด๋ |
| uffd-wp ๋ฑ๋ก | pte_clear_uffd_wp() | userfaultfd-wp ๋ง์ปค ์ ๊ฑฐ |
| VM_ACCOUNT | vrm_calc_charge() | ๋ฉ๋ชจ๋ฆฌ ๊ณ์ ์ฒญ๊ตฌ |
| VM_LOCKED | populate_expand | ํ์ฅ ์์ญ ์๋ populate |
| KSM ํ์ด์ง | ksm_madvise(MADV_UNMERGEABLE) | KSM ๋ณํฉ ํด์ |
| mseal()๋ VMA | check_prep_vma()์์ ๊ฑฐ๋ถ | ๋ด์ธ๋ VMA ๋ฆฌ๋งคํ ๋ถ๊ฐ |
| large folio | mremap_folio_pte_batch() | ์ฌ๋ฌ PTE ๋ฐฐ์น ์ฒ๋ฆฌ |
5. ํ์ฅ/์ถ์ ๋์ ๋น๊ต
| ์ฐ์ฐ | ์กฐ๊ฑด | in-place ๊ฐ๋ฅ | ์ด๋ ํ์ |
|---|---|---|---|
| ํ์ฅ (EXPAND) | VMA ๋๋ถ๋ถ + ๋น ๊ณต๊ฐ | ๊ฐ๋ฅ | ๋ถ๊ฐ๋ฅ ์ ์ด๋ |
| ์ถ์ (SHRINK) | VMA ๋๋ถ๋ถ ์ ๊ฑฐ | ํญ์ ๊ฐ๋ฅ | ๋ถํ์ |
| ์ด๋ (MOVE) | ์ ์ฃผ์ ์ง์ | ๋ถ๊ฐ๋ฅ | ํญ์ ์ด๋ |
6. rmap ์ ๊ธ ์ฒ๋ฆฌ ๋น๊ต
| ๋ ๋ฒจ | rmap ์ ๊ธ | ์ค๋ช |
|---|---|---|
| NORMAL_PMD | ํญ์ ํ์ | ์ผ๋ฐ PMD ๋ ๋ฒจ ์ด๋ |
| NORMAL_PUD | ํญ์ ํ์ | ์ผ๋ฐ PUD ๋ ๋ฒจ ์ด๋ |
| HPAGE_PMD | ์ ํ์ | Huge PMD ์ด๋ ์ |
| HPAGE_PUD | ์ ํ์ | Huge PUD ์ด๋ ์ |
| PTE | ์ ํ์ | PTE ๋ ๋ฒจ ์ด๋ ์ |