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

📄 swapfile.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		unuse_pmd(vma, pmd, address, end - address, offset, entry,			  page);		address = (address + PMD_SIZE) & PMD_MASK;		pmd++;	} while (address && (address < end));}/* mmlist_lock and vma->vm_mm->page_table_lock are held */static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,			swp_entry_t entry, struct page* page){	unsigned long start = vma->vm_start, end = vma->vm_end;	if (start >= end)		BUG();	do {		unuse_pgd(vma, pgdir, start, end - start, entry, page);		start = (start + PGDIR_SIZE) & PGDIR_MASK;		pgdir++;	} while (start && (start < end));}static void unuse_process(struct mm_struct * mm,			swp_entry_t entry, struct page* page){	struct vm_area_struct* vma;	/*	 * Go through process' page directory.	 */	spin_lock(&mm->page_table_lock);	for (vma = mm->mmap; vma; vma = vma->vm_next) {		pgd_t * pgd = pgd_offset(mm, vma->vm_start);		unuse_vma(vma, pgd, entry, page);	}	spin_unlock(&mm->page_table_lock);	return;}/* * Scan swap_map from current position to next entry still in use. * Recycle to start on reaching the end, returning 0 when empty. */static int find_next_to_unuse(struct swap_info_struct *si, int prev){	int max = si->max;	int i = prev;	int count;	/*	 * No need for swap_device_lock(si) here: we're just looking	 * for whether an entry is in use, not modifying it; false	 * hits are okay, and sys_swapoff() has already prevented new	 * allocations from this area (while holding swap_list_lock()).	 */	for (;;) {		if (++i >= max) {			if (!prev) {				i = 0;				break;			}			/*			 * No entries in use at top of swap_map,			 * loop back to start and recheck there.			 */			max = prev + 1;			prev = 0;			i = 1;		}		count = si->swap_map[i];		if (count && count != SWAP_MAP_BAD)			break;	}	return i;}/* * We completely avoid races by reading each swap page in advance, * and then search for the process using it.  All the necessary * page table adjustments can then be made atomically. */static int try_to_unuse(unsigned int type){	struct swap_info_struct * si = &swap_info[type];	struct mm_struct *start_mm;	unsigned short *swap_map;	unsigned short swcount;	struct page *page;	swp_entry_t entry;	int i = 0;	int retval = 0;	int reset_overflow = 0;	/*	 * When searching mms for an entry, a good strategy is to	 * start at the first mm we freed the previous entry from	 * (though actually we don't notice whether we or coincidence	 * freed the entry).  Initialize this start_mm with a hold.	 *	 * A simpler strategy would be to start at the last mm we	 * freed the previous entry from; but that would take less	 * advantage of mmlist ordering (now preserved by swap_out()),	 * which clusters forked address spaces together, most recent	 * child immediately after parent.  If we race with dup_mmap(),	 * we very much want to resolve parent before child, otherwise	 * we may miss some entries: using last mm would invert that.	 */	start_mm = &init_mm;	atomic_inc(&init_mm.mm_users);	/*	 * Keep on scanning until all entries have gone.  Usually,	 * one pass through swap_map is enough, but not necessarily:	 * mmput() removes mm from mmlist before exit_mmap() and its	 * zap_page_range().  That's not too bad, those entries are	 * on their way out, and handled faster there than here.	 * do_munmap() behaves similarly, taking the range out of mm's	 * vma list before zap_page_range().  But unfortunately, when	 * unmapping a part of a vma, it takes the whole out first,	 * then reinserts what's left after (might even reschedule if	 * open() method called) - so swap entries may be invisible	 * to swapoff for a while, then reappear - but that is rare.	 */	while ((i = find_next_to_unuse(si, i))) {		/* 		 * Get a page for the entry, using the existing swap		 * cache page if there is one.  Otherwise, get a clean		 * page and read the swap into it. 		 */		swap_map = &si->swap_map[i];		entry = SWP_ENTRY(type, i);		page = read_swap_cache_async(entry);		if (!page) {			/*			 * Either swap_duplicate() failed because entry			 * has been freed independently, and will not be			 * reused since sys_swapoff() already disabled			 * allocation from here, or alloc_page() failed.			 */			if (!*swap_map)				continue;			retval = -ENOMEM;			break;		}		/*		 * Don't hold on to start_mm if it looks like exiting.		 */		if (atomic_read(&start_mm->mm_users) == 1) {			mmput(start_mm);			start_mm = &init_mm;			atomic_inc(&init_mm.mm_users);		}		/*		 * Wait for and lock page.  When do_swap_page races with		 * try_to_unuse, do_swap_page can handle the fault much		 * faster than try_to_unuse can locate the entry.  This		 * apparently redundant "wait_on_page" lets try_to_unuse		 * defer to do_swap_page in such a case - in some tests,		 * do_swap_page and try_to_unuse repeatedly compete.		 */		wait_on_page(page);		lock_page(page);		/*		 * Remove all references to entry, without blocking.		 * Whenever we reach init_mm, there's no address space		 * to search, but use it as a reminder to search shmem.		 */		swcount = *swap_map;		if (swcount > 1) {			flush_page_to_ram(page);			if (start_mm == &init_mm)				shmem_unuse(entry, page);			else				unuse_process(start_mm, entry, page);		}		if (*swap_map > 1) {			int set_start_mm = (*swap_map >= swcount);			struct list_head *p = &start_mm->mmlist;			struct mm_struct *new_start_mm = start_mm;			struct mm_struct *mm;			spin_lock(&mmlist_lock);			while (*swap_map > 1 &&					(p = p->next) != &start_mm->mmlist) {				mm = list_entry(p, struct mm_struct, mmlist);				swcount = *swap_map;				if (mm == &init_mm) {					set_start_mm = 1;					shmem_unuse(entry, page);				} else					unuse_process(mm, entry, page);				if (set_start_mm && *swap_map < swcount) {					new_start_mm = mm;					set_start_mm = 0;				}			}			atomic_inc(&new_start_mm->mm_users);			spin_unlock(&mmlist_lock);			mmput(start_mm);			start_mm = new_start_mm;		}		/*		 * How could swap count reach 0x7fff when the maximum		 * pid is 0x7fff, and there's no way to repeat a swap		 * page within an mm (except in shmem, where it's the		 * shared object which takes the reference count)?		 * We believe SWAP_MAP_MAX cannot occur in Linux 2.4.		 *		 * If that's wrong, then we should worry more about		 * exit_mmap() and do_munmap() cases described above:		 * we might be resetting SWAP_MAP_MAX too early here.		 * We know "Undead"s can happen, they're okay, so don't		 * report them; but do report if we reset SWAP_MAP_MAX.		 */		if (*swap_map == SWAP_MAP_MAX) {			swap_list_lock();			swap_device_lock(si);			nr_swap_pages++;			*swap_map = 1;			swap_device_unlock(si);			swap_list_unlock();			reset_overflow = 1;		}		/*		 * If a reference remains (rare), we would like to leave		 * the page in the swap cache; but try_to_swap_out could		 * then re-duplicate the entry once we drop page lock,		 * so we might loop indefinitely; also, that page could		 * not be swapped out to other storage meanwhile.  So:		 * delete from cache even if there's another reference,		 * after ensuring that the data has been saved to disk -		 * since if the reference remains (rarer), it will be		 * read from disk into another page.  Splitting into two		 * pages would be incorrect if swap supported "shared		 * private" pages, but they are handled by tmpfs files.		 * Note shmem_unuse already deleted its from swap cache.		 */		swcount = *swap_map;		if ((swcount > 0) != PageSwapCache(page))			BUG();		if ((swcount > 1) && PageDirty(page)) {			rw_swap_page(WRITE, page);			lock_page(page);		}		if (PageSwapCache(page))			delete_from_swap_cache(page);		/*		 * So we could skip searching mms once swap count went		 * to 1, we did not mark any present ptes as dirty: must		 * mark page dirty so try_to_swap_out will preserve it.		 */		SetPageDirty(page);		UnlockPage(page);		page_cache_release(page);		/*		 * Make sure that we aren't completely killing		 * interactive performance.  Interruptible check on		 * signal_pending() would be nice, but changes the spec?		 */		if (current->need_resched)			schedule();	}	mmput(start_mm);	if (reset_overflow) {		printk(KERN_WARNING "swapoff: cleared swap entry overflow\n");		swap_overflow = 0;	}	return retval;}asmlinkage long sys_swapoff(const char * specialfile){	struct swap_info_struct * p = NULL;	unsigned short *swap_map;	struct nameidata nd;	int i, type, prev;	int err;		if (!capable(CAP_SYS_ADMIN))		return -EPERM;	err = user_path_walk(specialfile, &nd);	if (err)		goto out;	lock_kernel();	prev = -1;	swap_list_lock();	for (type = swap_list.head; type >= 0; type = swap_info[type].next) {		p = swap_info + type;		if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {			if (p->swap_file == nd.dentry)			  break;		}		prev = type;	}	err = -EINVAL;	if (type < 0) {		swap_list_unlock();		goto out_dput;	}	if (prev < 0) {		swap_list.head = p->next;	} else {		swap_info[prev].next = p->next;	}	if (type == swap_list.next) {		/* just pick something that's safe... */		swap_list.next = swap_list.head;	}	nr_swap_pages -= p->pages;	total_swap_pages -= p->pages;	p->flags = SWP_USED;	swap_list_unlock();	unlock_kernel();	err = try_to_unuse(type);	lock_kernel();	if (err) {		/* re-insert swap space back into swap_list */		swap_list_lock();		for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)			if (p->prio >= swap_info[i].prio)				break;		p->next = i;		if (prev < 0)			swap_list.head = swap_list.next = p - swap_info;		else			swap_info[prev].next = p - swap_info;		nr_swap_pages += p->pages;		total_swap_pages += p->pages;		p->flags = SWP_WRITEOK;		swap_list_unlock();		goto out_dput;	}	if (p->swap_device)		blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);	path_release(&nd);	swap_list_lock();	swap_device_lock(p);	nd.mnt = p->swap_vfsmnt;	nd.dentry = p->swap_file;	p->swap_vfsmnt = NULL;	p->swap_file = NULL;	p->swap_device = 0;	p->max = 0;	swap_map = p->swap_map;	p->swap_map = NULL;	p->flags = 0;	swap_device_unlock(p);	swap_list_unlock();	vfree(swap_map);	err = 0;out_dput:	unlock_kernel();	path_release(&nd);out:	return err;}int get_swaparea_info(char *buf){	char * page = (char *) __get_free_page(GFP_KERNEL);	struct swap_info_struct *ptr = swap_info;	int i, j, len = 0, usedswap;	if (!page)		return -ENOMEM;	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {		if ((ptr->flags & SWP_USED) && ptr->swap_map) {			char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,						page, PAGE_SIZE);			len += sprintf(buf + len, "%-31s ", path);			if (!ptr->swap_device)				len += sprintf(buf + len, "file\t\t");			else				len += sprintf(buf + len, "partition\t");			usedswap = 0;			for (j = 0; j < ptr->max; ++j)				switch (ptr->swap_map[j]) {					case SWAP_MAP_BAD:					case 0:						continue;					default:						usedswap++;				}			len += sprintf(buf + len, "%d\t%d\t%d\n", ptr->pages << (PAGE_SHIFT - 10), 				usedswap << (PAGE_SHIFT - 10), ptr->prio);		}	}	free_page((unsigned long) page);	return len;}int is_swap_partition(kdev_t dev) {	struct swap_info_struct *ptr = swap_info;	int i;	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {		if (ptr->flags & SWP_USED)			if (ptr->swap_device == dev)				return 1;	}	return 0;}/* * Written 01/25/92 by Simmule Turner, heavily changed by Linus. * * The swapon system call */asmlinkage long sys_swapon(const char * specialfile, int swap_flags){	struct swap_info_struct * p;	struct nameidata nd;	struct inode * swap_inode;	unsigned int type;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -