📄 swapfile.c
字号:
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 + -