⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 swap.c

📁 linux1.1源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -