diff options
-rw-r--r-- | include/linux/page_cgroup.h | 5 | ||||
-rw-r--r-- | mm/memcontrol.c | 66 |
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 | ||
102 | static inline int page_is_cgroup_locked(struct page_cgroup *pc) | ||
103 | { | ||
104 | return bit_spin_is_locked(PCG_LOCK, &pc->flags); | ||
105 | } | ||
106 | |||
107 | static inline void move_lock_page_cgroup(struct page_cgroup *pc, | 102 | static 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 | 2219 | static int mem_cgroup_move_account(struct page_cgroup *pc, | |
2219 | static 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 | /* | 2271 | unlock: |
2256 | * check whether the @pc is valid for moving account and call | ||
2257 | * __mem_cgroup_move_account() | ||
2258 | */ | ||
2259 | static 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); |
2278 | out: | ||
2287 | return ret; | 2279 | return ret; |
2288 | } | 2280 | } |
2289 | 2281 | ||