lkml.org 
[lkml]   [2004]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] rmaplock 6/6 swapoff use anon_vma
    Swapoff can make good use of a page's anon_vma and index, while it's
    still left in swapcache, or once it's brought back in and the first pte
    mapped back: unuse_vma go directly to just one page of only those vmas
    with the same anon_vma. And unuse_process can skip any vmas without an
    anon_vma (extending the hugetlb check: hugetlb vmas have no anon_vma).

    This just hacks in on top of the existing procedure, still going through
    all the vmas of all the mms in mmlist. A more elegant procedure might
    replace mmlist by a list of anon_vmas: but that would be more work to
    implement, with apparently more overhead in the common paths.

    Signed-off-by: Hugh Dickins <hugh@veritas.com>

    include/linux/rmap.h | 5 +++++
    mm/rmap.c | 20 ++++++++++++++++++++
    mm/swapfile.c | 23 ++++++++++++++++-------
    3 files changed, 41 insertions(+), 7 deletions(-)

    --- rmaplock5/include/linux/rmap.h 2004-07-12 18:20:22.333796048 +0100
    +++ rmaplock6/include/linux/rmap.h 2004-07-12 18:21:16.752523144 +0100
    @@ -91,6 +91,11 @@ static inline void page_dup_rmap(struct
    int page_referenced(struct page *, int is_locked);
    int try_to_unmap(struct page *);

    +/*
    + * Used by swapoff to help locate where page is expected in vma.
    + */
    +unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
    +
    #else /* !CONFIG_MMU */

    #define anon_vma_init() do {} while (0)
    --- rmaplock5/mm/rmap.c 2004-07-12 18:21:02.456696440 +0100
    +++ rmaplock6/mm/rmap.c 2004-07-12 18:21:16.767520864 +0100
    @@ -231,6 +231,24 @@ vma_address(struct page *page, struct vm
    }

    /*
    + * At what user virtual address is page expected in vma? checking that the
    + * page matches the vma: currently only used by unuse_process, on anon pages.
    + */
    +unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
    +{
    + if (PageAnon(page)) {
    + if ((void *)vma->anon_vma !=
    + (void *)page->mapping - PAGE_MAPPING_ANON)
    + return -EFAULT;
    + } else if (page->mapping && !(vma->vm_flags & VM_NONLINEAR)) {
    + if (vma->vm_file->f_mapping != page->mapping)
    + return -EFAULT;
    + } else
    + return -EFAULT;
    + return vma_address(page, vma);
    +}
    +
    +/*
    * Subfunctions of page_referenced: page_referenced_one called
    * repeatedly from either page_referenced_anon or page_referenced_file.
    */
    @@ -457,6 +475,8 @@ void page_remove_rmap(struct page *page)
    * which increments mapcount after us but sets mapping
    * before us: so leave the reset to free_hot_cold_page,
    * and remember that it's only reliable while mapped.
    + * Leaving it set also helps swapoff to reinstate ptes
    + * faster for those pages still in swapcache.
    */
    if (page_test_and_clear_dirty(page))
    set_page_dirty(page);
    --- rmaplock5/mm/swapfile.c 2004-07-12 18:21:02.458696136 +0100
    +++ rmaplock6/mm/swapfile.c 2004-07-12 18:21:16.769520560 +0100
    @@ -520,14 +520,24 @@ static unsigned long unuse_pgd(struct vm
    }

    /* vma->vm_mm->page_table_lock is held */
    -static unsigned long unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
    +static unsigned long unuse_vma(struct vm_area_struct * vma,
    swp_entry_t entry, struct page *page)
    {
    - unsigned long start = vma->vm_start, end = vma->vm_end;
    + pgd_t *pgdir;
    + unsigned long start, end;
    unsigned long foundaddr;

    - if (start >= end)
    - BUG();
    + if (page->mapping) {
    + start = page_address_in_vma(page, vma);
    + if (start == -EFAULT)
    + return 0;
    + else
    + end = start + PAGE_SIZE;
    + } else {
    + start = vma->vm_start;
    + end = vma->vm_end;
    + }
    + pgdir = pgd_offset(vma->vm_mm, start);
    do {
    foundaddr = unuse_pgd(vma, pgdir, start, end - start,
    entry, page);
    @@ -559,9 +569,8 @@ static int unuse_process(struct mm_struc
    }
    spin_lock(&mm->page_table_lock);
    for (vma = mm->mmap; vma; vma = vma->vm_next) {
    - if (!is_vm_hugetlb_page(vma)) {
    - pgd_t * pgd = pgd_offset(mm, vma->vm_start);
    - foundaddr = unuse_vma(vma, pgd, entry, page);
    + if (vma->anon_vma) {
    + foundaddr = unuse_vma(vma, entry, page);
    if (foundaddr)
    break;
    }
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:04    [W:0.026 / U:60.648 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site