aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Khlebnikov <k.khlebnikov@samsung.com>2014-10-09 18:29:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 22:26:01 -0400
commitd6d86c0a7f8ddc5b38cf089222cb1d9540762dc2 (patch)
tree839bdb8072211f053a800c25aab3e3da1d30c9ed
parent29e5694054149acd25b0d5538c95fb6d64478315 (diff)
mm/balloon_compaction: redesign ballooned pages management
Sasha Levin reported KASAN splash inside isolate_migratepages_range(). Problem is in the function __is_movable_balloon_page() which tests AS_BALLOON_MAP in page->mapping->flags. This function has no protection against anonymous pages. As result it tried to check address space flags inside struct anon_vma. Further investigation shows more problems in current implementation: * Special branch in __unmap_and_move() never works: balloon_page_movable() checks page flags and page_count. In __unmap_and_move() page is locked, reference counter is elevated, thus balloon_page_movable() always fails. As a result execution goes to the normal migration path. virtballoon_migratepage() returns MIGRATEPAGE_BALLOON_SUCCESS instead of MIGRATEPAGE_SUCCESS, move_to_new_page() thinks this is an error code and assigns newpage->mapping to NULL. Newly migrated page lose connectivity with balloon an all ability for further migration. * lru_lock erroneously required in isolate_migratepages_range() for isolation ballooned page. This function releases lru_lock periodically, this makes migration mostly impossible for some pages. * balloon_page_dequeue have a tight race with balloon_page_isolate: balloon_page_isolate could be executed in parallel with dequeue between picking page from list and locking page_lock. Race is rare because they use trylock_page() for locking. This patch fixes all of them. Instead of fake mapping with special flag this patch uses special state of page->_mapcount: PAGE_BALLOON_MAPCOUNT_VALUE = -256. Buddy allocator uses PAGE_BUDDY_MAPCOUNT_VALUE = -128 for similar purpose. Storing mark directly in struct page makes everything safer and easier. PagePrivate is used to mark pages present in page list (i.e. not isolated, like PageLRU for normal pages). It replaces special rules for reference counter and makes balloon migration similar to migration of normal pages. This flag is protected by page_lock together with link to the balloon device. Signed-off-by: Konstantin Khlebnikov <k.khlebnikov@samsung.com> Reported-by: Sasha Levin <sasha.levin@oracle.com> Link: http://lkml.kernel.org/p/53E6CEAA.9020105@oracle.com Cc: Rafael Aquini <aquini@redhat.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: <stable@vger.kernel.org> [3.8+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/virtio/virtio_balloon.c15
-rw-r--r--include/linux/balloon_compaction.h97
-rw-r--r--include/linux/migrate.h11
-rw-r--r--include/linux/mm.h19
-rw-r--r--mm/balloon_compaction.c26
-rw-r--r--mm/compaction.c2
-rw-r--r--mm/migrate.c16
7 files changed, 68 insertions, 118 deletions
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 25ebe8eecdb7..c3eb93fc9261 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -163,8 +163,8 @@ static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
163 /* Find pfns pointing at start of each page, get pages and free them. */ 163 /* Find pfns pointing at start of each page, get pages and free them. */
164 for (i = 0; i < num; i += VIRTIO_BALLOON_PAGES_PER_PAGE) { 164 for (i = 0; i < num; i += VIRTIO_BALLOON_PAGES_PER_PAGE) {
165 struct page *page = balloon_pfn_to_page(pfns[i]); 165 struct page *page = balloon_pfn_to_page(pfns[i]);
166 balloon_page_free(page);
167 adjust_managed_page_count(page, 1); 166 adjust_managed_page_count(page, 1);
167 put_page(page); /* balloon reference */
168 } 168 }
169} 169}
170 170
@@ -395,6 +395,8 @@ static int virtballoon_migratepage(struct address_space *mapping,
395 if (!mutex_trylock(&vb->balloon_lock)) 395 if (!mutex_trylock(&vb->balloon_lock))
396 return -EAGAIN; 396 return -EAGAIN;
397 397
398 get_page(newpage); /* balloon reference */
399
398 /* balloon's page migration 1st step -- inflate "newpage" */ 400 /* balloon's page migration 1st step -- inflate "newpage" */
399 spin_lock_irqsave(&vb_dev_info->pages_lock, flags); 401 spin_lock_irqsave(&vb_dev_info->pages_lock, flags);
400 balloon_page_insert(newpage, mapping, &vb_dev_info->pages); 402 balloon_page_insert(newpage, mapping, &vb_dev_info->pages);
@@ -404,12 +406,7 @@ static int virtballoon_migratepage(struct address_space *mapping,
404 set_page_pfns(vb->pfns, newpage); 406 set_page_pfns(vb->pfns, newpage);
405 tell_host(vb, vb->inflate_vq); 407 tell_host(vb, vb->inflate_vq);
406 408
407 /* 409 /* balloon's page migration 2nd step -- deflate "page" */
408 * balloon's page migration 2nd step -- deflate "page"
409 *
410 * It's safe to delete page->lru here because this page is at
411 * an isolated migration list, and this step is expected to happen here
412 */
413 balloon_page_delete(page); 410 balloon_page_delete(page);
414 vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE; 411 vb->num_pfns = VIRTIO_BALLOON_PAGES_PER_PAGE;
415 set_page_pfns(vb->pfns, page); 412 set_page_pfns(vb->pfns, page);
@@ -417,7 +414,9 @@ static int virtballoon_migratepage(struct address_space *mapping,
417 414
418 mutex_unlock(&vb->balloon_lock); 415 mutex_unlock(&vb->balloon_lock);
419 416
420 return MIGRATEPAGE_BALLOON_SUCCESS; 417 put_page(page); /* balloon reference */
418
419 return MIGRATEPAGE_SUCCESS;
421} 420}
422 421
423/* define the balloon_mapping->a_ops callback to allow balloon page migration */ 422/* define the balloon_mapping->a_ops callback to allow balloon page migration */
diff --git a/include/linux/balloon_compaction.h b/include/linux/balloon_compaction.h
index 089743ade734..38aa07d5b81c 100644
--- a/include/linux/balloon_compaction.h
+++ b/include/linux/balloon_compaction.h
@@ -27,10 +27,13 @@
27 * counter raised only while it is under our special handling; 27 * counter raised only while it is under our special handling;
28 * 28 *
29 * iii. after the lockless scan step have selected a potential balloon page for 29 * iii. after the lockless scan step have selected a potential balloon page for
30 * isolation, re-test the page->mapping flags and the page ref counter 30 * isolation, re-test the PageBalloon mark and the PagePrivate flag
31 * under the proper page lock, to ensure isolating a valid balloon page 31 * under the proper page lock, to ensure isolating a valid balloon page
32 * (not yet isolated, nor under release procedure) 32 * (not yet isolated, nor under release procedure)
33 * 33 *
34 * iv. isolation or dequeueing procedure must clear PagePrivate flag under
35 * page lock together with removing page from balloon device page list.
36 *
34 * The functions provided by this interface are placed to help on coping with 37 * The functions provided by this interface are placed to help on coping with
35 * the aforementioned balloon page corner case, as well as to ensure the simple 38 * the aforementioned balloon page corner case, as well as to ensure the simple
36 * set of exposed rules are satisfied while we are dealing with balloon pages 39 * set of exposed rules are satisfied while we are dealing with balloon pages
@@ -71,28 +74,6 @@ static inline void balloon_devinfo_free(struct balloon_dev_info *b_dev_info)
71 kfree(b_dev_info); 74 kfree(b_dev_info);
72} 75}
73 76
74/*
75 * balloon_page_free - release a balloon page back to the page free lists
76 * @page: ballooned page to be set free
77 *
78 * This function must be used to properly set free an isolated/dequeued balloon
79 * page at the end of a sucessful page migration, or at the balloon driver's
80 * page release procedure.
81 */
82static inline void balloon_page_free(struct page *page)
83{
84 /*
85 * Balloon pages always get an extra refcount before being isolated
86 * and before being dequeued to help on sorting out fortuite colisions
87 * between a thread attempting to isolate and another thread attempting
88 * to release the very same balloon page.
89 *
90 * Before we handle the page back to Buddy, lets drop its extra refcnt.
91 */
92 put_page(page);
93 __free_page(page);
94}
95
96#ifdef CONFIG_BALLOON_COMPACTION 77#ifdef CONFIG_BALLOON_COMPACTION
97extern bool balloon_page_isolate(struct page *page); 78extern bool balloon_page_isolate(struct page *page);
98extern void balloon_page_putback(struct page *page); 79extern void balloon_page_putback(struct page *page);
@@ -108,74 +89,33 @@ static inline void balloon_mapping_free(struct address_space *balloon_mapping)
108} 89}
109 90
110/* 91/*
111 * page_flags_cleared - helper to perform balloon @page ->flags tests. 92 * __is_movable_balloon_page - helper to perform @page PageBalloon tests
112 *
113 * As balloon pages are obtained from buddy and we do not play with page->flags
114 * at driver level (exception made when we get the page lock for compaction),
115 * we can safely identify a ballooned page by checking if the
116 * PAGE_FLAGS_CHECK_AT_PREP page->flags are all cleared. This approach also
117 * helps us skip ballooned pages that are locked for compaction or release, thus
118 * mitigating their racy check at balloon_page_movable()
119 */
120static inline bool page_flags_cleared(struct page *page)
121{
122 return !(page->flags & PAGE_FLAGS_CHECK_AT_PREP);
123}
124
125/*
126 * __is_movable_balloon_page - helper to perform @page mapping->flags tests
127 */ 93 */
128static inline bool __is_movable_balloon_page(struct page *page) 94static inline bool __is_movable_balloon_page(struct page *page)
129{ 95{
130 struct address_space *mapping = page->mapping; 96 return PageBalloon(page);
131 return mapping_balloon(mapping);
132} 97}
133 98
134/* 99/*
135 * balloon_page_movable - test page->mapping->flags to identify balloon pages 100 * balloon_page_movable - test PageBalloon to identify balloon pages
136 * that can be moved by compaction/migration. 101 * and PagePrivate to check that the page is not
137 * 102 * isolated and can be moved by compaction/migration.
138 * This function is used at core compaction's page isolation scheme, therefore
139 * most pages exposed to it are not enlisted as balloon pages and so, to avoid
140 * undesired side effects like racing against __free_pages(), we cannot afford
141 * holding the page locked while testing page->mapping->flags here.
142 * 103 *
143 * As we might return false positives in the case of a balloon page being just 104 * As we might return false positives in the case of a balloon page being just
144 * released under us, the page->mapping->flags need to be re-tested later, 105 * released under us, this need to be re-tested later, under the page lock.
145 * under the proper page lock, at the functions that will be coping with the
146 * balloon page case.
147 */ 106 */
148static inline bool balloon_page_movable(struct page *page) 107static inline bool balloon_page_movable(struct page *page)
149{ 108{
150 /* 109 return PageBalloon(page) && PagePrivate(page);
151 * Before dereferencing and testing mapping->flags, let's make sure
152 * this is not a page that uses ->mapping in a different way
153 */