?? swap.c
字號:
swap_task = 1; goto check_task; } p = task[swap_task]; if (!p || !p->swappable) { swap_task++; goto check_task; }check_dir: if (swap_table >= PTRS_PER_PAGE) { swap_table = 0; swap_task++; goto check_task; } pg_table = ((unsigned long *) p->tss.cr3)[swap_table]; if (pg_table >= high_memory || (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)) { swap_table++; goto check_dir; } if (!(PAGE_PRESENT & pg_table)) { printk("bad page-table at pg_dir[%d]: %08x\n", swap_table,pg_table); ((unsigned long *) p->tss.cr3)[swap_table] = 0; swap_table++; goto check_dir; } pg_table &= PAGE_MASK;check_table: if (swap_page >= PTRS_PER_PAGE) { swap_page = 0; swap_table++; goto check_dir; } switch (try_to_swap_out(swap_page + (unsigned long *) pg_table)) { case 0: break; case 1: p->rss--; return 1; default: p->rss--; } swap_page++; goto check_table;}#endifstatic int try_to_free_page(void){ int i=6; while (i--) { if (shrink_buffers(i)) return 1; if (shm_swap(i)) return 1; if (swap_out(i)) return 1; } return 0;}/* * Note that this must be atomic, or bad things will happen when * pages are requested in interrupts (as malloc can do). Thus the * cli/sti's. */static inline void add_mem_queue(unsigned long addr, unsigned long * queue){ addr &= PAGE_MASK; *(unsigned long *) addr = *queue; *queue = addr;}/* * Free_page() adds the page to the free lists. This is optimized for * fast normal cases (no error jumps taken normally). * * The way to optimize jumps for gcc-2.2.2 is to: * - select the "normal" case and put it inside the if () { XXX } * - no else-statements if you can avoid them * * With the above two rules, you get a straight-line execution path * for the normal case, giving better asm-code. */void free_page(unsigned long addr){ if (addr < high_memory) { unsigned short * map = mem_map + MAP_NR(addr); if (*map) { if (!(*map & MAP_PAGE_RESERVED)) { unsigned long flag; save_flags(flag); cli(); if (!--*map) { if (nr_secondary_pages < MAX_SECONDARY_PAGES) { add_mem_queue(addr,&secondary_page_list); nr_secondary_pages++; restore_flags(flag); return; } add_mem_queue(addr,&free_page_list); nr_free_pages++; } restore_flags(flag); } return; } printk("Trying to free free memory (%08lx): memory probabably corrupted\n",addr); printk("PC = %08lx\n",*(((unsigned long *)&addr)-1)); return; }}/* * This is one ugly macro, but it simplifies checking, and makes * this speed-critical place reasonably fast, especially as we have * to do things with the interrupt flag etc. * * Note that this #define is heavily optimized to give fast code * for the normal case - the if-statements are ordered so that gcc-2.2.2 * will make *no* jumps for the normal code. Don't touch unless you * know what you are doing. */#define REMOVE_FROM_MEM_QUEUE(queue,nr) \ cli(); \ if ((result = queue) != 0) { \ if (!(result & ~PAGE_MASK) && result < high_memory) { \ queue = *(unsigned long *) result; \ if (!mem_map[MAP_NR(result)]) { \ mem_map[MAP_NR(result)] = 1; \ nr--; \last_free_pages[index = (index + 1) & (NR_LAST_FREE_PAGES - 1)] = result; \ restore_flags(flag); \ return result; \ } \ printk("Free page %08lx has mem_map = %d\n", \ result,mem_map[MAP_NR(result)]); \ } else \ printk("Result = 0x%08lx - memory map destroyed\n", result); \ queue = 0; \ nr = 0; \ } else if (nr) { \ printk(#nr " is %d, but " #queue " is empty\n",nr); \ nr = 0; \ } \ restore_flags(flag)/* * Get physical address of first (actually last :-) free page, and mark it * used. If no free pages left, return 0. * * Note that this is one of the most heavily called functions in the kernel, * so it's a bit timing-critical (especially as we have to disable interrupts * in it). See the above macro which does most of the work, and which is * optimized for a fast normal path of execution. */unsigned long __get_free_page(int priority){ extern unsigned long intr_count; unsigned long result, flag; static unsigned long index = 0; /* this routine can be called at interrupt time via malloc. We want to make sure that the critical sections of code have interrupts disabled. -RAB Is this code reentrant? */ if (intr_count && priority != GFP_ATOMIC) { printk("gfp called nonatomically from interrupt %08lx\n", ((unsigned long *)&priority)[-1]); priority = GFP_ATOMIC; } save_flags(flag);repeat: REMOVE_FROM_MEM_QUEUE(free_page_list,nr_free_pages); if (priority == GFP_BUFFER) return 0; if (priority != GFP_ATOMIC) if (try_to_free_page()) goto repeat; REMOVE_FROM_MEM_QUEUE(secondary_page_list,nr_secondary_pages); return 0;}/* * Trying to stop swapping from a file is fraught with races, so * we repeat quite a bit here when we have to pause. swapoff() * isn't exactly timing-critical, so who cares? */static int try_to_unuse(unsigned int type){ int nr, pgt, pg; unsigned long page, *ppage; unsigned long tmp = 0; struct task_struct *p; nr = 0;/* * When we have to sleep, we restart the whole algorithm from the same * task we stopped in. That at least rids us of all races. */repeat: for (; nr < NR_TASKS ; nr++) { p = task[nr]; if (!p) continue; for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) { ppage = pgt + ((unsigned long *) p->tss.cr3); page = *ppage; if (!page) continue; if (!(page & PAGE_PRESENT) || (page >= high_memory)) continue; if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED) continue; ppage = (unsigned long *) (page & PAGE_MASK); for (pg = 0 ; pg < PTRS_PER_PAGE ; pg++,ppage++) { page = *ppage; if (!page) continue; if (page & PAGE_PRESENT) continue; if (SWP_TYPE(page) != type) continue; if (!tmp) { if (!(tmp = __get_free_page(GFP_KERNEL))) return -ENOMEM; goto repeat; } read_swap_page(page, (char *) tmp); if (*ppage == page) { *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE); ++p->rss; swap_free(page); tmp = 0; } goto repeat; } } } free_page(tmp); return 0;}asmlinkage int sys_swapoff(const char * specialfile){ struct swap_info_struct * p; struct inode * inode; unsigned int type; int i; if (!suser()) return -EPERM; i = namei(specialfile,&inode); if (i) return i; p = swap_info; for (type = 0 ; type < nr_swapfiles ; type++,p++) { if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK) continue; if (p->swap_file) { if (p->swap_file == inode) break; } else { if (!S_ISBLK(inode->i_mode)) continue; if (p->swap_device == inode->i_rdev) break; } } iput(inode); if (type >= nr_swapfiles) return -EINVAL; p->flags = SWP_USED; i = try_to_unuse(type); if (i) { p->flags = SWP_WRITEOK; return i; } nr_swap_pages -= p->pages; iput(p->swap_file); p->swap_file = NULL; p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; free_page((long) p->swap_lockmap); p->swap_lockmap = NULL; p->flags = 0; return 0;}/* * Written 01/25/92 by Simmule Turner, heavily changed by Linus. * * The swapon system call */asmlinkage int sys_swapon(const char * specialfile){ struct swap_info_struct * p; struct inode * swap_inode; unsigned int type; int i,j; int error; if (!suser()) return -EPERM; p = swap_info; for (type = 0 ; type < nr_swapfiles ; type++,p++) if (!(p->flags & SWP_USED)) break; if (type >= MAX_SWAPFILES) return -EPERM; if (type >= nr_swapfiles) nr_swapfiles = type+1; p->flags = SWP_USED; p->swap_file = NULL; p->swap_device = 0; p->swap_map = NULL; p->swap_lockmap = NULL; p->lowest_bit = 0; p->highest_bit = 0; p->max = 1; error = namei(specialfile,&swap_inode); if (error) goto bad_swap; error = -EBUSY; if (swap_inode->i_count != 1) goto bad_swap; error = -EINVAL; if (S_ISBLK(swap_inode->i_mode)) { p->swap_device = swap_inode->i_rdev; iput(swap_inode); error = -ENODEV; if (!p->swap_device) goto bad_swap; error = -EBUSY; for (i = 0 ; i < nr_swapfiles ; i++) { if (i == type) continue; if (p->swap_device == swap_info[i].swap_device) goto bad_swap; } } else if (S_ISREG(swap_inode->i_mode)) p->swap_file = swap_inode; else goto bad_swap; p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); if (!p->swap_lockmap) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap); if (memcmp("SWAP-SPACE",p->swap_lockmap+4086,10)) { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } memset(p->swap_lockmap+PAGE_SIZE-10,0,10); j = 0; p->lowest_bit = 0; p->highest_bit = 0; for (i = 1 ; i < 8*PAGE_SIZE ; i++) { if (test_bit(i,p->swap_lockmap)) { if (!p->lowest_bit) p->lowest_bit = i; p->highest_bit = i; p->max = i+1; j++; } } if (!j) { printk("Empty swap-file\n"); error = -EINVAL; goto bad_swap; } p->swap_map = (unsigned char *) vmalloc(p->max); if (!p->swap_map) { error = -ENOMEM; goto bad_swap; } for (i = 1 ; i < p->max ; i++) { if (test_bit(i,p->swap_lockmap)) p->swap_map[i] = 0; else p->swap_map[i] = 0x80; } p->swap_map[0] = 0x80; memset(p->swap_lockmap,0,PAGE_SIZE); p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; printk("Adding Swap: %dk swap-space\n",j<<2); return 0;bad_swap: free_page((long) p->swap_lockmap); vfree(p->swap_map); iput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; p->swap_map = NULL; p->swap_lockmap = NULL; p->flags = 0; return error;}void si_swapinfo(struct sysinfo *val){ unsigned int i, j; val->freeswap = val->totalswap = 0; for (i = 0; i < nr_swapfiles; i++) { if (!(swap_info[i].flags & SWP_USED)) continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) { case 128: continue; case 0: ++val->freeswap; default: ++val->totalswap; } } val->freeswap <<= PAGE_SHIFT; val->totalswap <<= PAGE_SHIFT; return;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -