extern void mem_cgroup_uncharge_page(struct page *page);
 extern void mem_cgroup_uncharge_cache_page(struct page *page);
 extern void mem_cgroup_move_lists(struct page *page, bool active);
+extern int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask);
+
 extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
                                        struct list_head *dst,
                                        unsigned long *scanned, int order,
 {
 }
 
+static inline int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask)
+{
+       return 0;
+}
+
 static inline void mem_cgroup_move_lists(struct page *page, bool active)
 {
 }
 
                mem_cgroup_uncharge_page(newpage);
 }
 
+/*
+ * A call to try to shrink memory usage under specified resource controller.
+ * This is typically used for page reclaiming for shmem for reducing side
+ * effect of page allocation from shmem, which is used by some mem_cgroup.
+ */
+int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask)
+{
+       struct mem_cgroup *mem;
+       int progress = 0;
+       int retry = MEM_CGROUP_RECLAIM_RETRIES;
+
+       rcu_read_lock();
+       mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
+       css_get(&mem->css);
+       rcu_read_unlock();
+
+       do {
+               progress = try_to_free_mem_cgroup_pages(mem, gfp_mask);
+       } while (!progress && --retry);
+
+       css_put(&mem->css);
+       if (!retry)
+               return -ENOMEM;
+       return 0;
+}
+
 /*
  * This routine traverse page_cgroup in given list and drop them all.
  * *And* this routine doesn't reclaim page itself, just removes page_cgroup.
 
                        shmem_swp_unmap(entry);
                        spin_unlock(&info->lock);
                        unlock_page(swappage);
+                       page_cache_release(swappage);
                        if (error == -ENOMEM) {
                                /* allow reclaim from this memory cgroup */
-                               error = mem_cgroup_cache_charge(swappage,
-                                       current->mm, gfp & ~__GFP_HIGHMEM);
-                               if (error) {
-                                       page_cache_release(swappage);
+                               error = mem_cgroup_shrink_usage(current->mm,
+                                                               gfp);
+                               if (error)
                                        goto failed;
-                               }
-                               mem_cgroup_uncharge_cache_page(swappage);
                        }
-                       page_cache_release(swappage);
                        goto repeat;
                }
        } else if (sgp == SGP_READ && !filepage) {