lkml.org 
[lkml]   [2012]   [Apr]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 05/11] mm: swap: Implement generic handler for swap_activate
    Date
    The version of swap_activate introduced is sufficient for swap-over-NFS
    but would not provide enough information to implement a generic handler.
    This patch shuffles things slightly to ensure the same information is
    available for aops->swap_activate() as is available to the core.

    No functionality change.

    Signed-off-by: Mel Gorman <mgorman@suse.de>
    ---
    include/linux/fs.h | 7 ++--
    include/linux/swap.h | 5 +++
    mm/page_io.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
    mm/swapfile.c | 91 +++----------------------------------------------
    4 files changed, 107 insertions(+), 88 deletions(-)
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index 0dcd1e8..5a71145 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -587,6 +587,8 @@ typedef struct {
    typedef int (*read_actor_t)(read_descriptor_t *, struct page *,
    unsigned long, unsigned long);

    +struct swap_info_struct;
    +
    struct address_space_operations {
    int (*writepage)(struct page *page, struct writeback_control *wbc);
    int (*readpage)(struct file *, struct page *);
    @@ -628,8 +630,9 @@ struct address_space_operations {
    int (*error_remove_page)(struct address_space *, struct page *);

    /* swapfile support */
    - int (*swap_activate)(struct file *file);
    - int (*swap_deactivate)(struct file *file);
    + int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
    + sector_t *span);
    + void (*swap_deactivate)(struct file *file);
    };

    extern const struct address_space_operations empty_aops;
    diff --git a/include/linux/swap.h b/include/linux/swap.h
    index 6b40350..4ab2276 100644
    --- a/include/linux/swap.h
    +++ b/include/linux/swap.h
    @@ -320,6 +320,11 @@ extern int swap_writepage(struct page *page, struct writeback_control *wbc);
    extern int swap_set_page_dirty(struct page *page);
    extern void end_swap_bio_read(struct bio *bio, int err);

    +int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
    + unsigned long nr_pages, sector_t start_block);
    +int generic_swapfile_activate(struct swap_info_struct *, struct file *,
    + sector_t *);
    +
    /* linux/mm/swap_state.c */
    extern struct address_space swapper_space;
    #define total_swapcache_pages swapper_space.nrpages
    diff --git a/mm/page_io.c b/mm/page_io.c
    index 2a7a4c1..0a7492c 100644
    --- a/mm/page_io.c
    +++ b/mm/page_io.c
    @@ -86,6 +86,98 @@ void end_swap_bio_read(struct bio *bio, int err)
    bio_put(bio);
    }

    +int generic_swapfile_activate(struct swap_info_struct *sis,
    + struct file *swap_file,
    + sector_t *span)
    +{
    + struct address_space *mapping = swap_file->f_mapping;
    + struct inode *inode = mapping->host;
    + unsigned blocks_per_page;
    + unsigned long page_no;
    + unsigned blkbits;
    + sector_t probe_block;
    + sector_t last_block;
    + sector_t lowest_block = -1;
    + sector_t highest_block = 0;
    + int nr_extents = 0;
    + int ret;
    +
    + blkbits = inode->i_blkbits;
    + blocks_per_page = PAGE_SIZE >> blkbits;
    +
    + /*
    + * Map all the blocks into the extent list. This code doesn't try
    + * to be very smart.
    + */
    + probe_block = 0;
    + page_no = 0;
    + last_block = i_size_read(inode) >> blkbits;
    + while ((probe_block + blocks_per_page) <= last_block &&
    + page_no < sis->max) {
    + unsigned block_in_page;
    + sector_t first_block;
    +
    + first_block = bmap(inode, probe_block);
    + if (first_block == 0)
    + goto bad_bmap;
    +
    + /*
    + * It must be PAGE_SIZE aligned on-disk
    + */
    + if (first_block & (blocks_per_page - 1)) {
    + probe_block++;
    + goto reprobe;
    + }
    +
    + for (block_in_page = 1; block_in_page < blocks_per_page;
    + block_in_page++) {
    + sector_t block;
    +
    + block = bmap(inode, probe_block + block_in_page);
    + if (block == 0)
    + goto bad_bmap;
    + if (block != first_block + block_in_page) {
    + /* Discontiguity */
    + probe_block++;
    + goto reprobe;
    + }
    + }
    +
    + first_block >>= (PAGE_SHIFT - blkbits);
    + if (page_no) { /* exclude the header page */
    + if (first_block < lowest_block)
    + lowest_block = first_block;
    + if (first_block > highest_block)
    + highest_block = first_block;
    + }
    +
    + /*
    + * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
    + */
    + ret = add_swap_extent(sis, page_no, 1, first_block);
    + if (ret < 0)
    + goto out;
    + nr_extents += ret;
    + page_no++;
    + probe_block += blocks_per_page;
    +reprobe:
    + continue;
    + }
    + ret = nr_extents;
    + *span = 1 + highest_block - lowest_block;
    + if (page_no == 0)
    + page_no = 1; /* force Empty message */
    + sis->max = page_no;
    + sis->pages = page_no - 1;
    + sis->highest_bit = page_no - 1;
    +out:
    + return ret;
    +bad_bmap:
    + printk(KERN_ERR "swapon: swapfile has holes\n");
    + ret = -EINVAL;
    + goto out;
    +}
    +
    /*
    * We may have stale swap cache pages in memory: notice
    * them here and get rid of the unnecessary final write.
    diff --git a/mm/swapfile.c b/mm/swapfile.c
    index fe2ed44..80b3415 100644
    --- a/mm/swapfile.c
    +++ b/mm/swapfile.c
    @@ -1358,7 +1358,7 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
    *
    * This function rather assumes that it is called in ascending page order.
    */
    -static int
    +int
    add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
    unsigned long nr_pages, sector_t start_block)
    {
    @@ -1434,106 +1434,25 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
    struct file *swap_file = sis->swap_file;
    struct address_space *mapping = swap_file->f_mapping;
    struct inode *inode = mapping->host;
    - unsigned blocks_per_page;
    - unsigned long page_no;
    - unsigned blkbits;
    - sector_t probe_block;
    - sector_t last_block;
    - sector_t lowest_block = -1;
    - sector_t highest_block = 0;
    - int nr_extents = 0;
    int ret;

    if (S_ISBLK(inode->i_mode)) {
    ret = add_swap_extent(sis, 0, sis->max, 0);
    *span = sis->pages;
    - goto out;
    + return ret;
    }

    if (mapping->a_ops->swap_activate) {
    - ret = mapping->a_ops->swap_activate(swap_file);
    + ret = mapping->a_ops->swap_activate(sis, swap_file, span);
    if (!ret) {
    sis->flags |= SWP_FILE;
    ret = add_swap_extent(sis, 0, sis->max, 0);
    *span = sis->pages;
    }
    - goto out;
    + return ret;
    }

    - blkbits = inode->i_blkbits;
    - blocks_per_page = PAGE_SIZE >> blkbits;
    -
    - /*
    - * Map all the blocks into the extent list. This code doesn't try
    - * to be very smart.
    - */
    - probe_block = 0;
    - page_no = 0;
    - last_block = i_size_read(inode) >> blkbits;
    - while ((probe_block + blocks_per_page) <= last_block &&
    - page_no < sis->max) {
    - unsigned block_in_page;
    - sector_t first_block;
    -
    - first_block = bmap(inode, probe_block);
    - if (first_block == 0)
    - goto bad_bmap;
    -
    - /*
    - * It must be PAGE_SIZE aligned on-disk
    - */
    - if (first_block & (blocks_per_page - 1)) {
    - probe_block++;
    - goto reprobe;
    - }
    -
    - for (block_in_page = 1; block_in_page < blocks_per_page;
    - block_in_page++) {
    - sector_t block;
    -
    - block = bmap(inode, probe_block + block_in_page);
    - if (block == 0)
    - goto bad_bmap;
    - if (block != first_block + block_in_page) {
    - /* Discontiguity */
    - probe_block++;
    - goto reprobe;
    - }
    - }
    -
    - first_block >>= (PAGE_SHIFT - blkbits);
    - if (page_no) { /* exclude the header page */
    - if (first_block < lowest_block)
    - lowest_block = first_block;
    - if (first_block > highest_block)
    - highest_block = first_block;
    - }
    -
    - /*
    - * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
    - */
    - ret = add_swap_extent(sis, page_no, 1, first_block);
    - if (ret < 0)
    - goto out;
    - nr_extents += ret;
    - page_no++;
    - probe_block += blocks_per_page;
    -reprobe:
    - continue;
    - }
    - ret = nr_extents;
    - *span = 1 + highest_block - lowest_block;
    - if (page_no == 0)
    - page_no = 1; /* force Empty message */
    - sis->max = page_no;
    - sis->pages = page_no - 1;
    - sis->highest_bit = page_no - 1;
    -out:
    - return ret;
    -bad_bmap:
    - printk(KERN_ERR "swapon: swapfile has holes\n");
    - ret = -EINVAL;
    - goto out;
    + return generic_swapfile_activate(sis, swap_file, span);
    }

    static void enable_swap_info(struct swap_info_struct *p, int prio,
    --
    1.7.9.2


    \
     
     \ /
      Last update: 2012-04-16 14:23    [from the cache]
    ©2003-2014 Jasper Spaans. hosted at Digital Ocean