lkml.org 
[lkml]   [1998]   [Jul]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectPage table cache problem
    I've found a page-table cache problem that's more serious than the
    question of whether the pgt should be trimmed by kswapd or not, and IMO
    it needs to get fixed right away.

    The pgt cache xxx-free_fast routines don't check the high-water mark
    when freeing pages, leaving open the possibility that the cache might
    grow very large. I added some instrumentation to the check_pgt_cache()
    code to check this by printing the cache size if it exceeds the high
    water mark, and I got some reports of huge caches -- once it exceeded
    1100 pages! (On a 32M UP system.)

    The testing was done by starting a large grep and then spawning lots of
    tasks doing a sleep 20. When the tasks exit, they dump their page tables
    into the cache, but since the cache trimming is done only by the idle
    task, the trimming may not happen for a while. The reports of large
    sizes were often followed by "fork failed" messages.

    I think the correct way to fix this is to directly call
    check_pgt_cache() after unloading the page tables. This ensures that the
    trimming (to the high water mark) happens immediately, but without
    burdening the xxx_free_fast code with extra tests. I've attached a patch
    that does this, and after enabling the patch the largest cache size I've
    seen is 54 pages.

    Regards,
    Bill




    --- linux-2.1.111/mm/memory.c.old Tue Jun 30 12:42:50 1998
    +++ linux-2.1.111/mm/memory.c Sun Jul 26 12:34:34 1998
    @@ -127,16 +131,23 @@
    */
    void clear_page_tables(struct task_struct * tsk)
    {
    + pgd_t * page_dir = tsk->mm->pgd;
    int i;
    - pgd_t * page_dir;

    - page_dir = tsk->mm->pgd;
    - if (!page_dir || page_dir == swapper_pg_dir) {
    - printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
    - return;
    - }
    + if (!page_dir || page_dir == swapper_pg_dir)
    + goto out_bad;
    for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
    free_one_pgd(page_dir + i);
    +
    + /* keep the page table cache within bounds */
    + check_pgt_cache();
    + return;
    +
    +out_bad:
    + printk(KERN_ERR
    + "clear_page_tables: %s trying to clear kernel pgd\n",
    + tsk->comm);
    + return;
    }

    /*
    @@ -146,19 +157,26 @@
    */
    void free_page_tables(struct mm_struct * mm)
    {
    + pgd_t * page_dir = mm->pgd;
    int i;
    - pgd_t * page_dir;

    - page_dir = mm->pgd;
    - if (page_dir) {
    - if (page_dir == swapper_pg_dir) {
    - printk("free_page_tables: Trying to free kernel pgd\n");
    - return;
    - }
    - for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
    - free_one_pgd(page_dir + i);
    - pgd_free(page_dir);
    - }
    + if (!page_dir)
    + goto out;
    + if (page_dir == swapper_pg_dir)
    + goto out_bad;
    + for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
    + free_one_pgd(page_dir + i);
    + pgd_free(page_dir);
    +
    + /* keep the page table cache within bounds */
    + check_pgt_cache();
    +out:
    + return;
    +
    +out_bad:
    + printk(KERN_ERR
    + "free_page_tables: Trying to free kernel pgd\n");
    + return;
    }

    int new_page_tables(struct task_struct * tsk)
    \
     
     \ /
      Last update: 2005-03-22 13:43    [W:0.023 / U:0.072 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site