aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorNick Piggin <piggin@cyberone.com.au>2006-04-09 21:21:48 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-10 13:16:37 -0400
commit676165a8af7167f488abdcce6851a9bc36e83254 (patch)
treea9b2b8dc155b48ce073b5ada31f2ac0694118e69 /include/linux
parentc3a9d6541f84ac3ff566982d08389b87c1c36b4e (diff)
[PATCH] Fix buddy list race that could lead to page lru list corruptions
Rohit found an obscure bug causing buddy list corruption. page_is_buddy is using a non-atomic test (PagePrivate && page_count == 0) to determine whether or not a free page's buddy is itself free and in the buddy lists. Each of the conjuncts may be true at different times due to unrelated conditions, so the non-atomic page_is_buddy test may find each conjunct to be true even if they were not both true at the same time (ie. the page was not on the buddy lists). Signed-off-by: Martin Bligh <mbligh@google.com> Signed-off-by: Rohit Seth <rohitseth@google.com> Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mm.h5
-rw-r--r--include/linux/page-flags.h8
2 files changed, 9 insertions, 4 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6aa016f1d3ae..1154684209a4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -229,10 +229,9 @@ struct page {
229 unsigned long private; /* Mapping-private opaque data: 229 unsigned long private; /* Mapping-private opaque data:
230 * usually used for buffer_heads 230 * usually used for buffer_heads
231 * if PagePrivate set; used for 231 * if PagePrivate set; used for
232 * swp_entry_t if PageSwapCache. 232 * swp_entry_t if PageSwapCache;
233 * When page is free, this
234 * indicates order in the buddy 233 * indicates order in the buddy
235 * system. 234 * system if PG_buddy is set.
236 */ 235 */
237 struct address_space *mapping; /* If low bit clear, points to 236 struct address_space *mapping; /* If low bit clear, points to
238 * inode address_space, or NULL. 237 * inode address_space, or NULL.
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 9ea629c02a4b..547aac7696cd 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -74,7 +74,9 @@
74#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ 74#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */
75#define PG_reclaim 17 /* To be reclaimed asap */ 75#define PG_reclaim 17 /* To be reclaimed asap */
76#define PG_nosave_free 18 /* Free, should not be written */ 76#define PG_nosave_free 18 /* Free, should not be written */
77#define PG_uncached 19 /* Page has been mapped as uncached */ 77#define PG_buddy 19 /* Page is free, on buddy lists */
78
79#define PG_uncached 20 /* Page has been mapped as uncached */
78 80
79/* 81/*
80 * Global page accounting. One instance per CPU. Only unsigned longs are 82 * Global page accounting. One instance per CPU. Only unsigned longs are
@@ -317,6 +319,10 @@ extern void __mod_page_state_offset(unsigned long offset, unsigned long delta);
317#define SetPageNosaveFree(page) set_bit(PG_nosave_free, &(page)->flags) 319#define SetPageNosaveFree(page) set_bit(PG_nosave_free, &(page)->flags)
318#define ClearPageNosaveFree(page) clear_bit(PG_nosave_free, &(page)->flags) 320#define ClearPageNosaveFree(page) clear_bit(PG_nosave_free, &(page)->flags)
319 321
322#define PageBuddy(page) test_bit(PG_buddy, &(page)->flags)
323#define __SetPageBuddy(page) __set_bit(PG_buddy, &(page)->flags)
324#define __ClearPageBuddy(page) __clear_bit(PG_buddy, &(page)->flags)
325
320#define PageMappedToDisk(page) test_bit(PG_mappedtodisk, &(page)->flags) 326#define PageMappedToDisk(page) test_bit(PG_mappedtodisk, &(page)->flags)
321#define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags) 327#define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags)
322#define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags) 328#define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags)