📄 swapfile.c
字号:
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) {
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;
int i, j, prev;
int error;
static int least_priority = 0;
union swap_header *swap_header = 0;
int swap_header_version;
int nr_good_pages = 0;
unsigned long maxpages;
int swapfilesize;
struct block_device *bdev = NULL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
lock_kernel();
p = swap_info;
for (type = 0 ; type < nr_swapfiles ; type++,p++)
if (!(p->flags & SWP_USED))
break;
error = -EPERM;
if (type >= MAX_SWAPFILES)
goto out;
if (type >= nr_swapfiles)
nr_swapfiles = type+1;
p->flags = SWP_USED;
p->swap_file = NULL;
p->swap_vfsmnt = NULL;
p->swap_device = 0;
p->swap_map = NULL;
p->lowest_bit = 0;
p->highest_bit = 0;
p->cluster_nr = 0;
p->sdev_lock = SPIN_LOCK_UNLOCKED;
p->max = 1;
p->next = -1;
if (swap_flags & SWAP_FLAG_PREFER) {
p->prio =
(swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
} else {
p->prio = --least_priority;
}
error = user_path_walk(specialfile, &nd);
if (error)
goto bad_swap_2;
p->swap_file = nd.dentry;
p->swap_vfsmnt = nd.mnt;
swap_inode = nd.dentry->d_inode;
error = -EINVAL;
if (S_ISBLK(swap_inode->i_mode)) {
kdev_t dev = swap_inode->i_rdev;
struct block_device_operations *bdops;
p->swap_device = dev;
set_blocksize(dev, PAGE_SIZE);
bdev = swap_inode->i_bdev;
bdops = devfs_get_ops(devfs_get_handle_from_inode(swap_inode));
if (bdops) bdev->bd_op = bdops;
error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
if (error)
goto bad_swap_2;
set_blocksize(dev, PAGE_SIZE);
error = -ENODEV;
if (!dev || (blk_size[MAJOR(dev)] &&
!blk_size[MAJOR(dev)][MINOR(dev)]))
goto bad_swap;
error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
if (i == type)
continue;
if (dev == swap_info[i].swap_device)
goto bad_swap;
}
swapfilesize = 0;
if (blk_size[MAJOR(dev)])
swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
>> (PAGE_SHIFT - 10);
} else if (S_ISREG(swap_inode->i_mode)) {
error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
if (i == type || !swap_info[i].swap_file)
continue;
if (swap_inode == swap_info[i].swap_file->d_inode)
goto bad_swap;
}
swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
} else
goto bad_swap;
swap_header = (void *) __get_free_page(GFP_USER);
if (!swap_header) {
printk("Unable to start swapping: out of memory :-)\n");
error = -ENOMEM;
goto bad_swap;
}
lock_page(virt_to_page(swap_header));
rw_swap_page_nolock(READ, SWP_ENTRY(type,0), (char *) swap_header, 1);
if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
swap_header_version = 1;
else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
swap_header_version = 2;
else {
printk("Unable to find swap-space signature\n");
error = -EINVAL;
goto bad_swap;
}
switch (swap_header_version) {
case 1:
memset(((char *) swap_header)+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,(char *) swap_header)) {
if (!p->lowest_bit)
p->lowest_bit = i;
p->highest_bit = i;
p->max = i+1;
j++;
}
}
nr_good_pages = j;
p->swap_map = vmalloc(p->max * sizeof(short));
if (!p->swap_map) {
error = -ENOMEM;
goto bad_swap;
}
for (i = 1 ; i < p->max ; i++) {
if (test_bit(i,(char *) swap_header))
p->swap_map[i] = 0;
else
p->swap_map[i] = SWAP_MAP_BAD;
}
break;
case 2:
/* Check the swap header's sub-version and the size of
the swap file and bad block lists */
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->highest_bit = swap_header->info.last_page - 1;
p->max = swap_header->info.last_page;
maxpages = SWP_OFFSET(SWP_ENTRY(0,~0UL));
if (p->max >= maxpages)
p->max = maxpages-1;
error = -EINVAL;
if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
goto bad_swap;
/* OK, set up the swap map and apply the bad block list */
if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) {
error = -ENOMEM;
goto bad_swap;
}
error = 0;
memset(p->swap_map, 0, p->max * sizeof(short));
for (i=0; i<swap_header->info.nr_badpages; i++) {
int page = swap_header->info.badpages[i];
if (page <= 0 || page >= swap_header->info.last_page)
error = -EINVAL;
else
p->swap_map[page] = SWAP_MAP_BAD;
}
nr_good_pages = swap_header->info.last_page -
swap_header->info.nr_badpages -
1 /* header page */;
if (error)
goto bad_swap;
}
if (swapfilesize && p->max > swapfilesize) {
printk(KERN_WARNING
"Swap area shorter than signature indicates\n");
error = -EINVAL;
goto bad_swap;
}
if (!nr_good_pages) {
printk(KERN_WARNING "Empty swap-file\n");
error = -EINVAL;
goto bad_swap;
}
p->swap_map[0] = SWAP_MAP_BAD;
p->flags = SWP_WRITEOK;
p->pages = nr_good_pages;
swap_list_lock();
nr_swap_pages += nr_good_pages;
printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
nr_good_pages<<(PAGE_SHIFT-10), p->prio);
/* 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;
}
swap_list_unlock();
error = 0;
goto out;
bad_swap:
if (bdev)
blkdev_put(bdev, BDEV_SWAP);
bad_swap_2:
if (p->swap_map)
vfree(p->swap_map);
nd.mnt = p->swap_vfsmnt;
nd.dentry = p->swap_file;
p->swap_device = 0;
p->swap_file = NULL;
p->swap_vfsmnt = NULL;
p->swap_map = NULL;
p->flags = 0;
if (!(swap_flags & SWAP_FLAG_PREFER))
++least_priority;
path_release(&nd);
out:
if (swap_header)
free_page((long) swap_header);
unlock_kernel();
return error;
}
void si_swapinfo(struct sysinfo *val)
{
unsigned int i;
unsigned long freeswap = 0;
unsigned long totalswap = 0;
for (i = 0; i < nr_swapfiles; i++) {
unsigned int j;
if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
continue;
for (j = 0; j < swap_info[i].max; ++j) {
switch (swap_info[i].swap_map[j]) {
case SWAP_MAP_BAD:
continue;
case 0:
freeswap++;
default:
totalswap++;
}
}
}
val->freeswap = freeswap;
val->totalswap = totalswap;
return;
}
/*
* Verify that a swap entry is valid and increment its swap map count.
* Kernel_lock is held, which guarantees existance of swap device.
*
* 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;
/* Swap entry 0 is illegal */
if (!entry.val)
goto out;
type = SWP_TYPE(entry);
if (type >= nr_swapfiles)
goto bad_file;
p = type + swap_info;
offset = SWP_OFFSET(entry);
if (offset >= p->max)
goto bad_offset;
if (!p->swap_map[offset])
goto bad_unused;
/*
* Entry is valid, so increment the map count.
*/
swap_device_lock(p);
if (p->swap_map[offset] < SWAP_MAP_MAX)
p->swap_map[offset]++;
else {
static int overflow = 0;
if (overflow++ < 5)
printk("VM: swap entry overflow\n");
p->swap_map[offset] = SWAP_MAP_MAX;
}
swap_device_unlock(p);
result = 1;
out:
return result;
bad_file:
printk("Bad swap file entry %08lx\n", entry.val);
goto out;
bad_offset:
printk("Bad swap offset entry %08lx\n", entry.val);
goto out;
bad_unused:
printk("Unused swap offset entry in swap_dup %08lx\n", entry.val);
goto out;
}
/*
* Page lock needs to be held in all cases to prevent races with
* swap file deletion.
*/
int swap_count(struct page *page)
{
struct swap_info_struct * p;
unsigned long offset, type;
swp_entry_t entry;
int retval = 0;
entry.val = page->index;
if (!entry.val)
goto bad_entry;
type = SWP_TYPE(entry);
if (type >= nr_swapfiles)
goto bad_file;
p = type + swap_info;
offset = SWP_OFFSET(entry);
if (offset >= p->max)
goto bad_offset;
if (!p->swap_map[offset])
goto bad_unused;
retval = p->swap_map[offset];
out:
return retval;
bad_entry:
printk(KERN_ERR "swap_count: null entry!\n");
goto out;
bad_file:
printk("Bad swap file entry %08lx\n", entry.val);
goto out;
bad_offset:
printk("Bad swap offset entry %08lx\n", entry.val);
goto out;
bad_unused:
printk("Unused swap offset entry in swap_count %08lx\n", entry.val);
goto out;
}
/*
* Kernel_lock protects against swap device deletion.
*/
void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
kdev_t *dev, struct inode **swapf)
{
unsigned long type;
struct swap_info_struct *p;
type = SWP_TYPE(entry);
if (type >= nr_swapfiles) {
printk("Internal error: bad swap-device\n");
return;
}
p = &swap_info[type];
*offset = SWP_OFFSET(entry);
if (*offset >= p->max) {
printk("rw_swap_page: weirdness\n");
return;
}
if (p->swap_map && !p->swap_map[*offset]) {
printk("VM: Bad swap entry %08lx\n", entry.val);
return;
}
if (!(p->flags & SWP_USED)) {
printk(KERN_ERR "rw_swap_page: "
"Trying to swap to unused swap-device\n");
return;
}
if (p->swap_device) {
*dev = p->swap_device;
} else if (p->swap_file) {
*swapf = p->swap_file->d_inode;
} else {
printk(KERN_ERR "rw_swap_page: no swap file or device\n");
}
return;
}
/*
* Kernel_lock protects against swap device deletion. Grab an extra
* reference on the swaphandle so that it dos not become unused.
*/
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
{
int ret = 0, i = 1 << page_cluster;
unsigned long toff;
struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
*offset = SWP_OFFSET(entry);
toff = *offset = (*offset >> page_cluster) << page_cluster;
swap_device_lock(swapdev);
do {
/* Don't read-ahead past the end of the swap area */
if (toff >= swapdev->max)
break;
/* Don't read in bad or busy pages */
if (!swapdev->swap_map[toff])
break;
if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
break;
swapdev->swap_map[toff]++;
toff++;
ret++;
} while (--i);
swap_device_unlock(swapdev);
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -