aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2016-03-09 17:08:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-09 18:43:42 -0500
commitd77a117e6871ff78a06def46583d23752593de60 (patch)
tree79bf0536897d69bcca3832dd77f4ac1ce6ec034e
parent06b241f32c711d7ca868a0351dd97fe91fd8817b (diff)
list: kill list_force_poison()
Given we have uninitialized list_heads being passed to list_add() it will always be the case that those uninitialized values randomly trigger the poison value. Especially since a list_add() operation will seed the stack with the poison value for later stack allocations to trip over. For example, see these two false positive reports: list_add attempted on force-poisoned entry WARNING: at lib/list_debug.c:34 [..] NIP [c00000000043c390] __list_add+0xb0/0x150 LR [c00000000043c38c] __list_add+0xac/0x150 Call Trace: __list_add+0xac/0x150 (unreliable) __down+0x4c/0xf8 down+0x68/0x70 xfs_buf_lock+0x4c/0x150 [xfs] list_add attempted on force-poisoned entry(0000000000000500), new->next == d0000000059ecdb0, new->prev == 0000000000000500 WARNING: at lib/list_debug.c:33 [..] NIP [c00000000042db78] __list_add+0xa8/0x140 LR [c00000000042db74] __list_add+0xa4/0x140 Call Trace: __list_add+0xa4/0x140 (unreliable) rwsem_down_read_failed+0x6c/0x1a0 down_read+0x58/0x60 xfs_log_commit_cil+0x7c/0x600 [xfs] Fixes: commit 5c2c2587b132 ("mm, dax, pmem: introduce {get|put}_dev_pagemap() for dax-gup") Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reported-by: Eryu Guan <eguan@redhat.com> Tested-by: Eryu Guan <eguan@redhat.com> Cc: Ross Zwisler <ross.zwisler@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/list.h11
-rw-r--r--kernel/memremap.c9
-rw-r--r--lib/list_debug.c9
3 files changed, 7 insertions, 22 deletions
diff --git a/include/linux/list.h b/include/linux/list.h
index 30cf4200ab40..5356f4d661a7 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -113,17 +113,6 @@ extern void __list_del_entry(struct list_head *entry);
113extern void list_del(struct list_head *entry); 113extern void list_del(struct list_head *entry);
114#endif 114#endif
115 115
116#ifdef CONFIG_DEBUG_LIST
117/*
118 * See devm_memremap_pages() which wants DEBUG_LIST=y to assert if one
119 * of the pages it allocates is ever passed to list_add()
120 */
121extern void list_force_poison(struct list_head *entry);
122#else
123/* fallback to the less strict LIST_POISON* definitions */
124#define list_force_poison list_del
125#endif
126
127/** 116/**
128 * list_replace - replace old entry by new one 117 * list_replace - replace old entry by new one
129 * @old : the element to be replaced 118 * @old : the element to be replaced
diff --git a/kernel/memremap.c b/kernel/memremap.c
index b981a7b023f0..778191e3e887 100644
--- a/kernel/memremap.c
+++ b/kernel/memremap.c
@@ -351,8 +351,13 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
351 for_each_device_pfn(pfn, page_map) { 351 for_each_device_pfn(pfn, page_map) {
352 struct page *page = pfn_to_page(pfn); 352 struct page *page = pfn_to_page(pfn);
353 353
354 /* ZONE_DEVICE pages must never appear on a slab lru */ 354 /*
355 list_force_poison(&page->lru); 355 * ZONE_DEVICE pages union ->lru with a ->pgmap back
356 * pointer. It is a bug if a ZONE_DEVICE page is ever
357 * freed or placed on a driver-private list. Seed the
358 * storage with LIST_POISON* values.
359 */
360 list_del(&page->lru);
356 page->pgmap = pgmap; 361 page->pgmap = pgmap;
357 } 362 }
358 devres_add(dev, page_map); 363 devres_add(dev, page_map);
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3345a089ef7b..3859bf63561c 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -12,13 +12,6 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/rculist.h> 13#include <linux/rculist.h>
14 14
15static struct list_head force_poison;
16void list_force_poison(struct list_head *entry)
17{
18 entry->next = &force_poison;
19 entry->prev = &force_poison;
20}
21
22/* 15/*
23 * Insert a new entry between two known consecutive entries. 16 * Insert a new entry between two known consecutive entries.
24 * 17 *
@@ -30,8 +23,6 @@ void __list_add(struct list_head *new,
30 struct list_head *prev, 23 struct list_head *prev,
31 struct list_head *next) 24 struct list_head *next)
32{ 25{
33 WARN(new->next == &force_poison || new->prev == &force_poison,
34 "list_add attempted on force-poisoned entry\n");
35 WARN(next->prev != prev, 26 WARN(next->prev != prev,
36 "list_add corruption. next->prev should be " 27 "list_add corruption. next->prev should be "
37 "prev (%p), but was %p. (next=%p).\n", 28 "prev (%p), but was %p. (next=%p).\n",