lkml.org 
[lkml]   [2000]   [Dec]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] swap write clustering for 2.4 (again)

    Linus,

    The following patch changes swap_writepage() to try to do write clustering
    of phisically contiguous pages which are dirty and in the swapcache.

    Do you want to include it in 2.4?


    diff -Nur --exclude-from=exclude linux.orig/include/linux/mm.h linux/include/linux/mm.h
    --- linux.orig/include/linux/mm.h Thu Dec 21 04:34:19 2000
    +++ linux/include/linux/mm.h Thu Dec 21 03:56:30 2000
    @@ -451,6 +451,8 @@
    extern int filemap_swapout(struct page *, struct file *);
    extern int filemap_sync(struct vm_area_struct *, unsigned long, size_t, unsigned int);
    extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int);
    +extern inline struct page * ___find_page_nolock(struct address_space *, unsigned long, struct page *);
    +

    /*
    * GFP bitmasks..
    diff -Nur --exclude-from=exclude linux.orig/include/linux/swap.h linux/include/linux/swap.h
    --- linux.orig/include/linux/swap.h Thu Dec 21 04:34:19 2000
    +++ linux/include/linux/swap.h Thu Dec 21 04:16:42 2000
    @@ -166,6 +166,8 @@
    extern unsigned long swap_cache_find_total;
    extern unsigned long swap_cache_find_success;
    #endif
    +
    +extern struct swap_info_struct swap_info[MAX_SWAPFILES];

    /*
    * Work out if there are any other processes sharing this page, ignoring
    diff -Nur --exclude-from=exclude linux.orig/mm/filemap.c linux/mm/filemap.c
    --- linux.orig/mm/filemap.c Thu Dec 21 04:34:20 2000
    +++ linux/mm/filemap.c Thu Dec 21 03:53:41 2000
    @@ -242,7 +242,7 @@
    spin_unlock(&pagecache_lock);
    }

    -static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
    +inline struct page * ___find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
    {
    goto inside;

    @@ -250,12 +250,22 @@
    page = page->next_hash;
    inside:
    if (!page)
    - goto not_found;
    + return NULL;
    if (page->mapping != mapping)
    continue;
    if (page->index == offset)
    break;
    }
    + return page;
    +}
    +
    +static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
    +{
    + page = ___find_page_nolock(mapping, offset, page);
    +
    + if(!page)
    + return NULL;
    +
    /*
    * Touching the page may move it to the active list.
    * If we end up with too few inactive pages, we wake
    @@ -264,7 +274,7 @@
    age_page_up(page);
    if (inactive_shortage() > inactive_target / 2 && free_shortage())
    wakeup_kswapd(0);
    -not_found:
    +
    return page;
    }

    diff -Nur --exclude-from=exclude linux.orig/mm/swap_state.c linux/mm/swap_state.c
    --- linux.orig/mm/swap_state.c Mon Dec 4 19:22:02 2000
    +++ linux/mm/swap_state.c Thu Dec 21 04:23:47 2000
    @@ -5,6 +5,8 @@
    * Swap reorganised 29.12.95, Stephen Tweedie
    *
    * Rewritten to use page cache, (C) 1998 Stephen Tweedie
    + *
    + * 21/12/2000 Added swap write clustering. Marcelo Tosatti
    */

    #include <linux/mm.h>
    @@ -17,9 +19,95 @@

    #include <asm/pgtable.h>

    +static inline struct page * swap_page_dirty(unsigned long, unsigned long, struct swap_info_struct *);
    +
    +#define SWAP_WRITE_CLUSTER (1 << page_cluster)
    +
    static int swap_writepage(struct page *page)
    {
    - rw_swap_page(WRITE, page, 0);
    + unsigned long page_offset, curr, offset, i, type;
    + struct swap_info_struct *swap;
    + swp_entry_t entry;
    + struct page *cpages[SWAP_WRITE_CLUSTER*2];
    + int count, first;
    +
    + entry.val = page->index;
    +
    + type = SWP_TYPE(entry);
    +
    + swap = &swap_info[type];
    +
    + /* If swap area is not a real device, do not try to write cluster. */
    + if(!swap->swap_device) {
    + rw_swap_page(WRITE, page, 0);
    + return 0;
    + }
    +
    + page_offset = offset = SWP_OFFSET(entry);
    + cpages[SWAP_WRITE_CLUSTER] = page;
    + count = 1;
    + first = SWAP_WRITE_CLUSTER;
    + curr = 1;
    +
    + spin_lock(&pagecache_lock);
    + swap_device_lock(swap);
    +
    + /*
    + * Search for clusterable dirty swap pages.
    + */
    +
    + while (count < SWAP_WRITE_CLUSTER) {
    + struct page *p = NULL;
    +
    + if(offset <= 0)
    + break;
    +
    + offset = page_offset - curr;
    + p = swap_page_dirty(offset, type, swap);
    +
    + if(!p)
    + break;
    +
    + cpages[--first] = p;
    +
    + ClearPageDirty(p);
    + curr++;
    + count++;
    + }
    +
    + curr = 1;
    +
    + while (count < SWAP_WRITE_CLUSTER) {
    + struct page *p = NULL;
    + offset = page_offset + curr;
    +
    + if(offset >= swap->max)
    + break;
    +
    + p = swap_page_dirty(offset, type, swap);
    + if(!p)
    + break;
    +
    + cpages[first + count] = p;
    + ClearPageDirty(p);
    + curr++;
    + count++;
    + }
    +
    + swap_device_unlock(swap);
    + spin_unlock(&pagecache_lock);
    +
    + /* Now write out everything we were able to cluster */
    +
    + for(i=0; i<count; i++) {
    + int pos = first + i;
    + rw_swap_page(WRITE, cpages[pos], 0);
    +
    + /* If the page is a clustered one, decrement its counter */
    + if(pos != SWAP_WRITE_CLUSTER)
    + page_cache_release(cpages[pos]);
    + }
    +
    return 0;
    }

    @@ -36,6 +124,43 @@
    0, /* nrpages */
    &swap_aops,
    };
    +
    +static inline struct page * swap_page_dirty(unsigned long offset, unsigned long type,
    + struct swap_info_struct *swapdev)
    +{
    + struct page *page, **hash;
    + swp_entry_t entry;
    + unsigned long index;
    +
    + entry = SWP_ENTRY(type, offset);
    +
    + index = entry.val;
    +
    + if(!swapdev->swap_map[offset])
    + return NULL;
    +
    + if(swapdev->swap_map[offset] == SWAP_MAP_BAD)
    + return NULL;
    +
    + hash = page_hash(&swapper_space, index);
    +
    + page = ___find_page_nolock(&swapper_space, index, *hash);
    +
    + if(!page)
    + return NULL;
    +
    + if(TryLockPage(page))
    + return NULL;
    +
    + page_cache_get(page);
    +
    + if(PageDirty(page) && PageSwapCache(page))
    + return page;
    +
    + UnlockPage(page);
    + page_cache_release(page);
    + return NULL;
    +}

    #ifdef SWAP_CACHE_INFO
    unsigned long swap_cache_add_total;

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 12:52    [W:0.035 / U:31.732 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site