diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-07-23 22:24:56 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-07-24 00:18:47 -0400 |
commit | 9feed42e93d2625db86423cedf8b4b2bed00779e (patch) | |
tree | b0b7601fdd59bacaa9bbfb84b941eefe0ba1043b | |
parent | 807a827d4e7455a40e8f56ec2a67c57a91cab9f7 (diff) |
powerpc/eeh: Use safe list traversal when walking EEH devices
Currently, we're trasversing the EEH devices list using list_for_each_entry().
That's not safe enough because the EEH devices might be removed from
its parent PE while doing iteration. The patch replaces that with
list_for_each_entry_safe().
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/include/asm/eeh.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/eeh_pe.c | 10 |
3 files changed, 9 insertions, 9 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 2ce22d7b71a0..e8c411b63caf 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -74,8 +74,8 @@ struct eeh_pe { | |||
74 | struct list_head child; /* Child PEs */ | 74 | struct list_head child; /* Child PEs */ |
75 | }; | 75 | }; |
76 | 76 | ||
77 | #define eeh_pe_for_each_dev(pe, edev) \ | 77 | #define eeh_pe_for_each_dev(pe, edev, tmp) \ |
78 | list_for_each_entry(edev, &pe->edevs, list) | 78 | list_for_each_entry_safe(edev, tmp, &pe->edevs, list) |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * The struct is used to trace EEH state for the associated | 81 | * The struct is used to trace EEH state for the associated |
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index ce81477316be..56bd4584f61f 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c | |||
@@ -231,7 +231,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) | |||
231 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity) | 231 | void eeh_slot_error_detail(struct eeh_pe *pe, int severity) |
232 | { | 232 | { |
233 | size_t loglen = 0; | 233 | size_t loglen = 0; |
234 | struct eeh_dev *edev; | 234 | struct eeh_dev *edev, *tmp; |
235 | bool valid_cfg_log = true; | 235 | bool valid_cfg_log = true; |
236 | 236 | ||
237 | /* | 237 | /* |
@@ -251,7 +251,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) | |||
251 | eeh_pe_restore_bars(pe); | 251 | eeh_pe_restore_bars(pe); |
252 | 252 | ||
253 | pci_regs_buf[0] = 0; | 253 | pci_regs_buf[0] = 0; |
254 | eeh_pe_for_each_dev(pe, edev) { | 254 | eeh_pe_for_each_dev(pe, edev, tmp) { |
255 | loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, | 255 | loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, |
256 | EEH_PCI_REGS_LOG_LEN - loglen); | 256 | EEH_PCI_REGS_LOG_LEN - loglen); |
257 | } | 257 | } |
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 32ef40940bad..c8b815e45c8f 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c | |||
@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, | |||
176 | eeh_traverse_func fn, void *flag) | 176 | eeh_traverse_func fn, void *flag) |
177 | { | 177 | { |
178 | struct eeh_pe *pe; | 178 | struct eeh_pe *pe; |
179 | struct eeh_dev *edev; | 179 | struct eeh_dev *edev, *tmp; |
180 | void *ret; | 180 | void *ret; |
181 | 181 | ||
182 | if (!root) { | 182 | if (!root) { |
@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, | |||
186 | 186 | ||
187 | /* Traverse root PE */ | 187 | /* Traverse root PE */ |
188 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { | 188 | for (pe = root; pe; pe = eeh_pe_next(pe, root)) { |
189 | eeh_pe_for_each_dev(pe, edev) { | 189 | eeh_pe_for_each_dev(pe, edev, tmp) { |
190 | ret = fn(edev, flag); | 190 | ret = fn(edev, flag); |
191 | if (ret) | 191 | if (ret) |
192 | return ret; | 192 | return ret; |
@@ -501,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag) | |||
501 | { | 501 | { |
502 | struct eeh_pe *pe = (struct eeh_pe *)data; | 502 | struct eeh_pe *pe = (struct eeh_pe *)data; |
503 | int state = *((int *)flag); | 503 | int state = *((int *)flag); |
504 | struct eeh_dev *tmp; | 504 | struct eeh_dev *edev, *tmp; |
505 | struct pci_dev *pdev; | 505 | struct pci_dev *pdev; |
506 | 506 | ||
507 | /* | 507 | /* |
@@ -511,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag) | |||
511 | * the PCI device driver. | 511 | * the PCI device driver. |
512 | */ | 512 | */ |
513 | pe->state |= state; | 513 | pe->state |= state; |
514 | eeh_pe_for_each_dev(pe, tmp) { | 514 | eeh_pe_for_each_dev(pe, edev, tmp) { |
515 | pdev = eeh_dev_to_pci_dev(tmp); | 515 | pdev = eeh_dev_to_pci_dev(edev); |
516 | if (pdev) | 516 | if (pdev) |
517 | pdev->error_state = pci_channel_io_frozen; | 517 | pdev->error_state = pci_channel_io_frozen; |
518 | } | 518 | } |