[커널 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 22172
517 alloc과 free함수에 대해서 질문입니다. [1] 정재훈 2011.06.28 93324
516 안드로이드 system 폴더안의 파일을 인식못하는데.. [5] 김영일 2011.04.14 69517
515 x86에서 ZONE_DMA 영역의 사용 [1] 홍문화 2011.05.02 57933
514 커널에서 page alloc에 관해서 [1] 미다리로23 2017.02.05 34420
513 디바이스 드라이버 모듈에서 작성한 함수를 커널에서 사용하는 방법 [1] 개짖는소리 2017.02.06 26942
512 Linux kernel의 CFS(Completely Fair Scheduling) 스케줄러에서 time slice 구하는 방법? [10] 김재호 2010.04.30 25189
511 "만들면서 배우는 OS..." 4장 kernel.asm 중 idtr 설정 질문드립니다 쿨쿨 2013.06.18 24883
510 리눅스 스케줄러 관련 [9] 홍문화 2011.02.23 22935
509 NFS NAS SAN 이란 무엇인가? file 박은병 2010.04.13 21873
508 s3c2440기반의 리눅스 커널 분석 중 MM관련 질문입니다. 유태경 2007.09.02 21522
507 /dev 폴더에 있는 node파일 중에서 어떤 것을 open해야 플래쉬를 사용할 수 있을까요? [1] 박종주 2012.02.17 19849
506 sparsemem에 대한 질문이 있습니다. [5] 안정모 2010.03.20 19717
505 16기 리눅스 커널 스터디 C조 18주차 질문입니다. [3] cien 2019.10.12 18681
504 tty, tty0, console, vc 는 각각 뭐하는 디바이스인지? [3] 이창만 2008.12.04 18535
503 ARM A8 이상의 프로세서를 공부할 때 스터디 방향 [4] 유강희 2011.06.15 18488
502 임베디드 OS 만들기 내용과 관련하여 문의드립니다. [5] 송인재 2010.03.25 18317
501 far call 이란 무엇인가요? [4] 박한범 2010.04.13 17840
500 파일시스템에 관한 질문(Htree [6] 사앙조 2017.05.22 17033
499 SMP관련 질문입니다. [2] 컴퓨터 2017.04.13 16573
XE Login