root/mm/swap.c

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

DEFINITIONS

This source file includes following definitions.
  1. rw_swap_page
  2. get_swap_page
  3. swap_free
  4. swap_in
  5. try_to_swap_out
  6. swap_out
  7. get_free_page
  8. sys_swapon

   1 /*
   2  *  linux/mm/swap.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  * This file should contain most things doing the swapping from/to disk.
   9  * Started 18.12.91
  10  */
  11 
  12 #include <linux/mm.h>
  13 #include <linux/sched.h>
  14 #include <linux/head.h>
  15 #include <linux/kernel.h>
  16 #include <linux/errno.h>
  17 #include <linux/string.h>
  18 #include <linux/stat.h>
  19 
  20 static int lowest_bit = 0;
  21 static int highest_bit = 0;
  22 
  23 /*
  24  * The following are used to make sure we don't thrash too much...
  25  */
  26 #define NR_LAST_FREE_PAGES 32
  27 static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
  28 
  29 #define SWAP_BITS (4096<<3)
  30 
  31 #define bitop(name,op) \
  32 static inline int name(char * addr,unsigned int nr) \
  33 { \
  34 int __res; \
  35 __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
  36 :"=g" (__res) \
  37 :"r" (nr),"m" (*(addr)),"0" (0)); \
  38 return __res; \
  39 }
  40 
  41 bitop(bit,"")
  42 bitop(setbit,"s")
  43 bitop(clrbit,"r")
  44 
  45 static char * swap_bitmap = NULL;
  46 static char * swap_lockmap = NULL;
  47 unsigned int swap_device = 0;
  48 struct inode * swap_file = NULL;
  49 
  50 void rw_swap_page(int rw, unsigned int nr, char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         static struct wait_queue * lock_queue = NULL;
  53 
  54         if (!swap_lockmap) {
  55                 printk("No swap lock-map\n");
  56                 return;
  57         }
  58         while (setbit(swap_lockmap,nr))
  59                 sleep_on(&lock_queue);
  60         if (swap_device) {
  61                 ll_rw_page(rw,swap_device,nr,buf);
  62         } else if (swap_file) {
  63                 unsigned int zones[4];
  64                 unsigned int block = nr << 2;
  65                 int i;
  66 
  67                 for (i = 0; i < 4; i++)
  68                         if (!(zones[i] = bmap(swap_file,block++))) {
  69                                 printk("rw_swap_page: bad swap file\n");
  70                                 return;
  71                         }
  72                 ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
  73         } else
  74                 printk("re_swap_page: no swap file or device\n");
  75         if (!clrbit(swap_lockmap,nr))
  76                 printk("rw_swap_page: lock already cleared\n");
  77         wake_up(&lock_queue);
  78 }
  79 
  80 static unsigned int get_swap_page(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         unsigned int nr;
  83 
  84         if (!swap_bitmap)
  85                 return 0;
  86         for (nr = lowest_bit; nr <= highest_bit ; nr++)
  87                 if (clrbit(swap_bitmap,nr)) {
  88                         if (nr == highest_bit)
  89                                 highest_bit--;
  90                         return lowest_bit = nr;
  91                 }
  92         return 0;
  93 }
  94 
  95 void swap_free(unsigned int swap_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         if (!swap_nr)
  98                 return;
  99         if (swap_bitmap && swap_nr < SWAP_BITS) {
 100                 if (swap_nr < lowest_bit)
 101                         lowest_bit = swap_nr;
 102                 if (swap_nr > highest_bit)
 103                         highest_bit = swap_nr;
 104                 if (!setbit(swap_bitmap,swap_nr))
 105                         return;
 106         }
 107         printk("swap_free: swap-space bitmap bad (bit %d)\n",swap_nr);
 108         return;
 109 }
 110 
 111 void swap_in(unsigned long *table_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         unsigned long swap_nr;
 114         unsigned long page;
 115 
 116         swap_nr = *table_ptr;
 117         if (1 & swap_nr) {
 118                 printk("trying to swap in present page\n\r");
 119                 return;
 120         }
 121         if (!swap_nr) {
 122                 printk("No swap page in swap_in\n\r");
 123                 return;
 124         }
 125         if (!swap_bitmap) {
 126                 printk("Trying to swap in without swap bit-map");
 127                 *table_ptr = BAD_PAGE;
 128                 return;
 129         }
 130         page = get_free_page(GFP_KERNEL);
 131         if (!page) {
 132                 oom(current);
 133                 page = BAD_PAGE;
 134         } else  
 135                 read_swap_page(swap_nr>>1, (char *) page);
 136         if (*table_ptr != swap_nr) {
 137                 free_page(page);
 138                 return;
 139         }
 140         swap_free(swap_nr>>1);
 141         *table_ptr = page | (PAGE_DIRTY | 7);
 142 }
 143 
 144 int try_to_swap_out(unsigned long * table_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         int i;
 147         unsigned long page;
 148         unsigned long swap_nr;
 149 
 150         page = *table_ptr;
 151         if (!(PAGE_PRESENT & page))
 152                 return 0;
 153         if (page < low_memory || page >= high_memory)
 154                 return 0;
 155         for (i = 0; i < NR_LAST_FREE_PAGES; i++)
 156                 if (last_free_pages[i] == (page & 0xfffff000))
 157                         return 0;
 158         if (PAGE_DIRTY & page) {
 159                 page &= 0xfffff000;
 160                 if (mem_map[MAP_NR(page)] != 1)
 161                         return 0;
 162                 if (!(swap_nr = get_swap_page()))
 163                         return 0;
 164                 *table_ptr = swap_nr<<1;
 165                 invalidate();
 166                 write_swap_page(swap_nr, (char *) page);
 167                 free_page(page);
 168                 return 1;
 169         }
 170         page &= 0xfffff000;
 171         *table_ptr = 0;
 172         invalidate();
 173         free_page(page);
 174         return 1;
 175 }
 176 
 177 /*
 178  * We never page the pages in task[0] - kernel memory.
 179  * We page all other pages.
 180  */
 181 #define FIRST_VM_PAGE (TASK_SIZE>>12)
 182 #define LAST_VM_PAGE (1024*1024)
 183 #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
 184 
 185 /*
 186  * Go through the page tables, searching for a user page that
 187  * we can swap out.
 188  *
 189  * We now check that the process is swappable (normally only 'init'
 190  * is un-swappable), allowing high-priority processes which cannot be
 191  * swapped out (things like user-level device drivers (Not implemented)).
 192  */
 193 int swap_out(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         static int dir_entry = 1024;
 196         static int page_entry = -1;
 197         int counter = VM_PAGES;
 198         int pg_table;
 199         struct task_struct * p;
 200 
 201 check_dir:
 202         if (counter < 0)
 203                 goto no_swap;
 204         if (dir_entry >= 1024)
 205                 dir_entry = FIRST_VM_PAGE>>10;
 206         if (!(p = task[dir_entry >> 4])) {
 207                 counter -= 1024;
 208                 dir_entry++;
 209                 goto check_dir;
 210         }
 211         if (!(1 & (pg_table = pg_dir[dir_entry]))) {
 212                 if (pg_table) {
 213                         printk("bad page-table at pg_dir[%d]: %08x\n\r",
 214                                 dir_entry,pg_table);
 215                         pg_dir[dir_entry] = 0;
 216                 }
 217                 counter -= 1024;
 218                 dir_entry++;
 219                 goto check_dir;
 220         }
 221         pg_table &= 0xfffff000;
 222 check_table:
 223         if (counter < 0)
 224                 goto no_swap;
 225         counter--;
 226         page_entry++;
 227         if (page_entry >= 1024) {
 228                 page_entry = -1;
 229                 dir_entry++;
 230                 goto check_dir;
 231         }
 232         if (p->swappable && try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
 233                 p->rss--;
 234                 dir_entry++;
 235                 return 1;
 236         }
 237         goto check_table;
 238 no_swap:
 239         printk("Out of swap-memory\n\r");
 240         return 0;
 241 }
 242 
 243 /*
 244  * Get physical address of first (actually last :-) free page, and mark it
 245  * used. If no free pages left, return 0.
 246  */
 247 unsigned long get_free_page(int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249         unsigned long result;
 250         static unsigned long index = 0;
 251 
 252 repeat:
 253         __asm__("std ; repne ; scasb\n\t"
 254                 "jne 1f\n\t"
 255                 "movb $1,1(%%edi)\n\t"
 256                 "sall $12,%%ecx\n\t"
 257                 "addl %2,%%ecx\n\t"
 258                 "movl %%ecx,%%edx\n\t"
 259                 "movl $1024,%%ecx\n\t"
 260                 "leal 4092(%%edx),%%edi\n\t"
 261                 "rep ; stosl\n\t"
 262                 "movl %%edx,%%eax\n"
 263                 "1:\tcld"
 264                 :"=a" (result)
 265                 :"0" (0),"b" (low_memory),"c" (paging_pages),
 266                 "D" (mem_map+paging_pages-1)
 267                 :"di","cx","dx");
 268         if (result >= high_memory)
 269                 goto repeat;
 270         if ((result && result < low_memory) || (result & 0xfff)) {
 271                 printk("weird result: %08x\n",result);
 272                 result = 0;
 273         }
 274         if (result) {
 275                 --nr_free_pages;
 276                 if (index >= NR_LAST_FREE_PAGES)
 277                         index = 0;
 278                 last_free_pages[index] = result;
 279                 index++;
 280                 return result;
 281         }
 282         if (nr_free_pages) {
 283                 printk("Damn. mm_free_page count is off by %d\r\n",
 284                         nr_free_pages);
 285                 nr_free_pages = 0;
 286         }
 287         if (priority <= GFP_BUFFER)
 288                 return 0;
 289         if (shrink_buffers()) {
 290                 schedule();
 291                 goto repeat;
 292         }
 293         if (swap_out()) {
 294                 schedule();
 295                 goto repeat;
 296         }
 297         return 0;
 298 }
 299 
 300 /*
 301  * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
 302  *
 303  * The swapon system call
 304  */
 305 int sys_swapon(const char * specialfile)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         struct inode * swap_inode;
 308         char * tmp;
 309         int i,j;
 310 
 311         if (!suser())
 312                 return -EPERM;
 313         if (!(swap_inode  = namei(specialfile)))
 314                 return -ENOENT;
 315         if (swap_file || swap_device || swap_bitmap || swap_lockmap) {
 316                 iput(swap_inode);
 317                 return -EBUSY;
 318         }
 319         if (S_ISBLK(swap_inode->i_mode)) {
 320                 swap_device = swap_inode->i_rdev;
 321                 iput(swap_inode);
 322         } else if (S_ISREG(swap_inode->i_mode))
 323                 swap_file = swap_inode;
 324         else {
 325                 iput(swap_inode);
 326                 return -EINVAL;
 327         }
 328         tmp = (char *) get_free_page(GFP_USER);
 329         swap_lockmap = (char *) get_free_page(GFP_USER);
 330         if (!tmp || !swap_lockmap) {
 331                 printk("Unable to start swapping: out of memory :-)\n");
 332                 free_page((long) tmp);
 333                 free_page((long) swap_lockmap);
 334                 iput(swap_file);
 335                 swap_device = 0;
 336                 swap_file = NULL;
 337                 swap_bitmap = NULL;
 338                 swap_lockmap = NULL;
 339                 return -ENOMEM;
 340         }
 341         read_swap_page(0,tmp);
 342         if (strncmp("SWAP-SPACE",tmp+4086,10)) {
 343                 printk("Unable to find swap-space signature\n\r");
 344                 free_page((long) tmp);
 345                 free_page((long) swap_lockmap);
 346                 iput(swap_file);
 347                 swap_device = 0;
 348                 swap_file = NULL;
 349                 swap_bitmap = NULL;
 350                 swap_lockmap = NULL;
 351                 return -EINVAL;
 352         }
 353         memset(tmp+4086,0,10);
 354         j = 0;
 355         lowest_bit = 0;
 356         highest_bit = 0;
 357         for (i = 1 ; i < SWAP_BITS ; i++)
 358                 if (bit(tmp,i)) {
 359                         if (!lowest_bit)
 360                                 lowest_bit = i;
 361                         highest_bit = i;
 362                         j++;
 363                 }
 364         if (!j) {
 365                 printk("Empty swap-file\n");
 366                 free_page((long) tmp);
 367                 free_page((long) swap_lockmap);
 368                 iput(swap_file);
 369                 swap_device = 0;
 370                 swap_file = NULL;
 371                 swap_bitmap = NULL;
 372                 swap_lockmap = NULL;
 373                 return -EINVAL;
 374         }
 375         swap_bitmap = tmp;
 376         printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
 377         return 0;
 378 }

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