Annotation of linux/mm/swap.c, revision 1.1.1.5

1.1       root        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: 
1.1.1.2   root       12: #include <errno.h>
1.1.1.5 ! root       13: #include <sys/stat.h>
1.1       root       14: 
                     15: #include <linux/mm.h>
1.1.1.5 ! root       16: #include <linux/string.h>
1.1       root       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;
1.1.1.2   root       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)
                     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: }
1.1       root       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)
                     72: {
                     73:        int nr;
                     74: 
                     75:        if (!swap_bitmap)
                     76:                return 0;
1.1.1.2   root       77:        for (nr = 1; nr < SWAP_BITS ; nr++)
1.1       root       78:                if (clrbit(swap_bitmap,nr))
                     79:                        return nr;
                     80:        return 0;
                     81: }
                     82: 
                     83: void swap_free(int swap_nr)
                     84: {
                     85:        if (!swap_nr)
                     86:                return;
                     87:        if (swap_bitmap && swap_nr < SWAP_BITS)
                     88:                if (!setbit(swap_bitmap,swap_nr))
                     89:                        return;
1.1.1.2   root       90:        printk("swap_free: swap-space bitmap bad\n");
1.1       root       91:        return;
                     92: }
                     93: 
                     94: void swap_in(unsigned long *table_ptr)
                     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)
                    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:        }
1.1.1.2   root      142:        page &= 0xfffff000;
1.1       root      143:        *table_ptr = 0;
                    144:        invalidate();
                    145:        free_page(page);
                    146:        return 1;
                    147: }
                    148: 
                    149: /*
1.1.1.2   root      150:  * Go through the page tables, searching for a user page that
                    151:  * we can swap out.
1.1.1.5 ! root      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...
1.1       root      158:  */
                    159: int swap_out(void)
                    160: {
1.1.1.2   root      161:        static int dir_entry = 1024;
1.1       root      162:        static int page_entry = -1;
                    163:        int counter = VM_PAGES;
1.1.1.3   root      164:        int pg_table;
1.1.1.5 ! root      165:        struct task_struct * p;
1.1       root      166: 
1.1.1.3   root      167: check_dir:
                    168:        if (counter < 0)
                    169:                goto no_swap;
                    170:        if (dir_entry >= 1024)
                    171:                dir_entry = FIRST_VM_PAGE>>10;
1.1.1.5 ! root      172:        if (!(p = task[dir_entry >> 4])) {
        !           173:                counter -= 1024;
        !           174:                dir_entry++;
        !           175:                goto check_dir;
        !           176:        }
1.1.1.3   root      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:                }
1.1       root      183:                counter -= 1024;
                    184:                dir_entry++;
1.1.1.3   root      185:                goto check_dir;
1.1       root      186:        }
                    187:        pg_table &= 0xfffff000;
1.1.1.3   root      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;
1.1       root      197:        }
1.1.1.4   root      198:        if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
1.1.1.5 ! root      199:                p->rss--;
1.1.1.3   root      200:                return 1;
1.1.1.4   root      201:        }
1.1.1.3   root      202:        goto check_table;
                    203: no_swap:
1.1       root      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)
                    213: {
1.1.1.2   root      214:        unsigned long result;
1.1       root      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"
1.1.1.2   root      227:                "1:\tcld"
                    228:                :"=a" (result)
1.1       root      229:                :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
                    230:                "D" (mem_map+PAGING_PAGES-1)
                    231:                :"di","cx","dx");
1.1.1.2   root      232:        if (result >= HIGH_MEMORY)
1.1       root      233:                goto repeat;
1.1.1.2   root      234:        if ((result && result < LOW_MEM) || (result & 0xfff)) {
                    235:                printk("weird result: %08x\n",result);
                    236:                result = 0;
                    237:        }
                    238:        if (!result && swap_out())
1.1       root      239:                goto repeat;
1.1.1.2   root      240:        return result;
1.1       root      241: }
                    242: 
1.1.1.2   root      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)
1.1       root      249: {
1.1.1.2   root      250:        struct inode * swap_inode;
1.1.1.5 ! root      251:        char * tmp;
1.1.1.2   root      252:        int i,j;
1.1       root      253: 
1.1.1.2   root      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;
1.1       root      270:        }
1.1.1.5 ! root      271:        tmp = (char *) get_free_page();
        !           272:        if (!tmp) {
1.1.1.2   root      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;
1.1       root      278:        }
1.1.1.5 ! root      279:        read_swap_page(0,tmp);
        !           280:        if (strncmp("SWAP-SPACE",tmp+4086,10)) {
1.1       root      281:                printk("Unable to find swap-space signature\n\r");
1.1.1.5 ! root      282:                free_page((long) tmp);
1.1.1.2   root      283:                iput(swap_file);
                    284:                swap_device = 0;
                    285:                swap_file = NULL;
1.1       root      286:                swap_bitmap = NULL;
1.1.1.2   root      287:                return -EINVAL;
1.1       root      288:        }
1.1.1.5 ! root      289:        memset(tmp+4086,0,10);
1.1       root      290:        j = 0;
1.1.1.2   root      291:        for (i = 1 ; i < SWAP_BITS ; i++)
1.1.1.5 ! root      292:                if (bit(tmp,i))
1.1       root      293:                        j++;
                    294:        if (!j) {
1.1.1.2   root      295:                printk("Empty swap-file\n");
1.1.1.5 ! root      296:                free_page((long) tmp);
1.1.1.2   root      297:                iput(swap_file);
                    298:                swap_device = 0;
                    299:                swap_file = NULL;
1.1       root      300:                swap_bitmap = NULL;
1.1.1.2   root      301:                return -EINVAL;
1.1       root      302:        }
1.1.1.5 ! root      303:        swap_bitmap = tmp;
1.1.1.2   root      304:        printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
                    305:        return 0;
1.1       root      306: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.