[커널 16차 스터디] 92주차 질문 사항입니다.

 

안녕하세요.

16기 이파란입니다.

 

try_to_unmap_one() 할 때,

기존 PTE 매핑을 swap_entry 로 바꿔서 이상합니다.

왜 그럴까요?

 

buddy system

    -> slow path memory allocation

        -> memory compaction

            -> try_to_unmap

 

물리 메모리 복사 붙여넣기 이후, 기존 물리 메모리 영역 매핑 해제 부분을

pageAnon 기준으로 보고 있습니다.

 

코드를 보다가 swap 관련 부분이 아니고, 메모리 compaction 시에

anon page 에 대해서는 모두 이 코드를 타는 것 같아서 의문이 들어서 문의드립니다.

 

컴팩션은 v2.6.35-rc1 에 추가되었고,

더 이전에 pageAnon(page) 가 추가되었던 릴리즈(v2.6.7)에서 확인해보니

해당 분기에 대한 처리는 주관적인 생각으로, 의미적으로는 크게 바뀌지 않은 것 같습니다.

 

이렇게 해당 코드는 유구한 전통(?) 을 가지고 있습니다.

 

저희 보는 5.1 그리고 v5.10.37 기준으로도 많이 바뀌지 않아서 

 

v2.6.7

v5.10.37

 

제가 참고해서 리뷰한 해당 부분의 코드입니다.

 

https://gist.github.com/paranlee/441778236268832ebeadea2954dbe803

 

gist embed 가 잘 안되서 우선, 아래에 나눠서 적었습니다.

 

v2.6.7

/** 

 * v2.6.7

 * https://elixir.bootlin.com/linux/v2.6.7/source/mm/rmap.c#L424

 */

/*

 * Subfunctions of try_to_unmap: try_to_unmap_one called

 * repeatedly from either try_to_unmap_anon or try_to_unmap_file.

 */

static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)

{

    struct mm_struct *mm = vma->vm_mm;

    unsigned long address;

    pgd_t *pgd;

    pmd_t *pmd;

    pte_t *pte;

    pte_t pteval;

    int ret = SWAP_AGAIN;

 

    if (!mm->rss)

        goto out;

    address = vma_address(page, vma);

    if (address == -EFAULT)

        goto out;

 

    /*

     * We need the page_table_lock to protect us from page faults,

     * munmap, fork, etc...

     */

    if (!spin_trylock(&mm->page_table_lock))

        goto out;

 

    pgd = pgd_offset(mm, address);

    if (!pgd_present(*pgd))

        goto out_unlock;

 

    pmd = pmd_offset(pgd, address);

    if (!pmd_present(*pmd))

        goto out_unlock;

 

    pte = pte_offset_map(pmd, address);

    if (!pte_present(*pte))

        goto out_unmap;

 

    if (page_to_pfn(page) != pte_pfn(*pte))

        goto out_unmap;

 

    /*

     * If the page is mlock()d, we cannot swap it out.

     * If it's recently referenced (perhaps page_referenced

     * skipped over this mm) then we should reactivate it.

     */

    if ((vma->vm_flags & (VM_LOCKED|VM_RESERVED)) ||

            ptep_test_and_clear_young(pte)) {

        ret = SWAP_FAIL;

        goto out_unmap;

    }

 

    /*

     * Don't pull an anonymous page out from under get_user_pages.

     * GUP carefully breaks COW and raises page count (while holding

     * page_table_lock, as we have here) to make sure that the page

     * cannot be freed.  If we unmap that page here, a user write

     * access to the virtual address will bring back the page, but

     * its raised count will (ironically) be taken to mean it's not

     * an exclusive swap page, do_wp_page will replace it by a copy

     * page, and the user never get to see the data GUP was holding

     * the original page for.

     */

    if (PageSwapCache(page) &&

        page_count(page) != page->mapcount + 2) {

        ret = SWAP_FAIL;

        goto out_unmap;

    }

 

    /* Nuke the page table entry. */

    flush_cache_page(vma, address);

    pteval = ptep_clear_flush(vma, address, pte);

 

    /* Move the dirty bit to the physical page now the pte is gone. */

    if (pte_dirty(pteval))

        set_page_dirty(page);

 

    if (PageAnon(page)) {

        swp_entry_t entry = { .val = page->private };

        /*

         * Store the swap location in the pte.

         * See handle_pte_fault() ...

         */

        BUG_ON(!PageSwapCache(page));

        swap_duplicate(entry);

        set_pte(pte, swp_entry_to_pte(entry));

        BUG_ON(pte_file(*pte));

    }

 

    mm->rss--;

    BUG_ON(!page->mapcount);

    page->mapcount--;

    page_cache_release(page);

 

out_unmap:

    pte_unmap(pte);

out_unlock:

    spin_unlock(&mm->page_table_lock);

out:

    return ret;

}

 

v5.10.37

/**

 * v5.10.37

 * https://elixir.bootlin.com/linux/v5.10.37/source/mm/rmap.c#L1617

 */

/*

 * @arg: enum ttu_flags will be passed to this argument

 */

static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,

             unsigned long address, void *arg)

