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/writeback.h>
  20#include <asm/pgtable.h>
  21
  22static struct bio *get_swap_bio(int gfp_flags, pgoff_t index,
  23                                struct page *page, bio_end_io_t end_io)
  24{
  25        struct bio *bio;
  26
  27        bio = bio_alloc(gfp_flags, 1);
  28        if (bio) {
  29                struct swap_info_struct *sis;
  30                swp_entry_t entry = { .val = index, };
  31
  32                sis = get_swap_info_struct(swp_type(entry));
  33                bio->bi_sector = map_swap_page(sis, swp_offset(entry)) *
  34                                        (PAGE_SIZE >> 9);
  35                bio->bi_bdev = sis->bdev;
  36                bio->bi_io_vec[0].bv_page = page;
  37                bio->bi_io_vec[0].bv_len = PAGE_SIZE;
  38                bio->bi_io_vec[0].bv_offset = 0;
  39                bio->bi_vcnt = 1;
  40                bio->bi_idx = 0;
  41                bio->bi_size = PAGE_SIZE;
  42                bio->bi_end_io = end_io;
  43        }
  44        return bio;
  45}
  46
  47static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err)
  48{
  49        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  50        struct page *page = bio->bi_io_vec[0].bv_page;
  51
  52        if (bio->bi_size)
  53                return 1;
  54
  55        if (!uptodate)
  56                SetPageError(page);
  57        end_page_writeback(page);
  58        bio_put(bio);
  59        return 0;
  60}
  61
  62static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
  63{
  64        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
  65        struct page *page = bio->bi_io_vec[0].bv_page;
  66
  67        if (bio->bi_size)
  68                return 1;
  69
  70        if (!uptodate) {
  71                SetPageError(page);
  72                ClearPageUptodate(page);
  73        } else {
  74                SetPageUptodate(page);
  75        }
  76        unlock_page(page);
  77        bio_put(bio);
  78        return 0;
  79}
  80
  81/*
  82 * We may have stale swap cache pages in memory: notice
  83 * them here and get rid of the unnecessary final write.
  84 */
  85int swap_writepage(struct page *page, struct writeback_control *wbc)
  86{
  87        struct bio *bio;
  88        int ret = 0, rw = WRITE;
  89
  90        if (remove_exclusive_swap_page(page)) {
  91                unlock_page(page);
  92                goto out;
  93        }
  94        bio = get_swap_bio(GFP_NOIO, page->private, page, end_swap_bio_write);
  95        if (bio == NULL) {
  96                set_page_dirty(page);
  97                unlock_page(page);
  98                ret = -ENOMEM;
  99                goto out;
 100        }
 101        if (wbc->sync_mode == WB_SYNC_ALL)
 102                rw |= (1 << BIO_RW_SYNC);
 103        inc_page_state(pswpout);
 104        set_page_writeback(page);
 105        unlock_page(page);
 106        submit_bio(rw, 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        BUG_ON(!PageLocked(page));
 117        ClearPageUptodate(page);
 118        bio = get_swap_bio(GFP_KERNEL, page->private, page, end_swap_bio_read);
 119        if (bio == NULL) {
 120                unlock_page(page);
 121                ret = -ENOMEM;
 122                goto out;
 123        }
 124        inc_page_state(pswpin);
 125        submit_bio(READ, bio);
 126out:
 127        return ret;
 128}
 129
 130#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK)
 131/*
 132 * A scruffy utility function to read or write an arbitrary swap page
 133 * and wait on the I/O.  The caller must have a ref on the page.
 134 *
 135 * We use end_swap_bio_read() even for writes, because it happens to do what
 136 * we want.
 137 */
 138int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page)
 139{
 140        struct bio *bio;
 141        int ret = 0;
 142
 143        lock_page(page);
 144
 145        bio = get_swap_bio(GFP_KERNEL, entry.val, page, end_swap_bio_read);
 146        if (bio == NULL) {
 147                unlock_page(page);
 148                ret = -ENOMEM;
 149                goto out;
 150        }
 151
 152        submit_bio(rw | (1 << BIO_RW_SYNC), bio);
 153        wait_on_page_locked(page);
 154
 155        if (!PageUptodate(page) || PageError(page))
 156                ret = -EIO;
 157out:
 158        return ret;
 159}
 160#endif
 161
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.