linux-bk/mm/page_io.c
<<
>>
Prefs
   1/*
   2 *  linux/mm/page_io.c
   3 *
   4 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   5 *
   6 *  Swap reorganised 29.12.95, 
   7 *  Asynchronous swapping added 30.12.95. Stephen Tweedie
   8 *  Removed race in async swapping. 14.4.1996. Bruno Haible
   9 *  Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie
  10 *  Always use brw_page, life becomes simpler. 12 May 1998 Eric Biederman
  11 */
  12
  13#include <linux/mm.h>
  14#include <linux/kernel_stat.h>
  15#include <linux/pagemap.h>
  16#include <linux/swap.h>
  17#include <linux/bio.h>
  18#include <linux/swapops.h>
  19#include <linux/buffer_head.h>  /* for block_sync_page() */
  20#include <linux/mpage.h>
  21#include <asm/pgtable.h>
  22
  23static struct bio *
  24get_swap_bio(int gfp_flags, struct page *page, bio_end_io_t end_io)
  25{
  26        struct bio *bio;
  27
  28        bio = bio_alloc(gfp_flags, 1);
  29        if (bio) {
  30                struct swap_info_struct *sis;
  31                swp_entry_t entry;
  32
  33                entry.val = page->index;
  34                sis = get_swap_info_struct(swp_type(entry));
  35
  36                bio->bi_sector = map_swap_page(sis, swp_offset(entry)) *
  37                                        (PAGE_SIZE >> 9);
  38                bio->bi_bdev = sis->bdev;
  39                bio->bi_io_vec[0].bv_page = page;
  40                bio->bi_io_vec[0].bv_len = PAGE_SIZE;
  41                bio->bi_io_vec[0].bv_offset = 0;
  42                bio->bi_vcnt = 1;
  43                bio->bi_idx = 0;
  44                bio->bi_size = PAGE_SIZE;
  45                bio->bi_end_io = end_io;
  46        }
  47        return bio;
  48}
  49
  50static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err)
  51{
  52        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  53        struct page *page = bio->bi_io_vec[0].bv_page;
  54
  55        if (bio->bi_size)
  56                return 1;
  57
  58        if (!uptodate)
  59                SetPageError(page);
  60        end_page_writeback(page);
  61        bio_put(bio);
  62        return 0;
  63}
  64
  65static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
  66{
  67        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  68        struct page *page = bio->bi_io_vec[0].bv_page;
  69
  70        if (bio->bi_size)
  71                return 1;
  72
  73        if (!uptodate) {
  74                SetPageError(page);
  75                ClearPageUptodate(page);
  76        } else {
  77                SetPageUptodate(page);
  78        }
  79        unlock_page(page);
  80        bio_put(bio);
  81        return 0;
  82}
  83
  84/*
  85 * We may have stale swap cache pages in memory: notice
  86 * them here and get rid of the unnecessary final write.
  87 */
  88int swap_writepage(struct page *page)
  89{
  90        struct bio *bio;
  91        int ret = 0;
  92
  93        if (remove_exclusive_swap_page(page)) {
  94                unlock_page(page);
  95                goto out;
  96        }
  97        bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
  98        if (bio == NULL) {
  99                set_page_dirty(page);
 100                ret = -ENOMEM;
 101                goto out;
 102        }
 103        kstat.pswpout++;
 104        SetPageWriteback(page);
 105        unlock_page(page);
 106        submit_bio(WRITE, bio);
 107out:
 108        return ret;
 109}
 110
 111int swap_readpage(struct file *file, struct page *page)
 112{
 113        struct bio *bio;
 114        int ret = 0;
 115
 116        ClearPageUptodate(page);
 117        bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
 118        if (bio == NULL) {
 119                ret = -ENOMEM;
 120                goto out;
 121        }
 122        kstat.pswpin++;
 123        submit_bio(READ, bio);
 124out:
 125        return ret;
 126}
 127/*
 128 * swapper_space doesn't have a real inode, so it gets a special vm_writeback()
 129 * so we don't need swap special cases in generic_vm_writeback().
 130 *
 131 * Swap pages are !PageLocked and PageWriteback while under writeout so that
 132 * memory allocators will throttle against them.
 133 */
 134static int swap_vm_writeback(struct page *page, struct writeback_control *wbc)
 135{
 136        struct address_space *mapping = page->mapping;
 137
 138        unlock_page(page);
 139        return generic_writepages(mapping, wbc);
 140}
 141
 142struct address_space_operations swap_aops = {
 143        .vm_writeback   = swap_vm_writeback,
 144        .writepage      = swap_writepage,
 145        .readpage       = swap_readpage,
 146        .sync_page      = block_sync_page,
 147        .set_page_dirty = __set_page_dirty_nobuffers,
 148};
 149
 150/*
 151 * A scruffy utility function to read or write an arbitrary swap page
 152 * and wait on the I/O.
 153 */
 154int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page)
 155{
 156        int ret;
 157
 158        lock_page(page);
 159
 160        BUG_ON(page->mapping);
 161        page->mapping = &swapper_space;
 162        page->index = entry.val;
 163
 164        if (rw == READ) {
 165                ret = swap_readpage(NULL, page);
 166                wait_on_page_locked(page);
 167        } else {
 168                ret = swap_writepage(page);
 169                wait_on_page_writeback(page);
 170        }
 171        page->mapping = NULL;
 172        if (ret == 0 && (!PageUptodate(page) || PageError(page)))
 173                ret = -EIO;
 174        return ret;
 175}
 176
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.