{

    struct mm_struct *mm = vma->vm_mm;

    struct page_vma_mapped_walk pvmw = {

        .page = page,

        .vma = vma,

        .address = address,

    };

    pte_t pteval;

    struct page *subpage;

    bool ret = true;

    struct mmu_notifier_range range;

    enum ttu_flags flags = (enum ttu_flags)(long)arg;

 

    // ..

 

    while (page_vma_mapped_walk(&pvmw)) {

 

        // ...

 

        } else if (IS_ENABLED(CONFIG_MIGRATION) &&
                (flags & (TTU_MIGRATION|TTU_SPLIT_FREEZE))) {

            swp_entry_t entry;
            pte_t swp_pte;

            if (arch_unmap_one(mm, vma, address, pteval) < 0) {
                set_pte_at(mm, address, pvmw.pte, pteval);
                ret = false;
                page_vma_mapped_walk_done(&pvmw);
                break;
            }

            /*
             * Store the pfn of the page in a special migration
             * pte. do_swap_page() will wait until the migration
             * pte is removed and then restart fault handling.
             */

            entry = make_migration_entry(subpage,
                    pte_write(pteval));
            swp_pte = swp_entry_to_pte(entry);

            if (pte_soft_dirty(pteval))
                swp_pte = pte_swp_mksoft_dirty(swp_pte);
            if (pte_uffd_wp(pteval))
                swp_pte = pte_swp_mkuffd_wp(swp_pte);
            set_pte_at(mm, address, pvmw.pte, swp_pte);
            /*
             * No need to invalidate here it will synchronize on
             * against the special swap migration pte.
             */

        } else if (PageAnon(page)) {

            swp_entry_t entry = { .val = page_private(subpage) };

            pte_t swp_pte;

 

            // ...

 

            swp_pte = swp_entry_to_pte(entry);

            if (pte_soft_dirty(pteval))

                swp_pte = pte_swp_mksoft_dirty(swp_pte);

            if (pte_uffd_wp(pteval))

                swp_pte = pte_swp_mkuffd_wp(swp_pte);

            set_pte_at(mm, address, pvmw.pte, swp_pte);

            /* Invalidate as we cleared the pte */

            mmu_notifier_invalidate_range(mm, address,

                              address + PAGE_SIZE);

        }

 

            // ...

 

 

discard:

        /*

         * No need to call mmu_notifier_invalidate_range() it has be

         * done above for all cases requiring it to happen under page

         * table lock before mmu_notifier_invalidate_range_end()

         *

         * See Documentation/vm/mmu_notifier.rst

         */

        page_remove_rmap(subpage, PageHuge(page));

        put_page(page);

    }

 

    mmu_notifier_invalidate_range_end(&range);

 

    return ret;

}

 

아래는 의논하면서 본 swap_entry 관련 다이어그램입니다.

 

swap-6a.png

<출처: http://jake.dothome.co.kr/swap-1/>

 

긴 글 끝까지 읽어주셔서 감사합니다.

 

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 프로그래밍 관련 Q&A 게시판 입니다. woos 2016.04.09 22244
518 사운드 관련하여 질문입니다. qtopia 2016.09.22 134
517 __no_granule_support에서의 wfe, wfi 중복 사용 [2] min 2022.10.03 175
516 unflatten_dt_nodes 질문 [3] file 에러 2019.10.12 214
515 __inval_dcache_area의 동작에 대해 질문드립니다. [2] dfx 2019.07.08 228
514 16기 리눅스 커널 스터디 C조 19주차 질문입니다. (두 번째) [2] rnsscman 2019.10.29 234
513 Android Application 구동에 관한 조언 부탁드립니다. [1] June 2016.09.21 236
512 16기 리눅스 커널 스터디 C조 cpu_bit_bitmap 질문 [2] sjahn 2019.10.05 244
511 cgroup의 구조 및 학습 방법에대해 질문드립니다. file dfx 2019.08.25 257
510 16기 리눅스 커널 스터디 C조 cgroup_init_early 부분 질문 [2] 이파란 2019.09.21 262
509 arm a53 아키텍처는 cache size를 configuration 할 수 없나요? [1] mnth 2023.12.03 274
508 안녕하세요 soheemon 2018.02.26 284
507 early_fixmap_init 질문 [3] file 에러 2019.12.17 288
506 head.S의 compute_indices 관련 문의 드립니다 [3] cien 2019.07.30 292
505 setup_machine_fdt() -> fixmap_remap_fdt() 질문입니다. [2] daeroro 2019.12.24 316
504 program을 실행 할 때 shell or dameon [2] wizard1483 2019.01.14 324
503 커널 컴파일 [1] ldy209 2017.04.06 329
502 early_fixmap_init 함수 질문 [2] 에러가왜안뜨지 2019.09.12 345
501 16기 리눅스 커널 스터디 33주차 질문입니다. [5] rnsscman 2020.02.08 358
500 메모리와 관련하여 질문있습니다. [5] 인그니야 2018.10.17 361
499 16기 리눅스 커널 스터디 25주차 질문입니다. [3] rnsscman 2019.12.03 367
XE Login