aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/page_cgroup.h5
-rw-r--r--mm/memcontrol.c66
2 files changed, 29 insertions, 42 deletions
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index 363bbc8b0f49..6b63679ce8a1 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -99,11 +99,6 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc)
99 bit_spin_unlock(PCG_LOCK, &pc->flags); 99 bit_spin_unlock(PCG_LOCK, &pc->flags);
100} 100}
101 101
102static inline int page_is_cgroup_locked(struct page_cgroup *pc)
103{
104 return bit_spin_is_locked(PCG_LOCK, &pc->flags);
105}
106
107static inline void move_lock_page_cgroup(struct page_cgroup *pc, 102static inline void move_lock_page_cgroup(struct page_cgroup *pc,
108 unsigned long *flags) 103 unsigned long *flags)
109{ 104{
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2881c9ef969a..e9d33dc151a5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2200,33 +2200,49 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
2200#endif 2200#endif
2201 2201
2202/** 2202/**
2203 * __mem_cgroup_move_account - move account of the page 2203 * mem_cgroup_move_account - move account of the page
2204 * @pc: page_cgroup of the page. 2204 * @pc: page_cgroup of the page.
2205 * @from: mem_cgroup which the page is moved from. 2205 * @from: mem_cgroup which the page is moved from.
2206 * @to: mem_cgroup which the page is moved to. @from != @to. 2206 * @to: mem_cgroup which the page is moved to. @from != @to.
2207 * @uncharge: whether we should call uncharge and css_put against @from. 2207 * @uncharge: whether we should call uncharge and css_put against @from.
2208 * @charge_size: number of bytes to charge (regular or huge page)
2208 * 2209 *
2209 * The caller must confirm following. 2210 * The caller must confirm following.
2210 * - page is not on LRU (isolate_page() is useful.) 2211 * - page is not on LRU (isolate_page() is useful.)
2211 * - the pc is locked, used, and ->mem_cgroup points to @from. 2212 * - compound_lock is held when charge_size > PAGE_SIZE
2212 * 2213 *
2213 * This function doesn't do "charge" nor css_get to new cgroup. It should be 2214 * This function doesn't do "charge" nor css_get to new cgroup. It should be
2214 * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is 2215 * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is
2215 * true, this function does "uncharge" from old cgroup, but it doesn't if 2216 * true, this function does "uncharge" from old cgroup, but it doesn't if
2216 * @uncharge is false, so a caller should do "uncharge". 2217 * @uncharge is false, so a caller should do "uncharge".
2217 */ 2218 */
2218 2219static int mem_cgroup_move_account(struct page_cgroup *pc,
2219static void __mem_cgroup_move_account(struct page_cgroup *pc, 2220 struct mem_cgroup *from, struct mem_cgroup *to,
2220 struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge, 2221 bool uncharge, int charge_size)
2221 int charge_size)
2222{ 2222{
2223 int nr_pages = charge_size >> PAGE_SHIFT; 2223 int nr_pages = charge_size >> PAGE_SHIFT;
2224 unsigned long flags;
2225 int ret;
2224 2226
2225 VM_BUG_ON(from == to); 2227 VM_BUG_ON(from == to);
2226 VM_BUG_ON(PageLRU(pc->page)); 2228 VM_BUG_ON(PageLRU(pc->page));
2227 VM_BUG_ON(!page_is_cgroup_locked(pc)); 2229 /*
2228 VM_BUG_ON(!PageCgroupUsed(pc)); 2230 * The page is isolated from LRU. So, collapse function
2229 VM_BUG_ON(pc->mem_cgroup != from); 2231 * will not handle this page. But page splitting can happen.
2232 * Do this check under compound_page_lock(). The caller should
2233 * hold it.
2234 */
2235 ret = -EBUSY;
2236 if (charge_size > PAGE_SIZE && !PageTransHuge(pc->page))
2237 goto out;
2238
2239 lock_page_cgroup(pc);
2240
2241 ret = -EINVAL;
2242 if (!PageCgroupUsed(pc) || pc->mem_cgroup != from)
2243 goto unlock;
2244
2245 move_lock_page_cgroup(pc, &flags);
2230 2246
2231 if (PageCgroupFileMapped(pc)) { 2247 if (PageCgroupFileMapped(pc)) {
2232 /* Update mapped_file data for mem_cgroup */ 2248 /* Update mapped_file data for mem_cgroup */
@@ -2250,40 +2266,16 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
2250 * garanteed that "to" is never removed. So, we don't check rmdir 2266 * garanteed that "to" is never removed. So, we don't check rmdir
2251 * status here. 2267 * status here.
2252 */ 2268 */
2253} 2269 move_unlock_page_cgroup(pc, &flags);
2254 2270 ret = 0;
2255/* 2271unlock:
2256 * check whether the @pc is valid for moving account and call
2257 * __mem_cgroup_move_account()
2258 */
2259static int mem_cgroup_move_account(struct page_cgroup *pc,
2260 struct mem_cgroup *from, struct mem_cgroup *to,
2261 bool uncharge, int charge_size)
2262{
2263 int ret = -EINVAL;
2264 unsigned long flags;
2265 /*
2266 * The page is isolated from LRU. So, collapse function
2267 * will not handle this page. But page splitting can happen.
2268 * Do this check under compound_page_lock(). The caller should
2269 * hold it.
2270 */
2271 if ((charge_size > PAGE_SIZE) && !PageTransHuge(pc->page))
2272 return -EBUSY;
2273
2274 lock_page_cgroup(pc);
2275 if (PageCgroupUsed(pc) && pc->mem_cgroup == from) {
2276 move_lock_page_cgroup(pc, &flags);
2277 __mem_cgroup_move_account(pc, from, to, uncharge, charge_size);
2278 move_unlock_page_cgroup(pc, &flags);
2279 ret = 0;
2280 }
2281 unlock_page_cgroup(pc); 2272 unlock_page_cgroup(pc);
2282 /* 2273 /*
2283 * check events 2274 * check events
2284 */ 2275 */
2285 memcg_check_events(to, pc->page); 2276 memcg_check_events(to, pc->page);
2286 memcg_check_events(from, pc->page); 2277 memcg_check_events(from, pc->page);
2278out:
2287 return ret; 2279 return ret;
2288} 2280}
2289 2281