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

📄 swapfile.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/mm/swapfile.c * *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds *  Swap reorganised 29.12.95, Stephen Tweedie */#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/kernel_stat.h>#include <linux/swap.h>#include <linux/swapctl.h>#include <linux/blkdev.h> /* for blk_size */#include <linux/vmalloc.h>#include <linux/pagemap.h>#include <linux/shm.h>#include <linux/compiler.h>#include <asm/pgtable.h>spinlock_t swaplock = SPIN_LOCK_UNLOCKED;unsigned int nr_swapfiles;int total_swap_pages;static int swap_overflow;static const char Bad_file[] = "Bad swap file entry ";static const char Unused_file[] = "Unused swap file entry ";static const char Bad_offset[] = "Bad swap offset entry ";static const char Unused_offset[] = "Unused swap offset entry ";struct swap_list_t swap_list = {-1, -1};struct swap_info_struct swap_info[MAX_SWAPFILES];#define SWAPFILE_CLUSTER 256static inline int scan_swap_map(struct swap_info_struct *si){	unsigned long offset;	/* 	 * We try to cluster swap pages by allocating them	 * sequentially in swap.  Once we've allocated	 * SWAPFILE_CLUSTER pages this way, however, we resort to	 * first-free allocation, starting a new cluster.  This	 * prevents us from scattering swap pages all over the entire	 * swap partition, so that we reduce overall disk seek times	 * between swap pages.  -- sct */	if (si->cluster_nr) {		while (si->cluster_next <= si->highest_bit) {			offset = si->cluster_next++;			if (si->swap_map[offset])				continue;			si->cluster_nr--;			goto got_page;		}	}	si->cluster_nr = SWAPFILE_CLUSTER;	/* try to find an empty (even not aligned) cluster. */	offset = si->lowest_bit; check_next_cluster:	if (offset+SWAPFILE_CLUSTER-1 <= si->highest_bit)	{		int nr;		for (nr = offset; nr < offset+SWAPFILE_CLUSTER; nr++)			if (si->swap_map[nr])			{				offset = nr+1;				goto check_next_cluster;			}		/* We found a completly empty cluster, so start		 * using it.		 */		goto got_page;	}	/* No luck, so now go finegrined as usual. -Andrea */	for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {		if (si->swap_map[offset])			continue;		si->lowest_bit = offset+1;	got_page:		if (offset == si->lowest_bit)			si->lowest_bit++;		if (offset == si->highest_bit)			si->highest_bit--;		if (si->lowest_bit > si->highest_bit) {			si->lowest_bit = si->max;			si->highest_bit = 0;		}		si->swap_map[offset] = 1;		nr_swap_pages--;		si->cluster_next = offset+1;		return offset;	}	si->lowest_bit = si->max;	si->highest_bit = 0;	return 0;}swp_entry_t get_swap_page(void){	struct swap_info_struct * p;	unsigned long offset;	swp_entry_t entry;	int type, wrapped = 0;	entry.val = 0;	/* Out of memory */	swap_list_lock();	type = swap_list.next;	if (type < 0)		goto out;	if (nr_swap_pages <= 0)		goto out;	while (1) {		p = &swap_info[type];		if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {			swap_device_lock(p);			offset = scan_swap_map(p);			swap_device_unlock(p);			if (offset) {				entry = SWP_ENTRY(type,offset);				type = swap_info[type].next;				if (type < 0 ||					p->prio != swap_info[type].prio) {						swap_list.next = swap_list.head;				} else {					swap_list.next = type;				}				goto out;			}		}		type = p->next;		if (!wrapped) {			if (type < 0 || p->prio != swap_info[type].prio) {				type = swap_list.head;				wrapped = 1;			}		} else			if (type < 0)				goto out;	/* out of swap space */	}out:	swap_list_unlock();	return entry;}static struct swap_info_struct * swap_info_get(swp_entry_t entry){	struct swap_info_struct * p;	unsigned long offset, type;	if (!entry.val)		goto out;	type = SWP_TYPE(entry);	if (type >= nr_swapfiles)		goto bad_nofile;	p = & swap_info[type];	if (!(p->flags & SWP_USED))		goto bad_device;	offset = SWP_OFFSET(entry);	if (offset >= p->max)		goto bad_offset;	if (!p->swap_map[offset])		goto bad_free;	swap_list_lock();	if (p->prio > swap_info[swap_list.next].prio)		swap_list.next = type;	swap_device_lock(p);	return p;bad_free:	printk(KERN_ERR "swap_free: %s%08lx\n", Unused_offset, entry.val);	goto out;bad_offset:	printk(KERN_ERR "swap_free: %s%08lx\n", Bad_offset, entry.val);	goto out;bad_device:	printk(KERN_ERR "swap_free: %s%08lx\n", Unused_file, entry.val);	goto out;bad_nofile:	printk(KERN_ERR "swap_free: %s%08lx\n", Bad_file, entry.val);out:	return NULL;}	static void swap_info_put(struct swap_info_struct * p){	swap_device_unlock(p);	swap_list_unlock();}static int swap_entry_free(struct swap_info_struct *p, unsigned long offset){	int count = p->swap_map[offset];	if (count < SWAP_MAP_MAX) {		count--;		p->swap_map[offset] = count;		if (!count) {			if (offset < p->lowest_bit)				p->lowest_bit = offset;			if (offset > p->highest_bit)				p->highest_bit = offset;			nr_swap_pages++;		}	}	return count;}/* * Caller has made sure that the swapdevice corresponding to entry * is still around or has not been recycled. */void swap_free(swp_entry_t entry){	struct swap_info_struct * p;	p = swap_info_get(entry);	if (p) {		swap_entry_free(p, SWP_OFFSET(entry));		swap_info_put(p);	}}/* * Check if we're the only user of a swap page, * when the page is locked. */static int exclusive_swap_page(struct page *page){	int retval = 0;	struct swap_info_struct * p;	swp_entry_t entry;	entry.val = page->index;	p = swap_info_get(entry);	if (p) {		/* Is the only swap cache user the cache itself? */		if (p->swap_map[SWP_OFFSET(entry)] == 1) {			/* Recheck the page count with the pagecache lock held.. */			spin_lock(&pagecache_lock);			if (page_count(page) - !!page->buffers == 2)				retval = 1;			spin_unlock(&pagecache_lock);		}		swap_info_put(p);	}	return retval;}/* * We can use this swap cache entry directly * if there are no other references to it. * * Here "exclusive_swap_page()" does the real * work, but we opportunistically check whether * we need to get all the locks first.. */int can_share_swap_page(struct page *page){	int retval = 0;	if (!PageLocked(page))		BUG();	switch (page_count(page)) {	case 3:		if (!page->buffers)			break;		/* Fallthrough */	case 2:		if (!PageSwapCache(page))			break;		retval = exclusive_swap_page(page);		break;	case 1:		if (PageReserved(page))			break;		retval = 1;	}	return retval;}/* * Work out if there are any other processes sharing this * swap cache page. Free it if you can. Return success. */int remove_exclusive_swap_page(struct page *page){	int retval;	struct swap_info_struct * p;	swp_entry_t entry;	if (!PageLocked(page))		BUG();	if (!PageSwapCache(page))		return 0;	if (page_count(page) - !!page->buffers != 2)	/* 2: us + cache */		return 0;	entry.val = page->index;	p = swap_info_get(entry);	if (!p)		return 0;	/* Is the only swap cache user the cache itself? */	retval = 0;	if (p->swap_map[SWP_OFFSET(entry)] == 1) {		/* Recheck the page count with the pagecache lock held.. */		spin_lock(&pagecache_lock);		if (page_count(page) - !!page->buffers == 2) {			__delete_from_swap_cache(page);			SetPageDirty(page);			retval = 1;		}		spin_unlock(&pagecache_lock);	}	swap_info_put(p);	if (retval) {		block_flushpage(page, 0);		swap_free(entry);		page_cache_release(page);	}	return retval;}/* * Free the swap entry like above, but also try to * free the page cache entry if it is the last user. */void free_swap_and_cache(swp_entry_t entry){	struct swap_info_struct * p;	struct page *page = NULL;	p = swap_info_get(entry);	if (p) {		if (swap_entry_free(p, SWP_OFFSET(entry)) == 1)			page = find_trylock_page(&swapper_space, entry.val);		swap_info_put(p);	}	if (page) {		page_cache_get(page);		/* Only cache user (+us), or swap space full? Free it! */		if (page_count(page) - !!page->buffers == 2 || vm_swap_full()) {			delete_from_swap_cache(page);			SetPageDirty(page);		}		UnlockPage(page);		page_cache_release(page);	}}/* * The swap entry has been read in advance, and we return 1 to indicate * that the page has been used or is no longer needed. * * Always set the resulting pte to be nowrite (the same as COW pages * after one process has exited).  We don't know just how many PTEs will * share this swap entry, so be cautious and let do_wp_page work out * what to do if a write is requested later. *//* mmlist_lock and vma->vm_mm->page_table_lock are held */static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,	pte_t *dir, swp_entry_t entry, struct page* page){	pte_t pte = *dir;	if (likely(pte_to_swp_entry(pte).val != entry.val))		return;	if (unlikely(pte_none(pte) || pte_present(pte)))		return;	get_page(page);	set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));	swap_free(entry);	++vma->vm_mm->rss;}/* mmlist_lock and vma->vm_mm->page_table_lock are held */static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,	unsigned long address, unsigned long size, unsigned long offset,	swp_entry_t entry, struct page* page){	pte_t * pte;	unsigned long end;	if (pmd_none(*dir))		return;	if (pmd_bad(*dir)) {		pmd_ERROR(*dir);		pmd_clear(dir);		return;	}	pte = pte_offset(dir, address);	offset += address & PMD_MASK;	address &= ~PMD_MASK;	end = address + size;	if (end > PMD_SIZE)		end = PMD_SIZE;	do {		unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page);		address += PAGE_SIZE;		pte++;	} while (address && (address < end));}/* mmlist_lock and vma->vm_mm->page_table_lock are held */static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,	unsigned long address, unsigned long size,	swp_entry_t entry, struct page* page){	pmd_t * pmd;	unsigned long offset, end;	if (pgd_none(*dir))		return;	if (pgd_bad(*dir)) {		pgd_ERROR(*dir);		pgd_clear(dir);		return;	}	pmd = pmd_offset(dir, address);	offset = address & PGDIR_MASK;	address &= ~PGDIR_MASK;	end = address + size;	if (end > PGDIR_SIZE)		end = PGDIR_SIZE;	if (address >= end)		BUG();	do {

⌨️ 快捷键说明

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