diff options
author | Hugh Dickins <hugh@veritas.com> | 2008-03-04 17:29:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-03-04 19:35:15 -0500 |
commit | 9442ec9df40d952b0de185ae5638a74970388e01 (patch) | |
tree | 14b06d71203be119d93736464ca49f37ce402c1c /mm/memcontrol.c | |
parent | 98837c7f82ef78aa38f40462aa2fcac68fd3acbf (diff) |
memcg: bad page if page_cgroup when free
Replace free_hot_cold_page's VM_BUG_ON(page_get_page_cgroup(page)) by a "Bad
page state" and clear: most users don't have CONFIG_DEBUG_VM on, and if it
were set here, it'd likely cause corruption when the page is reused.
Don't use page_assign_page_cgroup to clear it: that should be private to
memcontrol.c, and always called with the lock taken; and memmap_init_zone
doesn't need it either - like page->mapping and other pointers throughout the
kernel, Linux assumes pointers in zeroed structures are NULL pointers.
Instead use page_reset_bad_cgroup, added to memcontrol.h for this only.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: David Rientjes <rientjes@google.com>
Acked-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Hirokazu Takahashi <taka@valinux.co.jp>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Cc: Paul Menage <menage@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 27 |
1 files changed, 12 insertions, 15 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index afdd406f618a..9e170d3c71e5 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -140,11 +140,17 @@ struct mem_cgroup { | |||
140 | 140 | ||
141 | /* | 141 | /* |
142 | * We use the lower bit of the page->page_cgroup pointer as a bit spin | 142 | * We use the lower bit of the page->page_cgroup pointer as a bit spin |
143 | * lock. We need to ensure that page->page_cgroup is atleast two | 143 | * lock. We need to ensure that page->page_cgroup is at least two |
144 | * byte aligned (based on comments from Nick Piggin) | 144 | * byte aligned (based on comments from Nick Piggin). But since |
145 | * bit_spin_lock doesn't actually set that lock bit in a non-debug | ||
146 | * uniprocessor kernel, we should avoid setting it here too. | ||
145 | */ | 147 | */ |
146 | #define PAGE_CGROUP_LOCK_BIT 0x0 | 148 | #define PAGE_CGROUP_LOCK_BIT 0x0 |
147 | #define PAGE_CGROUP_LOCK (1 << PAGE_CGROUP_LOCK_BIT) | 149 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) |
150 | #define PAGE_CGROUP_LOCK (1 << PAGE_CGROUP_LOCK_BIT) | ||
151 | #else | ||
152 | #define PAGE_CGROUP_LOCK 0x0 | ||
153 | #endif | ||
148 | 154 | ||
149 | /* | 155 | /* |
150 | * A page_cgroup page is associated with every page descriptor. The | 156 | * A page_cgroup page is associated with every page descriptor. The |
@@ -271,19 +277,10 @@ static inline int page_cgroup_locked(struct page *page) | |||
271 | &page->page_cgroup); | 277 | &page->page_cgroup); |
272 | } | 278 | } |
273 | 279 | ||
274 | void page_assign_page_cgroup(struct page *page, struct page_cgroup *pc) | 280 | static void page_assign_page_cgroup(struct page *page, struct page_cgroup *pc) |
275 | { | 281 | { |
276 | int locked; | 282 | VM_BUG_ON(!page_cgroup_locked(page)); |
277 | 283 | page->page_cgroup = ((unsigned long)pc | PAGE_CGROUP_LOCK); | |
278 | /* | ||
279 | * While resetting the page_cgroup we might not hold the | ||
280 | * page_cgroup lock. free_hot_cold_page() is an example | ||
281 | * of such a scenario | ||
282 | */ | ||
283 | if (pc) | ||
284 | VM_BUG_ON(!page_cgroup_locked(page)); | ||
285 | locked = (page->page_cgroup & PAGE_CGROUP_LOCK); | ||
286 | page->page_cgroup = ((unsigned long)pc | locked); | ||
287 | } | 284 | } |
288 | 285 | ||
289 | struct page_cgroup *page_get_page_cgroup(struct page *page) | 286 | struct page_cgroup *page_get_page_cgroup(struct page *page) |