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

1.1       root        1: /*
                      2:  *  linux/mm/swap.c
                      3:  *
1.1.1.7 ! root        4:  *  Copyright (C) 1991, 1992  Linus Torvalds
1.1       root        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>
1.1.1.7 ! root       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,};
1.1       root       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;
1.1.1.7 ! root       46: static char * swap_lockmap = NULL;
1.1.1.2   root       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)
                     51: {
1.1.1.7 ! root       52:        static struct wait_queue * lock_queue = NULL;
1.1.1.2   root       53: 
1.1.1.7 ! root       54:        if (!swap_lockmap) {
        !            55:                printk("No swap lock-map\n");
1.1.1.2   root       56:                return;
                     57:        }
1.1.1.7 ! root       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: 
1.1.1.2   root       67:                for (i = 0; i < 4; i++)
1.1.1.7 ! root       68:                        if (!(zones[i] = bmap(swap_file,block++))) {
1.1.1.2   root       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);
1.1.1.7 ! root       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);
1.1.1.2   root       78: }
1.1       root       79: 
1.1.1.7 ! root       80: static unsigned int get_swap_page(void)
1.1       root       81: {
1.1.1.7 ! root       82:        unsigned int nr;
1.1       root       83: 
                     84:        if (!swap_bitmap)
                     85:                return 0;
1.1.1.7 ! root       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:                }
1.1       root       92:        return 0;
                     93: }
                     94: 
1.1.1.7 ! root       95: void swap_free(unsigned int swap_nr)
1.1       root       96: {
                     97:        if (!swap_nr)
                     98:                return;
1.1.1.7 ! root       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;
1.1       root      104:                if (!setbit(swap_bitmap,swap_nr))
                    105:                        return;
1.1.1.7 ! root      106:        }
        !           107:        printk("swap_free: swap-space bitmap bad (bit %d)\n",swap_nr);
1.1       root      108:        return;
                    109: }
                    110: 
                    111: void swap_in(unsigned long *table_ptr)
                    112: {
1.1.1.7 ! root      113:        unsigned long swap_nr;
1.1       root      114:        unsigned long page;
                    115: 
1.1.1.7 ! root      116:        swap_nr = *table_ptr;
        !           117:        if (1 & swap_nr) {
1.1       root      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:        }
1.1.1.7 ! root      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);
1.1       root      141:        *table_ptr = page | (PAGE_DIRTY | 7);
                    142: }
                    143: 
                    144: int try_to_swap_out(unsigned long * table_ptr)
                    145: {
1.1.1.7 ! root      146:        int i;
1.1       root      147:        unsigned long page;
                    148:        unsigned long swap_nr;
                    149: 
                    150:        page = *table_ptr;
                    151:        if (!(PAGE_PRESENT & page))
                    152:                return 0;
1.1.1.7 ! root      153:        if (page < low_memory || page >= high_memory)
1.1       root      154:                return 0;
1.1.1.7 ! root      155:        for (i = 0; i < NR_LAST_FREE_PAGES; i++)
        !           156:                if (last_free_pages[i] == (page & 0xfffff000))
        !           157:                        return 0;
1.1       root      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:        }
1.1.1.2   root      170:        page &= 0xfffff000;
1.1       root      171:        *table_ptr = 0;
                    172:        invalidate();
                    173:        free_page(page);
                    174:        return 1;
                    175: }
                    176: 
                    177: /*
1.1.1.7 ! root      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: /*
1.1.1.2   root      186:  * Go through the page tables, searching for a user page that
                    187:  * we can swap out.
1.1.1.5   root      188:  *
1.1.1.7 ! root      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)).
1.1       root      192:  */
                    193: int swap_out(void)
                    194: {
1.1.1.2   root      195:        static int dir_entry = 1024;
1.1       root      196:        static int page_entry = -1;
                    197:        int counter = VM_PAGES;
1.1.1.3   root      198:        int pg_table;
1.1.1.5   root      199:        struct task_struct * p;
1.1       root      200: 
1.1.1.3   root      201: check_dir:
                    202:        if (counter < 0)
                    203:                goto no_swap;
                    204:        if (dir_entry >= 1024)
                    205:                dir_entry = FIRST_VM_PAGE>>10;
1.1.1.5   root      206:        if (!(p = task[dir_entry >> 4])) {
                    207:                counter -= 1024;
                    208:                dir_entry++;
                    209:                goto check_dir;
                    210:        }
1.1.1.3   root      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:                }
1.1       root      217:                counter -= 1024;
                    218:                dir_entry++;
1.1.1.3   root      219:                goto check_dir;
1.1       root      220:        }
                    221:        pg_table &= 0xfffff000;
