|
@@ -536,28 +536,6 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
|
|
|
if (mem_cgroup_subsys.disabled)
|
|
|
return 0;
|
|
|
|
|
|
- /*
|
|
|
- * Should page_cgroup's go to their own slab?
|
|
|
- * One could optimize the performance of the charging routine
|
|
|
- * by saving a bit in the page_flags and using it as a lock
|
|
|
- * to see if the cgroup page already has a page_cgroup associated
|
|
|
- * with it
|
|
|
- */
|
|
|
-retry:
|
|
|
- lock_page_cgroup(page);
|
|
|
- pc = page_get_page_cgroup(page);
|
|
|
- /*
|
|
|
- * The page_cgroup exists and
|
|
|
- * the page has already been accounted.
|
|
|
- */
|
|
|
- if (unlikely(pc)) {
|
|
|
- VM_BUG_ON(pc->page != page);
|
|
|
- VM_BUG_ON(!pc->mem_cgroup);
|
|
|
- unlock_page_cgroup(page);
|
|
|
- goto done;
|
|
|
- }
|
|
|
- unlock_page_cgroup(page);
|
|
|
-
|
|
|
pc = kmem_cache_alloc(page_cgroup_cache, gfp_mask);
|
|
|
if (unlikely(pc == NULL))
|
|
|
goto err;
|
|
@@ -618,15 +596,10 @@ retry:
|
|
|
lock_page_cgroup(page);
|
|
|
if (unlikely(page_get_page_cgroup(page))) {
|
|
|
unlock_page_cgroup(page);
|
|
|
- /*
|
|
|
- * Another charge has been added to this page already.
|
|
|
- * We take lock_page_cgroup(page) again and read
|
|
|
- * page->cgroup, increment refcnt.... just retry is OK.
|
|
|
- */
|
|
|
res_counter_uncharge(&mem->res, PAGE_SIZE);
|
|
|
css_put(&mem->css);
|
|
|
kmem_cache_free(page_cgroup_cache, pc);
|
|
|
- goto retry;
|
|
|
+ goto done;
|
|
|
}
|
|
|
page_assign_page_cgroup(page, pc);
|
|
|
|
|
@@ -665,8 +638,32 @@ int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask)
|
|
|
int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
|
|
|
gfp_t gfp_mask)
|
|
|
{
|
|
|
+ /*
|
|
|
+ * Corner case handling. This is called from add_to_page_cache()
|
|
|
+ * in usual. But some FS (shmem) precharges this page before calling it
|
|
|
+ * and call add_to_page_cache() with GFP_NOWAIT.
|
|
|
+ *
|
|
|
+ * For GFP_NOWAIT case, the page may be pre-charged before calling
|
|
|
+ * add_to_page_cache(). (See shmem.c) check it here and avoid to call
|
|
|
+ * charge twice. (It works but has to pay a bit larger cost.)
|
|
|
+ */
|
|
|
+ if (!(gfp_mask & __GFP_WAIT)) {
|
|
|
+ struct page_cgroup *pc;
|
|
|
+
|
|
|
+ lock_page_cgroup(page);
|
|
|
+ pc = page_get_page_cgroup(page);
|
|
|
+ if (pc) {
|
|
|
+ VM_BUG_ON(pc->page != page);
|
|
|
+ VM_BUG_ON(!pc->mem_cgroup);
|
|
|
+ unlock_page_cgroup(page);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ unlock_page_cgroup(page);
|
|
|
+ }
|
|
|
+
|
|
|
if (unlikely(!mm))
|
|
|
mm = &init_mm;
|
|
|
+
|
|
|
return mem_cgroup_charge_common(page, mm, gfp_mask,
|
|
|
MEM_CGROUP_CHARGE_TYPE_CACHE, NULL);
|
|
|
}
|