memcg: fix deadlock between lock_page_cgroup and mapping tree_lock
[sfrench/cifs-2.6.git] / mm / swap_state.c
index 3353c9029cef1cdf4b3f86231bc931b0d732f540..1416e7e9e02db3b5da60fe3a270e98e7b84024bb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/backing-dev.h>
 #include <linux/pagevec.h>
 #include <linux/migrate.h>
+#include <linux/page_cgroup.h>
 
 #include <asm/pgtable.h>
 
@@ -72,10 +73,10 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
 {
        int error;
 
-       BUG_ON(!PageLocked(page));
-       BUG_ON(PageSwapCache(page));
-       BUG_ON(PagePrivate(page));
-       BUG_ON(!PageSwapBacked(page));
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(PageSwapCache(page));
+       VM_BUG_ON(!PageSwapBacked(page));
+
        error = radix_tree_preload(gfp_mask);
        if (!error) {
                page_cache_get(page);
@@ -108,10 +109,9 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
  */
 void __delete_from_swap_cache(struct page *page)
 {
-       BUG_ON(!PageLocked(page));
-       BUG_ON(!PageSwapCache(page));
-       BUG_ON(PageWriteback(page));
-       BUG_ON(PagePrivate(page));
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(!PageSwapCache(page));
+       VM_BUG_ON(PageWriteback(page));
 
        radix_tree_delete(&swapper_space.page_tree, page_private(page));
        set_page_private(page, 0);
@@ -129,13 +129,13 @@ void __delete_from_swap_cache(struct page *page)
  * Allocate swap space for the page and add the page to the
  * swap cache.  Caller needs to hold the page lock. 
  */
-int add_to_swap(struct page * page, gfp_t gfp_mask)
+int add_to_swap(struct page *page)
 {
        swp_entry_t entry;
        int err;
 
-       BUG_ON(!PageLocked(page));
-       BUG_ON(!PageUptodate(page));
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(!PageUptodate(page));
 
        for (;;) {
                entry = get_swap_page();
@@ -154,7 +154,7 @@ int add_to_swap(struct page * page, gfp_t gfp_mask)
                 * Add it to the swap cache and mark it dirty
                 */
                err = add_to_swap_cache(page, entry,
-                               gfp_mask|__GFP_NOMEMALLOC|__GFP_NOWARN);
+                               __GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN);
 
                switch (err) {
                case 0:                         /* Success */
@@ -188,6 +188,7 @@ void delete_from_swap_cache(struct page *page)
        __delete_from_swap_cache(page);
        spin_unlock_irq(&swapper_space.tree_lock);
 
+       mem_cgroup_uncharge_swapcache(page, entry);
        swap_free(entry);
        page_cache_release(page);
 }
@@ -196,14 +197,14 @@ void delete_from_swap_cache(struct page *page)
  * If we are the only user, then try to free up the swap cache. 
  * 
  * Its ok to check for PageSwapCache without the page lock
- * here because we are going to recheck again inside 
- * exclusive_swap_page() _with_ the lock. 
+ * here because we are going to recheck again inside
+ * try_to_free_swap() _with_ the lock.
  *                                     - Marcelo
  */
 static inline void free_swap_cache(struct page *page)
 {
-       if (PageSwapCache(page) && trylock_page(page)) {
-               remove_exclusive_swap_page(page);
+       if (PageSwapCache(page) && !page_mapped(page) && trylock_page(page)) {
+               try_to_free_swap(page);
                unlock_page(page);
        }
 }