1.1.1.3   root      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;
1.1       root      231:        }
1.1.1.7 ! root      232:        if (p->swappable && try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
1.1.1.5   root      233:                p->rss--;
1.1.1.7 ! root      234:                dir_entry++;
1.1.1.3   root      235:                return 1;
1.1.1.4   root      236:        }
1.1.1.3   root      237:        goto check_table;
                    238: no_swap:
1.1       root      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:  */
1.1.1.7 ! root      247: unsigned long get_free_page(int priority)
1.1       root      248: {
1.1.1.2   root      249:        unsigned long result;
1.1.1.7 ! root      250:        static unsigned long index = 0;
1.1       root      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"
1.1.1.2   root      263:                "1:\tcld"
                    264:                :"=a" (result)
1.1.1.7 ! root      265:                :"0" (0),"b" (low_memory),"c" (paging_pages),
        !           266:                "D" (mem_map+paging_pages-1)
1.1       root      267:                :"di","cx","dx");
1.1.1.7 ! root      268:        if (result >= high_memory)
1.1       root      269:                goto repeat;
1.1.1.7 ! root      270:        if ((result && result < low_memory) || (result & 0xfff)) {
1.1.1.2   root      271:                printk("weird result: %08x\n",result);
                    272:                result = 0;
                    273:        }
1.1.1.7 ! root      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();
1.1       root      295:                goto repeat;
1.1.1.7 ! root      296:        }
        !           297:        return 0;
1.1       root      298: }
                    299: 
1.1.1.2   root      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)
1.1       root      306: {
1.1.1.2   root      307:        struct inode * swap_inode;
1.1.1.5   root      308:        char * tmp;
1.1.1.2   root      309:        int i,j;
1.1       root      310: 
1.1.1.2   root      311:        if (!suser())
                    312:                return -EPERM;
                    313:        if (!(swap_inode  = namei(specialfile)))
                    314:                return -ENOENT;
1.1.1.7 ! root      315:        if (swap_file || swap_device || swap_bitmap || swap_lockmap) {
1.1.1.2   root      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;
1.1       root      327:        }
1.1.1.7 ! root      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);
1.1.1.2   root      334:                iput(swap_file);
                    335:                swap_device = 0;
                    336:                swap_file = NULL;
1.1.1.7 ! root      337:                swap_bitmap = NULL;
        !           338:                swap_lockmap = NULL;
1.1.1.2   root      339:                return -ENOMEM;
1.1       root      340:        }
1.1.1.5   root      341:        read_swap_page(0,tmp);
                    342:        if (strncmp("SWAP-SPACE",tmp+4086,10)) {
1.1       root      343:                printk("Unable to find swap-space signature\n\r");
1.1.1.5   root      344:                free_page((long) tmp);
1.1.1.7 ! root      345:                free_page((long) swap_lockmap);
1.1.1.2   root      346:                iput(swap_file);
                    347:                swap_device = 0;
                    348:                swap_file = NULL;
1.1       root      349:                swap_bitmap = NULL;
1.1.1.7 ! root      350:                swap_lockmap = NULL;
1.1.1.2   root      351:                return -EINVAL;
1.1       root      352:        }
1.1.1.5   root      353:        memset(tmp+4086,0,10);
1.1       root      354:        j = 0;
1.1.1.7 ! root      355:        lowest_bit = 0;
        !           356:        highest_bit = 0;
1.1.1.2   root      357:        for (i = 1 ; i < SWAP_BITS ; i++)
1.1.1.7 ! root      358:                if (bit(tmp,i)) {
        !           359:                        if (!lowest_bit)
        !           360:                                lowest_bit = i;
        !           361:                        highest_bit = i;
1.1       root      362:                        j++;
1.1.1.7 ! root      363:                }
1.1       root      364:        if (!j) {
1.1.1.2   root      365:                printk("Empty swap-file\n");
1.1.1.5   root      366:                free_page((long) tmp);
1.1.1.7 ! root      367:                free_page((long) swap_lockmap);
1.1.1.2   root      368:                iput(swap_file);
                    369:                swap_device = 0;
                    370:                swap_file = NULL;
1.1       root      371:                swap_bitmap = NULL;
1.1.1.7 ! root      372:                swap_lockmap = NULL;
1.1.1.2   root      373:                return -EINVAL;
1.1       root      374:        }
1.1.1.5   root      375:        swap_bitmap = tmp;
1.1.1.2   root      376:        printk("Adding Swap: %d pages (%d bytes) swap-space\n\r",j,j*4096);
                    377:        return 0;
1.1       root      378: }

unix.superglobalmegacorp.com

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