root/mm/page_io.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rw_swap_page
  2. swap_after_unlock_page
  3. ll_rw_page

   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/segment.h> /* for memcpy_to/fromfs */
  27 #include <asm/bitops.h>
  28 #include <asm/pgtable.h>
  29 
  30 static 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  */
  44 void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 (set_bit(offset,p->swap_lockmap))
  71                 sleep_on(&lock_queue);
  72         if (rw == READ)
  73                 kstat.pswpin++;
  74         else
  75                 kstat.pswpout++;
  76         page = mem_map + MAP_NR(buf);
  77         wait_on_page(page);
  78         if (p->swap_device) {
  79                 if (!wait) {
  80                         page->count++;
  81                         set_bit(PG_free_after, &page->flags);
  82                         set_bit(PG_decr_after, &page->flags);
  83                         set_bit(PG_swap_unlock_after, &page->flags);
  84                         page->swap_unlock_entry = entry;
  85                         nr_async_pages++;
  86                 }
  87                 ll_rw_page(rw,p->swap_device,offset,buf);
  88                 if (!wait)
  89                         return;
  90                 wait_on_page(page);
  91         } else if (p->swap_file) {
  92                 struct inode *swapf = p->swap_file;
  93                 unsigned int zones[PAGE_SIZE/512];
  94                 int i;
  95                 if (swapf->i_op->bmap == NULL
  96                         && swapf->i_op->smap != NULL){
  97                         /*
  98                                 With MsDOS, we use msdos_smap which return
  99                                 a sector number (not a cluster or block number).
 100                                 It is a patch to enable the UMSDOS project.
 101                                 Other people are working on better solution.
 102 
 103                                 It sounds like ll_rw_swap_file defined
 104                                 it operation size (sector size) based on
 105                                 PAGE_SIZE and the number of block to read.
 106                                 So using bmap or smap should work even if
 107                                 smap will require more blocks.
 108                         */
 109                         int j;
 110                         unsigned int block = offset << 3;
 111 
 112                         for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
 113                                 if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
 114                                         printk("rw_swap_page: bad swap file\n");
 115                                         return;
 116                                 }
 117                         }
 118                 }else{
 119                         int j;
 120                         unsigned int block = offset
 121                                 << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
 122 
 123                         for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
 124                                 if (!(zones[i] = bmap(swapf,block++))) {
 125                                         printk("rw_swap_page: bad swap file\n");
 126                                 }
 127                 }
 128                 ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
 129         } else
 130                 printk("rw_swap_page: no swap file or device\n");
 131         if (offset && !clear_bit(offset,p->swap_lockmap))
 132                 printk("rw_swap_page: lock already cleared\n");
 133         wake_up(&lock_queue);
 134 }
 135 
 136 /* This is run when asynchronous page I/O has completed. */
 137 void swap_after_unlock_page (unsigned long entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139         unsigned long type, offset;
 140         struct swap_info_struct * p;
 141 
 142         type = SWP_TYPE(entry);
 143         if (type >= nr_swapfiles) {
 144                 printk("swap_after_unlock_page: bad swap-device\n");
 145                 return;
 146         }
 147         p = &swap_info[type];
 148         offset = SWP_OFFSET(entry);
 149         if (offset >= p->max) {
 150                 printk("swap_after_unlock_page: weirdness\n");
 151                 return;
 152         }
 153         if (!clear_bit(offset,p->swap_lockmap))
 154                 printk("swap_after_unlock_page: lock already cleared\n");
 155         wake_up(&lock_queue);
 156 }
 157 
 158 /*
 159  * Swap partitions are now read via brw_page.  ll_rw_page is an
 160  * asynchronous function now --- we must call wait_on_page afterwards
 161  * if synchronous IO is required.  
 162  */
 163 void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         int block = page;
 166 
 167         switch (rw) {
 168                 case READ:
 169                         break;
 170                 case WRITE:
 171                         if (is_read_only(dev)) {
 172                                 printk("Can't page to read-only device %s\n",
 173                                         kdevname(dev));
 174                                 return;
 175                         }
 176                         break;
 177                 default:
 178                         panic("ll_rw_page: bad block dev cmd, must be R/W");
 179         }
 180         if (set_bit(PG_locked, &mem_map[MAP_NR(buffer)].flags))
 181                 panic ("ll_rw_page: page already locked");
 182         brw_page(rw, (unsigned long) buffer, dev, &block, PAGE_SIZE, 0);
 183 }

/* [previous][next][first][last][top][bottom][index][help] */