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  *  (C) 1991  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 <errno.h>
  13 
  14 #include <linux/stat.h>
  15 #include <linux/mm.h>
  16 #include <linux/string.h>
  17 #include <linux/sched.h>
  18 #include <linux/head.h>
  19 #include <linux/kernel.h>
  20 
  21 #define SWAP_BITS (4096<<3)
  22 
  23 #define bitop(name,op) \
  24 static inline int name(char * addr,unsigned int nr) \
  25 { \
  26 int __res; \
  27 __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
  28 :"=g" (__res) \
  29 :"r" (nr),"m" (*(addr)),"0" (0)); \
  30 return __res; \
  31 }
  32 
  33 bitop(bit,"")
  34 bitop(setbit,"s")
  35 bitop(clrbit,"r")
  36 
  37 static char * swap_bitmap = NULL;
  38 unsigned int swap_device = 0;
  39 struct inode * swap_file = NULL;
  40 
  41 void rw_swap_page(int rw, unsigned int nr, char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  42 {
  43         unsigned int zones[4];
  44         int i;
  45 
  46         if (swap_device) {
  47                 ll_rw_page(rw,swap_device,nr,buf);
  48                 return;
  49         }
  50         if (swap_file) {
  51                 nr <<= 2;
  52                 for (i = 0; i < 4; i++)
  53                         if (!(zones[i] = bmap(swap_file,nr++))) {
  54                                 printk("rw_swap_page: bad swap file\n");
  55                                 return;
  56                         }
  57                 ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf);
  58                 return;
  59         }
  60         printk("ll_swap_page: no swap file or device\n");
  61 }
  62 
  63 /*
  64  * We never page the pages in task[0] - kernel memory.
  65  * We page all other pages.
  66  */
  67 #define FIRST_VM_PAGE (TASK_SIZE>>12)
  68 #define LAST_VM_PAGE (1024*1024)
  69 #define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
  70 
  71 static int get_swap_page(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         int nr;
  74 
  75         if (!swap_bitmap)
  76                 return 0;
  77         for (nr = 1; nr < SWAP_BITS ; nr++)
  78                 if (clrbit(swap_bitmap,nr))
  79                         return nr;
  80         return 0;
  81 }
  82 
  83 void swap_free(int swap_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         if (!swap_nr)
  86                 return;
  87         if (swap_bitmap && swap_nr < SWAP_BITS)
  88                 if (!setbit(swap_bitmap,swap_nr))
  89                         return;
  90         printk("swap_free: swap-space bitmap bad\n");
  91         return;
  92 }
  93 
  94 void swap_in(unsigned long *table_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96         int swap_nr;
  97         unsigned long page;
  98 
  99         if (!swap_bitmap) {
 100                 printk("Trying to swap in without swap bit-map");
 101                 return;
 102         }
 103         if (1 & *table_ptr) {
 104                 printk("trying to swap in present page\n\r");
 105                 return;
 106         }
 107         swap_nr = *table_ptr >> 1;
 108         if (!swap_nr) {
 109                 printk("No swap page in swap_in\n\r");
 110                 return;
 111         }
 112         if (!(page = get_free_page()))
 113                 oom();
 114         read_swap_page(swap_nr, (char *) page);
 115         if (setbit(swap_bitmap,swap_nr))
 116                 printk("swapping in multiply from same page\n\r");
 117         *table_ptr = page | (PAGE_DIRTY | 7);
 118 }
 119 
 120 int try_to_swap_out(unsigned long * table_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         unsigned long page;
 123         unsigned long swap_nr;
 124 
 125         page = *table_ptr;
 126         if (!(PAGE_PRESENT & page))
 127                 return 0;
 128         if (page - LOW_MEM > PAGING_MEMORY)
 129                 return 0;
 130         if (PAGE_DIRTY & page) {
 131                 page &= 0xfffff000;
 132                 if (mem_map[MAP_NR(page)] != 1)
 133                         return 0;
 134                 if (!(swap_nr = get_swap_page()))
 135                         return 0;
 136                 *table_ptr = swap_nr<<1;
 137                 invalidate();
 138                 write_swap_page(swap_nr, (char *) page);
 139                 free_page(page);
 140                 return 1;
 141         }
 142         page &= 0xfffff000;
 143         *table_ptr = 0;
 144         invalidate();
 145         free_page(page);
 146         return 1;
 147 }
 148 
 149 /*
 150  * Go through the page tables, searching for a user page that
 151  * we can swap out.
 152  *
 153  * Here it's easy to add a check for tasks that may not be swapped out:
 154  * loadable device drivers or similar. Just add an entry to the task-struct
 155  * and check it at the same time you check for the existence of the task.
 156  * The code assumes tasks are page-table aligned, but so do other parts
 157  * of the memory manager...
 158  */
 159 int swap_out(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         static int dir_entry = 1024;
 162         static int page_entry = -1;
 163         int counter = VM_PAGES;
 164         int pg_table;
 165         struct task_struct * p;
 166 
 167 check_dir:
 168         if (counter < 0)
 169                 goto no_swap;
 170         if (dir_entry >= 1024)
 171                 dir_entry = FIRST_VM_PAGE>>10;
 172         if (!(p = task[dir_entry >> 4])) {
 173                 counter -= 1024;
 174                 dir_entry++;
 175                 goto check_dir;
 176         }
 177         if (!(1 & (pg_table = pg_dir[dir_entry]))) {
 178                 if (pg_table) {
 179                         printk("bad page-table at pg_dir[%d]: %08x\n\r",
 180                                 dir_entry,pg_table);
 181                         pg_dir[dir_entry] = 0;
 182                 }
 183                 counter -= 1024;
 184                 dir_entry++;
 185                 goto check_dir;
 186         }
 187         pg_table &= 0xfffff000;
 188 check_table:
 189         if (counter < 0)
 190                 goto no_swap;
 191         counter--;
 192         page_entry++;
 193         if (page_entry >= 1024) {
 194                 page_entry = -1;
 195                 dir_entry++;
 196                 goto check_dir;
 197         }
 198         if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
 199                 p->rss--;
 200                 return 1;
 201         }
 202         goto check_table;
 203 no_swap:
 204         printk("Out of swap-memory\n\r");
 205         return 0;
 206 }
 207 
 208 /*
 209  * Get physical address of first (actually last :-) free page, and mark it
 210  * used. If no free pages left, return 0.
 211  */
 212 unsigned long get_free_page(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 213 {
 214         unsigned long result;
 215 
 216 repeat:
 217         __asm__("std ; repne ; scasb\n\t"
 218                 "jne 1f\n\t"
 219                 "movb $1,1(%%edi)\n\t"
 220                 "sall $12,%%ecx\n\t"
 221                 "addl %2,%%ecx\n\t"
 222                 "movl %%ecx,%%edx\n\t"
 223                 "movl $1024,%%ecx\n\t"
 224                 "leal 4092(%%edx),%%edi\n\t"
 225                 "rep ; stosl\n\t"
 226                 "movl %%edx,%%eax\n"
 227                 "1:\tcld"
 228                 :"=a" (result)
 229                 :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
 230                 "D" (mem_map+PAGING_PAGES-1)
 231                 :"di","cx","dx");
 232         if (result >= HIGH_MEMORY)
 233                 goto repeat;
 234         if ((result && result < LOW_MEM) || (result & 0xfff)) {
 235                 printk("weird result: %08x\n",result);
 236                 result = 0;
 237         }
 238         if (!result && swap_out())
 239                 goto repeat;
 240         return result;
 241 }
 242 
 243 /*
 244  * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
 245  *
 246  * The swapon system call
 247  */
 248 int sys_swapon(const char * specialfile)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250         struct inode * swap_inode;
 251         char * tmp;
 252         int i,j;
 253 
 254         if (!suser())
 255                 return -EPERM;
 256         if (!(swap_inode  = namei(specialfile)))
 257                 return -ENOENT;
 258         if (swap_file || swap_device || swap_bitmap) {
 259                 iput(swap_inode);
 260                 return -EBUSY;
 261         }
 262         if (S_ISBLK(swap_inode->i_mode)) {
 263                 swap_device = swap_inode->i_rdev;
 264                 iput(swap_inode);
 265         } else if (S_ISREG(swap_inode->i_mode))
 266                 swap_file = swap_inode;
 267         else {
 268                 iput(swap_inode);
 269                 return -EINVAL;
 270         }
 271         tmp = (char *) get_free_page();
 272         if (!tmp) {
 273                 iput(swap_file);
 274                 swap_device = 0;
 275                 swap_file = NULL;
 276                 printk("Unable to start swapping: out of memory :-)\n");
 277                 return -ENOMEM;
 278         }
 279         read_swap_page(0,tmp);
 280         if (strncmp("SWAP-SPACE",tmp+4086,10)) {
 281                 printk("Unable to find swap-space signature\n\r");
 282                 free_page((long) tmp);
 283                 iput(swap_file);
 284                 swap_device = 0;
 285                 swap_file = NULL;
 286                 swap_bitmap = NULL;
 287                 return -EINVAL;
 288         }
 289         memset(tmp+4086,0,10);
 290         j = 0;
 291         for (i = 1 ; i < SWAP_BITS ; i++)
 292                 if (bit(tmp,i))
 293                         j++;
 294         if (!j) {
 295                 printk("Empty swap-file\n");
 296                 free_page((long) tmp);
 297                 iput(swap_file);
 298                 swap_device = 0;
 299                 swap_file = NULL;
 300                 swap_bitmap = NULL;
 301                 return -EINVAL;
 302         }
 303         swap_bitmap = tmp;
 304         printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
 305         return 0;
 306 }

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