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

📄 swapfile.c

📁 最新最稳定的Linux内存管理模块源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	loff_t l = *pos;	mutex_lock(&swapon_mutex);	if (!l)		return SEQ_START_TOKEN;	for (i = 0; i < nr_swapfiles; i++, ptr++) {		if (!(ptr->flags & SWP_USED) || !ptr->swap_map)			continue;		if (!--l)			return ptr;	}	return NULL;}static void *swap_next(struct seq_file *swap, void *v, loff_t *pos){	struct swap_info_struct *ptr;	struct swap_info_struct *endptr = swap_info + nr_swapfiles;	if (v == SEQ_START_TOKEN)		ptr = swap_info;	else {		ptr = v;		ptr++;	}	for (; ptr < endptr; ptr++) {		if (!(ptr->flags & SWP_USED) || !ptr->swap_map)			continue;		++*pos;		return ptr;	}	return NULL;}static void swap_stop(struct seq_file *swap, void *v){	mutex_unlock(&swapon_mutex);}static int swap_show(struct seq_file *swap, void *v){	struct swap_info_struct *ptr = v;	struct file *file;	int len;	if (ptr == SEQ_START_TOKEN) {		seq_puts(swap,"Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");		return 0;	}	file = ptr->swap_file;	len = seq_path(swap, &file->f_path, " \t\n\\");	seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",			len < 40 ? 40 - len : 1, " ",			S_ISBLK(file->f_path.dentry->d_inode->i_mode) ?				"partition" : "file\t",			ptr->pages << (PAGE_SHIFT - 10),			ptr->inuse_pages << (PAGE_SHIFT - 10),			ptr->prio);	return 0;}static const struct seq_operations swaps_op = {	.start =	swap_start,	.next =		swap_next,	.stop =		swap_stop,	.show =		swap_show};static int swaps_open(struct inode *inode, struct file *file){	return seq_open(file, &swaps_op);}static const struct file_operations proc_swaps_operations = {	.open		= swaps_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release,};static int __init procswaps_init(void){	proc_create("swaps", 0, NULL, &proc_swaps_operations);	return 0;}__initcall(procswaps_init);#endif /* CONFIG_PROC_FS */#ifdef MAX_SWAPFILES_CHECKstatic int __init max_swapfiles_check(void){	MAX_SWAPFILES_CHECK();	return 0;}late_initcall(max_swapfiles_check);#endif/* * Written 01/25/92 by Simmule Turner, heavily changed by Linus. * * The swapon system call */SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags){	struct swap_info_struct * p;	char *name = NULL;	struct block_device *bdev = NULL;	struct file *swap_file = NULL;	struct address_space *mapping;	unsigned int type;	int i, prev;	int error;	union swap_header *swap_header = NULL;	unsigned int nr_good_pages = 0;	int nr_extents = 0;	sector_t span;	unsigned long maxpages = 1;	unsigned long swapfilepages;	unsigned short *swap_map = NULL;	struct page *page = NULL;	struct inode *inode = NULL;	int did_down = 0;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	spin_lock(&swap_lock);	p = swap_info;	for (type = 0 ; type < nr_swapfiles ; type++,p++)		if (!(p->flags & SWP_USED))			break;	error = -EPERM;	if (type >= MAX_SWAPFILES) {		spin_unlock(&swap_lock);		goto out;	}	if (type >= nr_swapfiles)		nr_swapfiles = type+1;	memset(p, 0, sizeof(*p));	INIT_LIST_HEAD(&p->extent_list);	p->flags = SWP_USED;	p->next = -1;	spin_unlock(&swap_lock);	name = getname(specialfile);	error = PTR_ERR(name);	if (IS_ERR(name)) {		name = NULL;		goto bad_swap_2;	}	swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0);	error = PTR_ERR(swap_file);	if (IS_ERR(swap_file)) {		swap_file = NULL;		goto bad_swap_2;	}	p->swap_file = swap_file;	mapping = swap_file->f_mapping;	inode = mapping->host;	error = -EBUSY;	for (i = 0; i < nr_swapfiles; i++) {		struct swap_info_struct *q = &swap_info[i];		if (i == type || !q->swap_file)			continue;		if (mapping == q->swap_file->f_mapping)			goto bad_swap;	}	error = -EINVAL;	if (S_ISBLK(inode->i_mode)) {		bdev = I_BDEV(inode);		error = bd_claim(bdev, sys_swapon);		if (error < 0) {			bdev = NULL;			error = -EINVAL;			goto bad_swap;		}		p->old_block_size = block_size(bdev);		error = set_blocksize(bdev, PAGE_SIZE);		if (error < 0)			goto bad_swap;		p->bdev = bdev;	} else if (S_ISREG(inode->i_mode)) {		p->bdev = inode->i_sb->s_bdev;		mutex_lock(&inode->i_mutex);		did_down = 1;		if (IS_SWAPFILE(inode)) {			error = -EBUSY;			goto bad_swap;		}	} else {		goto bad_swap;	}	swapfilepages = i_size_read(inode) >> PAGE_SHIFT;	/*	 * Read the swap header.	 */	if (!mapping->a_ops->readpage) {		error = -EINVAL;		goto bad_swap;	}	page = read_mapping_page(mapping, 0, swap_file);	if (IS_ERR(page)) {		error = PTR_ERR(page);		goto bad_swap;	}	swap_header = kmap(page);	if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) {		printk(KERN_ERR "Unable to find swap-space signature\n");		error = -EINVAL;		goto bad_swap;	}	/* swap partition endianess hack... */	if (swab32(swap_header->info.version) == 1) {		swab32s(&swap_header->info.version);		swab32s(&swap_header->info.last_page);		swab32s(&swap_header->info.nr_badpages);		for (i = 0; i < swap_header->info.nr_badpages; i++)			swab32s(&swap_header->info.badpages[i]);	}	/* Check the swap header's sub-version */	if (swap_header->info.version != 1) {		printk(KERN_WARNING		       "Unable to handle swap header version %d\n",		       swap_header->info.version);		error = -EINVAL;		goto bad_swap;	}	p->lowest_bit  = 1;	p->cluster_next = 1;	/*	 * Find out how many pages are allowed for a single swap	 * device. There are two limiting factors: 1) the number of	 * bits for the swap offset in the swp_entry_t type and	 * 2) the number of bits in the a swap pte as defined by	 * the different architectures. In order to find the	 * largest possible bit mask a swap entry with swap type 0	 * and swap offset ~0UL is created, encoded to a swap pte,	 * decoded to a swp_entry_t again and finally the swap	 * offset is extracted. This will mask all the bits from	 * the initial ~0UL mask that can't be encoded in either	 * the swp_entry_t or the architecture definition of a	 * swap pte.	 */	maxpages = swp_offset(pte_to_swp_entry(			swp_entry_to_pte(swp_entry(0, ~0UL)))) - 1;	if (maxpages > swap_header->info.last_page)		maxpages = swap_header->info.last_page;	p->highest_bit = maxpages - 1;	error = -EINVAL;	if (!maxpages)		goto bad_swap;	if (swapfilepages && maxpages > swapfilepages) {		printk(KERN_WARNING		       "Swap area shorter than signature indicates\n");		goto bad_swap;	}	if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))		goto bad_swap;	if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)		goto bad_swap;	/* OK, set up the swap map and apply the bad block list */	swap_map = vmalloc(maxpages * sizeof(short));	if (!swap_map) {		error = -ENOMEM;		goto bad_swap;	}	memset(swap_map, 0, maxpages * sizeof(short));	for (i = 0; i < swap_header->info.nr_badpages; i++) {		int page_nr = swap_header->info.badpages[i];		if (page_nr <= 0 || page_nr >= swap_header->info.last_page) {			error = -EINVAL;			goto bad_swap;		}		swap_map[page_nr] = SWAP_MAP_BAD;	}	error = swap_cgroup_swapon(type, maxpages);	if (error)		goto bad_swap;	nr_good_pages = swap_header->info.last_page -			swap_header->info.nr_badpages -			1 /* header page */;	if (nr_good_pages) {		swap_map[0] = SWAP_MAP_BAD;		p->max = maxpages;		p->pages = nr_good_pages;		nr_extents = setup_swap_extents(p, &span);		if (nr_extents < 0) {			error = nr_extents;			goto bad_swap;		}		nr_good_pages = p->pages;	}	if (!nr_good_pages) {		printk(KERN_WARNING "Empty swap-file\n");		error = -EINVAL;		goto bad_swap;	}	if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {		p->flags |= SWP_SOLIDSTATE;		p->cluster_next = 1 + (random32() % p->highest_bit);	}	if (discard_swap(p) == 0)		p->flags |= SWP_DISCARDABLE;	mutex_lock(&swapon_mutex);	spin_lock(&swap_lock);	if (swap_flags & SWAP_FLAG_PREFER)		p->prio =		  (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT;	else		p->prio = --least_priority;	p->swap_map = swap_map;	p->flags |= SWP_WRITEOK;	nr_swap_pages += nr_good_pages;	total_swap_pages += nr_good_pages;	printk(KERN_INFO "Adding %uk swap on %s.  "			"Priority:%d extents:%d across:%lluk %s%s\n",		nr_good_pages<<(PAGE_SHIFT-10), name, p->prio,		nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),		(p->flags & SWP_SOLIDSTATE) ? "SS" : "",		(p->flags & SWP_DISCARDABLE) ? "D" : "");	/* insert swap space into swap_list: */	prev = -1;	for (i = swap_list.head; i >= 0; i = swap_info[i].next) {		if (p->prio >= swap_info[i].prio) {			break;		}		prev = i;	}	p->next = i;	if (prev < 0) {		swap_list.head = swap_list.next = p - swap_info;	} else {		swap_info[prev].next = p - swap_info;	}	spin_unlock(&swap_lock);	mutex_unlock(&swapon_mutex);	error = 0;	goto out;bad_swap:	if (bdev) {		set_blocksize(bdev, p->old_block_size);		bd_release(bdev);	}	destroy_swap_extents(p);	swap_cgroup_swapoff(type);bad_swap_2:	spin_lock(&swap_lock);	p->swap_file = NULL;	p->flags = 0;	spin_unlock(&swap_lock);	vfree(swap_map);	if (swap_file)		filp_close(swap_file, NULL);out:	if (page && !IS_ERR(page)) {		kunmap(page);		page_cache_release(page);	}	if (name)		putname(name);	if (did_down) {		if (!error)			inode->i_flags |= S_SWAPFILE;		mutex_unlock(&inode->i_mutex);	}	return error;}void si_swapinfo(struct sysinfo *val){	unsigned int i;	unsigned long nr_to_be_unused = 0;	spin_lock(&swap_lock);	for (i = 0; i < nr_swapfiles; i++) {		if (!(swap_info[i].flags & SWP_USED) ||		     (swap_info[i].flags & SWP_WRITEOK))			continue;		nr_to_be_unused += swap_info[i].inuse_pages;	}	val->freeswap = nr_swap_pages + nr_to_be_unused;	val->totalswap = total_swap_pages + nr_to_be_unused;	spin_unlock(&swap_lock);}/* * Verify that a swap entry is valid and increment its swap map count. * * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as * "permanent", but will be reclaimed by the next swapoff. */int swap_duplicate(swp_entry_t entry){	struct swap_info_struct * p;	unsigned long offset, type;	int result = 0;	if (is_migration_entry(entry))		return 1;	type = swp_type(entry);	if (type >= nr_swapfiles)		goto bad_file;	p = type + swap_info;	offset = swp_offset(entry);	spin_lock(&swap_lock);	if (offset < p->max && p->swap_map[offset]) {		if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {			p->swap_map[offset]++;			result = 1;		} else if (p->swap_map[offset] <= SWAP_MAP_MAX) {			if (swap_overflow++ < 5)				printk(KERN_WARNING "swap_dup: swap entry overflow\n");			p->swap_map[offset] = SWAP_MAP_MAX;			result = 1;		}	}	spin_unlock(&swap_lock);out:	return result;bad_file:	printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);	goto out;}struct swap_info_struct *get_swap_info_struct(unsigned type){	return &swap_info[type];}/* * swap_lock prevents swap_map being freed. Don't grab an extra * reference on the swaphandle, it doesn't matter if it becomes unused. */int valid_swaphandles(swp_entry_t entry, unsigned long *offset){	struct swap_info_struct *si;	int our_page_cluster = page_cluster;	pgoff_t target, toff;	pgoff_t base, end;	int nr_pages = 0;	if (!our_page_cluster)	/* no readahead */		return 0;	si = &swap_info[swp_type(entry)];	target = swp_offset(entry);	base = (target >> our_page_cluster) << our_page_cluster;	end = base + (1 << our_page_cluster);	if (!base)		/* first page is swap header */		base++;	spin_lock(&swap_lock);	if (end > si->max)	/* don't go beyond end of map */		end = si->max;	/* Count contiguous allocated slots above our target */	for (toff = target; ++toff < end; nr_pages++) {		/* Don't read in free or bad pages */		if (!si->swap_map[toff])			break;		if (si->swap_map[toff] == SWAP_MAP_BAD)			break;	}	/* Count contiguous allocated slots below our target */	for (toff = target; --toff >= base; nr_pages++) {		/* Don't read in free or bad pages */		if (!si->swap_map[toff])			break;		if (si->swap_map[toff] == SWAP_MAP_BAD)			break;	}	spin_unlock(&swap_lock);	/*	 * Indicate starting offset, and return number of pages to get:	 * if only 1, say 0, since there's then no readahead to be done.	 */	*offset = ++toff;	return nr_pages? ++nr_pages: 0;}

⌨️ 快捷键说明

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