linux-old/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 */
  10
  11#include <linux/mm.h>
  12#include <linux/sched.h>
  13#include <linux/head.h>
  14#include <linux/kernel.h>
  15#include <linux/kernel_stat.h>
  16#include <linux/errno.h>
  17#include <linux/string.h>
  18#include <linux/stat.h>
  19#include <linux/swap.h>
  20#include <linux/fs.h>
  21#include <linux/locks.h>
  22#include <linux/swapctl.h>
  23
  24#include <asm/dma.h>
  25#include <asm/system.h> /* for cli()/sti() */
  26#include <asm/uaccess.h> /* for copy_to/from_user */
  27#include <asm/bitops.h>
  28#include <asm/pgtable.h>
  29
  30static struct wait_queue * lock_queue = NULL;
  31
  32/*
  33 * Reads or writes a swap page.
  34 * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
  35 *
  36 * Important prevention of race condition: The first thing we do is set a lock
  37 * on this swap page, which lasts until I/O completes. This way a
  38 * write_swap_page(entry) immediately followed by a read_swap_page(entry)
  39 * on the same entry will first complete the write_swap_page(). Fortunately,
  40 * not more than one write_swap_page() request can be pending per entry. So
  41 * all races the caller must catch are: multiple read_swap_page() requests
  42 * on the same entry.
  43 */
  44void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
  45{
  46        unsigned long type, offset;
  47        struct swap_info_struct * p;
  48        struct page *page;
  49        
  50        type = SWP_TYPE(entry);
  51        if (type >= nr_swapfiles) {
  52                printk("Internal error: bad swap-device\n");
  53                return;
  54        }
  55        p = &swap_info[type];
  56        offset = SWP_OFFSET(entry);
  57        if (offset >= p->max) {
  58                printk("rw_swap_page: weirdness\n");
  59                return;
  60        }
  61        if (p->swap_map && !p->swap_map[offset]) {
  62                printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
  63                return;
  64        }
  65        if (!(p->flags & SWP_USED)) {
  66                printk("Trying to swap to unused swap-device\n");
  67                return;
  68        }
  69        /* Make sure we are the only process doing I/O with this swap page. */
  70        while (test_and_set_bit(offset,p->swap_lockmap)) {
  71                run_task_queue(&tq_disk);
  72                sleep_on(&lock_queue);
  73        }
  74        if (rw == READ)
  75                kstat.pswpin++;
  76        else
  77                kstat.pswpout++;
  78        page = mem_map + MAP_NR(buf);
  79        atomic_inc(&page->count);
  80        wait_on_page(page);
  81        if (p->swap_device) {
  82                if (!wait) {
  83                        set_bit(PG_free_after, &page->flags);
  84                        set_bit(PG_decr_after, &page->flags);
  85                        set_bit(PG_swap_unlock_after, &page->flags);
  86                        /* swap-cache  shouldn't be set, but play safe */
  87                        PageClearSwapCache(page);
  88                        page->pg_swap_entry = entry;
  89                        atomic_inc(&nr_async_pages);
  90                }
  91                ll_rw_page(rw,p->swap_device,offset,buf);
  92                /*
  93                 * NOTE! We don't decrement the page count if we
  94                 * don't wait - that will happen asynchronously
  95                 * when the IO completes.
  96                 */
  97                if (!wait)
  98                        return;
  99                wait_on_page(page);
 100        } else if (p->swap_file) {
 101                struct inode *swapf = p->swap_file->d_inode;
 102                unsigned int zones[PAGE_SIZE/512];
 103                int i;
 104                if (swapf->i_op->bmap == NULL
 105                        && swapf->i_op->smap != NULL){
 106                        /*
 107                                With MsDOS, we use msdos_smap which return
 108                                a sector number (not a cluster or block number).
 109                                It is a patch to enable the UMSDOS project.
 110                                Other people are working on better solution.
 111
 112                                It sounds like ll_rw_swap_file defined
 113                                it operation size (sector size) based on
 114                                PAGE_SIZE and the number of block to read.
 115                                So using bmap or smap should work even if
 116                                smap will require more blocks.
 117                        */
 118                        int j;
 119                        unsigned int block = offset << 3;
 120
 121                        for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
 122                                if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
 123                                        printk("rw_swap_page: bad swap file\n");
 124                                        return;
 125                                }
 126                        }
 127                }else{
 128                        int j;
 129                        unsigned int block = offset
 130                                << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
 131
 132                        for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
 133                                if (!(zones[i] = bmap(swapf,block++))) {
 134                                        printk("rw_swap_page: bad swap file\n");
 135                                }
 136                }
 137                ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
 138        } else
 139                printk("rw_swap_page: no swap file or device\n");
 140        atomic_dec(&page->count);
 141        if (offset && !test_and_clear_bit(offset,p->swap_lockmap))
 142                printk("rw_swap_page: lock already cleared\n");
 143        wake_up(&lock_queue);
 144}
 145
 146/* This is run when asynchronous page I/O has completed. */
 147void swap_after_unlock_page (unsigned long entry)
 148{
 149        unsigned long type, offset;
 150        struct swap_info_struct * p;
 151
 152        type = SWP_TYPE(entry);
 153        if (type >= nr_swapfiles) {
 154                printk("swap_after_unlock_page: bad swap-device\n");
 155                return;
 156        }
 157        p = &swap_info[type];
 158        offset = SWP_OFFSET(entry);
 159        if (offset >= p->max) {
 160                printk("swap_after_unlock_page: weirdness\n");
 161                return;
 162        }
 163        if (!test_and_clear_bit(offset,p->swap_lockmap))
 164                printk("swap_after_unlock_page: lock already cleared\n");
 165        wake_up(&lock_queue);
 166}
 167
 168/*
 169 * Swap partitions are now read via brw_page.  ll_rw_page is an
 170 * asynchronous function now --- we must call wait_on_page afterwards
 171 * if synchronous IO is required.  
 172 */
 173void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
 174{
 175        int block = offset;
 176        struct page *page;
 177
 178        switch (rw) {
 179                case READ:
 180                        break;
 181                case WRITE:
 182                        if (is_read_only(dev)) {
 183                                printk("Can't page to read-only device %s\n",
 184                                        kdevname(dev));
 185                                return;
 186                        }
 187                        break;
 188                default:
 189                        panic("ll_rw_page: bad block dev cmd, must be R/W");
 190        }
 191        page = mem_map + MAP_NR(buffer);
 192        if (test_and_set_bit(PG_locked, &page->flags))
 193                panic ("ll_rw_page: page already locked");
 194        brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
 195}
 196
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.