diff options
Diffstat (limited to 'mm/swapfile.c')
-rw-r--r-- | mm/swapfile.c | 210 |
1 files changed, 184 insertions, 26 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index dbd2b67..3e5a3a7 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -21,6 +21,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/ksm.h> #include <linux/rmap.h> #include <linux/security.h> @@ -1614,7 +1615,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); err = try_to_unuse(type); - compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); + test_set_oom_score_adj(oom_score_adj); if (err) { /* @@ -1649,6 +1650,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) p->max = 0; swap_map = p->swap_map; p->swap_map = NULL; + p->flags = 0; spin_unlock(&swap_lock); mutex_unlock(&swapon_mutex); vfree(swap_map); @@ -1666,16 +1668,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) mutex_unlock(&inode->i_mutex); } filp_close(swap_file, NULL); - - /* - * Clear the SWP_USED flag after all resources are freed so that swapon - * can reuse this swap_info in alloc_swap_info() safely. It is ok to - * not hold p->lock after we cleared its SWP_WRITEOK. - */ - spin_lock(&swap_lock); - p->flags = 0; - spin_unlock(&swap_lock); - err = 0; atomic_inc(&proc_poll_event); wake_up_interruptible(&proc_poll_wait); @@ -1687,14 +1679,19 @@ out: } #ifdef CONFIG_PROC_FS +struct proc_swaps { + struct seq_file seq; + int event; +}; + static unsigned swaps_poll(struct file *file, poll_table *wait) { - struct seq_file *seq = file->private_data; + struct proc_swaps *s = file->private_data; poll_wait(file, &proc_poll_wait, wait); - if (seq->poll_event != atomic_read(&proc_poll_event)) { - seq->poll_event = atomic_read(&proc_poll_event); + if (s->event != atomic_read(&proc_poll_event)) { + s->event = atomic_read(&proc_poll_event); return POLLIN | POLLRDNORM | POLLERR | POLLPRI; } @@ -1784,16 +1781,24 @@ static const struct seq_operations swaps_op = { static int swaps_open(struct inode *inode, struct file *file) { - struct seq_file *seq; + struct proc_swaps *s; int ret; + s = kmalloc(sizeof(struct proc_swaps), GFP_KERNEL); + if (!s) + return -ENOMEM; + + file->private_data = s; + ret = seq_open(file, &swaps_op); - if (ret) + if (ret) { + kfree(s); return ret; + } - seq = file->private_data; - seq->poll_event = atomic_read(&proc_poll_event); - return 0; + s->seq.private = s; + s->event = atomic_read(&proc_poll_event); + return ret; } static const struct file_operations proc_swaps_operations = { @@ -1930,13 +1935,13 @@ static unsigned long read_swap_header(struct swap_info_struct *p, /* * 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 swap pte as defined by the - * different architectures. In order to find the - * largest possible bit mask, a swap entry with swap type 0 + * 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 + * 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 @@ -2007,6 +2012,159 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, return nr_extents; } +#ifdef CONFIG_ZRAM_FOR_ANDROID +int swapon(char *name, int swap_flags) +{ + struct swap_info_struct *p; + + struct file *swap_file = NULL; + struct address_space *mapping; + int i; + int prio; + int error; + union swap_header *swap_header; + int nr_extents; + sector_t span; + unsigned long maxpages; + unsigned char *swap_map = NULL; + struct page *page = NULL; + struct inode *inode = NULL; + + p = alloc_swap_info(); + if (IS_ERR(p)) + return PTR_ERR(p); + + swap_file = filp_open(name, O_RDWR | O_LARGEFILE, 0); + if (IS_ERR(swap_file)) { + error = PTR_ERR(swap_file); + swap_file = NULL; + printk("zfqin, filp_open failed\n"); + goto bad_swap; + } + + printk("zfqin, filp_open succeeded\n"); + p->swap_file = swap_file; + mapping = swap_file->f_mapping; + + for (i = 0; i < nr_swapfiles; i++) { + struct swap_info_struct *q = swap_info[i]; + + if (q == p || !q->swap_file) + continue; + if (mapping == q->swap_file->f_mapping) { + error = -EBUSY; + goto bad_swap; + } + } + + inode = mapping->host; + /* If S_ISREG(inode->i_mode) will do mutex_lock(&inode->i_mutex); */ + error = claim_swapfile(p, inode); + if (unlikely(error)) + goto bad_swap; + + /* + * 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); + + maxpages = read_swap_header(p, swap_header, inode); + if (unlikely(!maxpages)) { + error = -EINVAL; + goto bad_swap; + } + + /* OK, set up the swap map and apply the bad block list */ + swap_map = vzalloc(maxpages); + if (!swap_map) { + error = -ENOMEM; + goto bad_swap; + } + + error = swap_cgroup_swapon(p->type, maxpages); + if (error) + goto bad_swap; + + nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, + maxpages, &span); + if (unlikely(nr_extents < 0)) { + error = nr_extents; + goto bad_swap; + } + + if (p->bdev) { + 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 && (swap_flags & SWAP_FLAG_DISCARD)) + p->flags |= SWP_DISCARDABLE; + } + + mutex_lock(&swapon_mutex); + prio = -1; + if (swap_flags & SWAP_FLAG_PREFER) + prio = + (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; + enable_swap_info(p, prio, swap_map); + + printk(KERN_INFO "Adding %uk swap on %s. " + "Priority:%d extents:%d across:%lluk %s%s\n", + p->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" : ""); + + mutex_unlock(&swapon_mutex); + atomic_inc(&proc_poll_event); + wake_up_interruptible(&proc_poll_wait); + + if (S_ISREG(inode->i_mode)) + inode->i_flags |= S_SWAPFILE; + error = 0; + goto out; + bad_swap: + if (inode && S_ISBLK(inode->i_mode) && p->bdev) { + set_blocksize(p->bdev, p->old_block_size); + blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + } + destroy_swap_extents(p); + swap_cgroup_swapoff(p->type); + spin_lock(&swap_lock); + p->swap_file = NULL; + p->flags = 0; + spin_unlock(&swap_lock); + vfree(swap_map); + if (swap_file) { + if (inode && S_ISREG(inode->i_mode)) { + mutex_unlock(&inode->i_mutex); + inode = NULL; + } + filp_close(swap_file, NULL); + } + out: + if (page && !IS_ERR(page)) { + kunmap(page); + page_cache_release(page); + } + + if (inode && S_ISREG(inode->i_mode)) + mutex_unlock(&inode->i_mutex); + return error; +} + +EXPORT_SYMBOL(swapon); +#endif /* CONFIG_ZRAM_FOR_ANDROID */ + SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; @@ -2107,7 +2265,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->flags |= SWP_SOLIDSTATE; p->cluster_next = 1 + (random32() % p->highest_bit); } - if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0) + if (discard_swap(p) == 0 && (swap_flags & SWAP_FLAG_DISCARD)) p->flags |= SWP_DISCARDABLE; } |