ALSA: hda - Workaround for buggy DMA position on ATI controllers
[firefly-linux-kernel-4.4.55.git] / mm / swapfile.c
index 763210732b5fd019875cbec86ec136e6c29b1383..da422c47e2ee515bb68c131f0980c603b7d1b380 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <linux/swapops.h>
+#include <linux/page_cgroup.h>
 
 static DEFINE_SPINLOCK(swap_lock);
 static unsigned int nr_swapfiles;
@@ -96,7 +97,7 @@ static int discard_swap(struct swap_info_struct *si)
 
        list_for_each_entry(se, &si->extent_list, list) {
                sector_t start_block = se->start_block << (PAGE_SHIFT - 9);
-               pgoff_t nr_blocks = se->nr_pages << (PAGE_SHIFT - 9);
+               sector_t nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9);
 
                if (se->start_page == 0) {
                        /* Do not discard the swap header page! */
@@ -133,7 +134,7 @@ static void discard_swap_cluster(struct swap_info_struct *si,
                    start_page < se->start_page + se->nr_pages) {
                        pgoff_t offset = start_page - se->start_page;
                        sector_t start_block = se->start_block + offset;
-                       pgoff_t nr_blocks = se->nr_pages - offset;
+                       sector_t nr_blocks = se->nr_pages - offset;
 
                        if (nr_blocks > nr_pages)
                                nr_blocks = nr_pages;
@@ -470,8 +471,9 @@ out:
        return NULL;
 }
 
-static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
+static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent)
 {
+       unsigned long offset = swp_offset(ent);
        int count = p->swap_map[offset];
 
        if (count < SWAP_MAP_MAX) {
@@ -486,6 +488,7 @@ static int swap_entry_free(struct swap_info_struct *p, unsigned long offset)
                                swap_list.next = p - swap_info;
                        nr_swap_pages++;
                        p->inuse_pages--;
+                       mem_cgroup_uncharge_swap(ent);
                }
        }
        return count;
@@ -501,7 +504,7 @@ void swap_free(swp_entry_t entry)
 
        p = swap_info_get(entry);
        if (p) {
-               swap_entry_free(p, swp_offset(entry));
+               swap_entry_free(p, entry);
                spin_unlock(&swap_lock);
        }
 }
@@ -571,17 +574,17 @@ int try_to_free_swap(struct page *page)
  * 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)
+int free_swap_and_cache(swp_entry_t entry)
 {
-       struct swap_info_struct * p;
+       struct swap_info_struct *p;
        struct page *page = NULL;
 
        if (is_migration_entry(entry))
-               return;
+               return 1;
 
        p = swap_info_get(entry);
        if (p) {
-               if (swap_entry_free(p, swp_offset(entry)) == 1) {
+               if (swap_entry_free(p, entry) == 1) {
                        page = find_get_page(&swapper_space, entry.val);
                        if (page && !trylock_page(page)) {
                                page_cache_release(page);
@@ -603,6 +606,7 @@ void free_swap_and_cache(swp_entry_t entry)
                unlock_page(page);
                page_cache_release(page);
        }
+       return p != NULL;
 }
 
 #ifdef CONFIG_HIBERNATION
@@ -689,17 +693,18 @@ unsigned int count_swap_pages(int type, int free)
 static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
+       struct mem_cgroup *ptr = NULL;
        spinlock_t *ptl;
        pte_t *pte;
        int ret = 1;
 
-       if (mem_cgroup_charge(page, vma->vm_mm, GFP_KERNEL))
+       if (mem_cgroup_try_charge_swapin(vma->vm_mm, page, GFP_KERNEL, &ptr))
                ret = -ENOMEM;
 
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
                if (ret > 0)
-                       mem_cgroup_uncharge_page(page);
+                       mem_cgroup_cancel_charge_swapin(ptr);
                ret = 0;
                goto out;
        }
@@ -709,6 +714,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        set_pte_at(vma->vm_mm, addr, pte,
                   pte_mkold(mk_pte(page, vma->vm_page_prot)));
        page_add_anon_rmap(page, vma, addr);
+       mem_cgroup_commit_charge_swapin(page, ptr);
        swap_free(entry);
        /*
         * Move the page to the active list so it is not
@@ -1371,26 +1377,6 @@ out:
        return ret;
 }
 
-#if 0  /* We don't need this yet */
-#include <linux/backing-dev.h>
-int page_queue_congested(struct page *page)
-{
-       struct backing_dev_info *bdi;
-
-       VM_BUG_ON(!PageLocked(page));   /* It pins the swap_info_struct */
-
-       if (PageSwapCache(page)) {
-               swp_entry_t entry = { .val = page_private(page) };
-               struct swap_info_struct *sis;
-
-               sis = get_swap_info_struct(swp_type(entry));
-               bdi = sis->bdev->bd_inode->i_mapping->backing_dev_info;
-       } else
-               bdi = page->mapping->backing_dev_info;
-       return bdi_write_congested(bdi);
-}
-#endif
-
 asmlinkage long sys_swapoff(const char __user * specialfile)
 {
        struct swap_info_struct * p = NULL;
@@ -1511,6 +1497,9 @@ asmlinkage long sys_swapoff(const char __user * specialfile)
        spin_unlock(&swap_lock);
        mutex_unlock(&swapon_mutex);
        vfree(swap_map);
+       /* Destroy swap account informatin */
+       swap_cgroup_swapoff(type);
+
        inode = mapping->host;
        if (S_ISBLK(inode->i_mode)) {
                struct block_device *bdev = I_BDEV(inode);
@@ -1828,6 +1817,11 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
                }
                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 */;
@@ -1851,7 +1845,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
 
        if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
                p->flags |= SWP_SOLIDSTATE;
-               srandom32((u32)get_seconds());
                p->cluster_next = 1 + (random32() % p->highest_bit);
        }
        if (discard_swap(p) == 0)
@@ -1900,6 +1893,7 @@ bad_swap:
                bd_release(bdev);
        }
        destroy_swap_extents(p);
+       swap_cgroup_swapoff(type);
 bad_swap_2:
        spin_lock(&swap_lock);
        p->swap_file = NULL;