diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-05 00:45:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-05 00:45:21 -0500 |
commit | 53c6de50262a8edd6932bb59a32db7b9d92f8d67 (patch) | |
tree | 3200068f880aa9647e9184f15619345727f447a5 | |
parent | 8ecffd7914484b728799dd31968f1339fae91593 (diff) | |
parent | 2885432aaf15c1b7e65c787bfe7c5fec428296f0 (diff) |
Merge branch 'x86/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 and EFI fixes from Peter Anvin:
"Half of these are EFI-related:
The by far biggest change is the change to hold off the deletion of a
sysfs entry while a backend scan is in progress. This is to avoid
calling kmemdup() while under a spinlock.
The other major change is for each entry in the EFI pstore backend to
get a unique identifier, as required by the pstore filesystem proper.
The other changes are:
A fix to the recent consolidation and optimization of using "asm goto"
with read-modify-write operation, which broke the bitops; specifically
in such a way that we could end up generating invalid code.
A build hack to make sure we compile with -mno-sse. icc, and most
likely future versions of gcc, can generate SSE instructions unless we
tell it not to.
A comment-only patch to a change the was due in part to an unpublished
erratum; now when the erratum is published we want to add a comment
explaining why"
* 'x86/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/apic, doc: Justification for disabling IO APIC before Local APIC
x86, bitops: Correct the assembly constraints to testing bitops
x86-64, build: Always pass in -mno-sse
efi-pstore: Make efi-pstore return a unique id
x86/efi: Fix earlyprintk off-by-one bug
efivars, efi-pstore: Hold off deletion of sysfs entry until the scan is completed
-rw-r--r-- | arch/x86/Makefile | 8 | ||||
-rw-r--r-- | arch/x86/include/asm/atomic.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/atomic64_64.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/bitops.h | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/local.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/rmwcc.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/reboot.c | 11 | ||||
-rw-r--r-- | arch/x86/platform/efi/early_printk.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 163 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 12 | ||||
-rw-r--r-- | include/linux/efi.h | 4 |
12 files changed, 201 insertions, 37 deletions
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 41250fb33985..eda00f9be0cf 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
@@ -31,6 +31,9 @@ ifeq ($(CONFIG_X86_32),y) | |||
31 | 31 | ||
32 | KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return | 32 | KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return |
33 | 33 | ||
34 | # Don't autogenerate SSE instructions | ||
35 | KBUILD_CFLAGS += -mno-sse | ||
36 | |||
34 | # Never want PIC in a 32-bit kernel, prevent breakage with GCC built | 37 | # Never want PIC in a 32-bit kernel, prevent breakage with GCC built |
35 | # with nonstandard options | 38 | # with nonstandard options |
36 | KBUILD_CFLAGS += -fno-pic | 39 | KBUILD_CFLAGS += -fno-pic |
@@ -57,8 +60,11 @@ else | |||
57 | KBUILD_AFLAGS += -m64 | 60 | KBUILD_AFLAGS += -m64 |
58 | KBUILD_CFLAGS += -m64 | 61 | KBUILD_CFLAGS += -m64 |
59 | 62 | ||
63 | # Don't autogenerate SSE instructions | ||
64 | KBUILD_CFLAGS += -mno-sse | ||
65 | |||
60 | # Use -mpreferred-stack-boundary=3 if supported. | 66 | # Use -mpreferred-stack-boundary=3 if supported. |
61 | KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3) | 67 | KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3) |
62 | 68 | ||
63 | # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu) | 69 | # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu) |
64 | cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) | 70 | cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) |
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index da31c8b8a92d..b17f4f48ecd7 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h | |||
@@ -77,7 +77,7 @@ static inline void atomic_sub(int i, atomic_t *v) | |||
77 | */ | 77 | */ |
78 | static inline int atomic_sub_and_test(int i, atomic_t *v) | 78 | static inline int atomic_sub_and_test(int i, atomic_t *v) |
79 | { | 79 | { |
80 | GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, i, "%0", "e"); | 80 | GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); |
81 | } | 81 | } |
82 | 82 | ||
83 | /** | 83 | /** |
@@ -141,7 +141,7 @@ static inline int atomic_inc_and_test(atomic_t *v) | |||
141 | */ | 141 | */ |
142 | static inline int atomic_add_negative(int i, atomic_t *v) | 142 | static inline int atomic_add_negative(int i, atomic_t *v) |
143 | { | 143 | { |
144 | GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, i, "%0", "s"); | 144 | GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); |
145 | } | 145 | } |
146 | 146 | ||
147 | /** | 147 | /** |
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 3f065c985aee..46e9052bbd28 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h | |||
@@ -72,7 +72,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) | |||
72 | */ | 72 | */ |
73 | static inline int atomic64_sub_and_test(long i, atomic64_t *v) | 73 | static inline int atomic64_sub_and_test(long i, atomic64_t *v) |
74 | { | 74 | { |
75 | GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, i, "%0", "e"); | 75 | GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", "e"); |
76 | } | 76 | } |
77 | 77 | ||
78 | /** | 78 | /** |
@@ -138,7 +138,7 @@ static inline int atomic64_inc_and_test(atomic64_t *v) | |||
138 | */ | 138 | */ |
139 | static inline int atomic64_add_negative(long i, atomic64_t *v) | 139 | static inline int atomic64_add_negative(long i, atomic64_t *v) |
140 | { | 140 | { |
141 | GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, i, "%0", "s"); | 141 | GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", "s"); |
142 | } | 142 | } |
143 | 143 | ||
144 | /** | 144 | /** |
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 6d76d0935989..9fc1af74dc83 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h | |||
@@ -205,7 +205,7 @@ static inline void change_bit(long nr, volatile unsigned long *addr) | |||
205 | */ | 205 | */ |
206 | static inline int test_and_set_bit(long nr, volatile unsigned long *addr) | 206 | static inline int test_and_set_bit(long nr, volatile unsigned long *addr) |
207 | { | 207 | { |
208 | GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, nr, "%0", "c"); | 208 | GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); |
209 | } | 209 | } |
210 | 210 | ||
211 | /** | 211 | /** |
@@ -251,7 +251,7 @@ static inline int __test_and_set_bit(long nr, volatile unsigned long *addr) | |||
251 | */ | 251 | */ |
252 | static inline int test_and_clear_bit(long nr, volatile unsigned long *addr) | 252 | static inline int test_and_clear_bit(long nr, volatile unsigned long *addr) |
253 | { | 253 | { |
254 | GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, nr, "%0", "c"); | 254 | GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); |
255 | } | 255 | } |
256 | 256 | ||
257 | /** | 257 | /** |
@@ -304,7 +304,7 @@ static inline int __test_and_change_bit(long nr, volatile unsigned long *addr) | |||
304 | */ | 304 | */ |
305 | static inline int test_and_change_bit(long nr, volatile unsigned long *addr) | 305 | static inline int test_and_change_bit(long nr, volatile unsigned long *addr) |
306 | { | 306 | { |
307 | GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, nr, "%0", "c"); | 307 | GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); |
308 | } | 308 | } |
309 | 309 | ||
310 | static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) | 310 | static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) |
diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 5b23e605e707..4ad6560847b1 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h | |||
@@ -52,7 +52,7 @@ static inline void local_sub(long i, local_t *l) | |||
52 | */ | 52 | */ |
53 | static inline int local_sub_and_test(long i, local_t *l) | 53 | static inline int local_sub_and_test(long i, local_t *l) |
54 | { | 54 | { |
55 | GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, i, "%0", "e"); | 55 | GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", "e"); |
56 | } | 56 | } |
57 | 57 | ||
58 | /** | 58 | /** |
@@ -92,7 +92,7 @@ static inline int local_inc_and_test(local_t *l) | |||
92 | */ | 92 | */ |
93 | static inline int local_add_negative(long i, local_t *l) | 93 | static inline int local_add_negative(long i, local_t *l) |
94 | { | 94 | { |
95 | GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, i, "%0", "s"); | 95 | GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", "s"); |
96 | } | 96 | } |
97 | 97 | ||
98 | /** | 98 | /** |
diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 1ff990f1de8e..8f7866a5b9a4 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h | |||
@@ -16,8 +16,8 @@ cc_label: \ | |||
16 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ | 16 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ |
17 | __GEN_RMWcc(op " " arg0, var, cc) | 17 | __GEN_RMWcc(op " " arg0, var, cc) |
18 | 18 | ||
19 | #define GEN_BINARY_RMWcc(op, var, val, arg0, cc) \ | 19 | #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ |
20 | __GEN_RMWcc(op " %1, " arg0, var, cc, "er" (val)) | 20 | __GEN_RMWcc(op " %1, " arg0, var, cc, vcon (val)) |
21 | 21 | ||
22 | #else /* !CC_HAVE_ASM_GOTO */ | 22 | #else /* !CC_HAVE_ASM_GOTO */ |
23 | 23 | ||
@@ -33,8 +33,8 @@ do { \ | |||
33 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ | 33 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ |
34 | __GEN_RMWcc(op " " arg0, var, cc) | 34 | __GEN_RMWcc(op " " arg0, var, cc) |
35 | 35 | ||
36 | #define GEN_BINARY_RMWcc(op, var, val, arg0, cc) \ | 36 | #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ |
37 | __GEN_RMWcc(op " %2, " arg0, var, cc, "er" (val)) | 37 | __GEN_RMWcc(op " %2, " arg0, var, cc, vcon (val)) |
38 | 38 | ||
39 | #endif /* CC_HAVE_ASM_GOTO */ | 39 | #endif /* CC_HAVE_ASM_GOTO */ |
40 | 40 | ||
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index da3c599584a3..c752cb43e52f 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -558,6 +558,17 @@ void native_machine_shutdown(void) | |||
558 | { | 558 | { |
559 | /* Stop the cpus and apics */ | 559 | /* Stop the cpus and apics */ |
560 | #ifdef CONFIG_X86_IO_APIC | 560 | #ifdef CONFIG_X86_IO_APIC |
561 | /* | ||
562 | * Disabling IO APIC before local APIC is a workaround for | ||
563 | * erratum AVR31 in "Intel Atom Processor C2000 Product Family | ||
564 | * Specification Update". In this situation, interrupts that target | ||
565 | * a Logical Processor whose Local APIC is either in the process of | ||
566 | * being hardware disabled or software disabled are neither delivered | ||
567 | * nor discarded. When this erratum occurs, the processor may hang. | ||
568 | * | ||
569 | * Even without the erratum, it still makes sense to quiet IO APIC | ||
570 | * before disabling Local APIC. | ||
571 | */ | ||
561 | disable_IO_APIC(); | 572 | disable_IO_APIC(); |
562 | #endif | 573 | #endif |
563 | 574 | ||
diff --git a/arch/x86/platform/efi/early_printk.c b/arch/x86/platform/efi/early_printk.c index 6599a0027b76..81b506d5befd 100644 --- a/arch/x86/platform/efi/early_printk.c +++ b/arch/x86/platform/efi/early_printk.c | |||
@@ -142,7 +142,7 @@ early_efi_write(struct console *con, const char *str, unsigned int num) | |||
142 | efi_y += font->height; | 142 | efi_y += font->height; |
143 | } | 143 | } |
144 | 144 | ||
145 | if (efi_y + font->height >= si->lfb_height) { | 145 | if (efi_y + font->height > si->lfb_height) { |
146 | u32 i; | 146 | u32 i; |
147 | 147 | ||
148 | efi_y -= font->height; | 148 | efi_y -= font->height; |
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 5002d50e3781..743fd426f21b 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c | |||
@@ -18,14 +18,12 @@ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); | |||
18 | 18 | ||
19 | static int efi_pstore_open(struct pstore_info *psi) | 19 | static int efi_pstore_open(struct pstore_info *psi) |
20 | { | 20 | { |
21 | efivar_entry_iter_begin(); | ||
22 | psi->data = NULL; | 21 | psi->data = NULL; |
23 | return 0; | 22 | return 0; |
24 | } | 23 | } |
25 | 24 | ||
26 | static int efi_pstore_close(struct pstore_info *psi) | 25 | static int efi_pstore_close(struct pstore_info *psi) |
27 | { | 26 | { |
28 | efivar_entry_iter_end(); | ||
29 | psi->data = NULL; | 27 | psi->data = NULL; |
30 | return 0; | 28 | return 0; |
31 | } | 29 | } |
@@ -39,6 +37,12 @@ struct pstore_read_data { | |||
39 | char **buf; | 37 | char **buf; |
40 | }; | 38 | }; |
41 | 39 | ||
40 | static inline u64 generic_id(unsigned long timestamp, | ||
41 | unsigned int part, int count) | ||
42 | { | ||
43 | return (timestamp * 100 + part) * 1000 + count; | ||
44 | } | ||
45 | |||
42 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | 46 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) |
43 | { | 47 | { |
44 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 48 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
@@ -57,7 +61,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
57 | 61 | ||
58 | if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", | 62 | if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", |
59 | cb_data->type, &part, &cnt, &time, &data_type) == 5) { | 63 | cb_data->type, &part, &cnt, &time, &data_type) == 5) { |
60 | *cb_data->id = part; | 64 | *cb_data->id = generic_id(time, part, cnt); |
61 | *cb_data->count = cnt; | 65 | *cb_data->count = cnt; |
62 | cb_data->timespec->tv_sec = time; | 66 | cb_data->timespec->tv_sec = time; |
63 | cb_data->timespec->tv_nsec = 0; | 67 | cb_data->timespec->tv_nsec = 0; |
@@ -67,7 +71,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
67 | *cb_data->compressed = false; | 71 | *cb_data->compressed = false; |
68 | } else if (sscanf(name, "dump-type%u-%u-%d-%lu", | 72 | } else if (sscanf(name, "dump-type%u-%u-%d-%lu", |
69 | cb_data->type, &part, &cnt, &time) == 4) { | 73 | cb_data->type, &part, &cnt, &time) == 4) { |
70 | *cb_data->id = part; | 74 | *cb_data->id = generic_id(time, part, cnt); |
71 | *cb_data->count = cnt; | 75 | *cb_data->count = cnt; |
72 | cb_data->timespec->tv_sec = time; | 76 | cb_data->timespec->tv_sec = time; |
73 | cb_data->timespec->tv_nsec = 0; | 77 | cb_data->timespec->tv_nsec = 0; |
@@ -79,7 +83,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
79 | * which doesn't support holding | 83 | * which doesn't support holding |
80 | * multiple logs, remains. | 84 | * multiple logs, remains. |
81 | */ | 85 | */ |
82 | *cb_data->id = part; | 86 | *cb_data->id = generic_id(time, part, 0); |
83 | *cb_data->count = 0; | 87 | *cb_data->count = 0; |
84 | cb_data->timespec->tv_sec = time; | 88 | cb_data->timespec->tv_sec = time; |
85 | cb_data->timespec->tv_nsec = 0; | 89 | cb_data->timespec->tv_nsec = 0; |
@@ -91,19 +95,125 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | |||
91 | __efivar_entry_get(entry, &entry->var.Attributes, | 95 | __efivar_entry_get(entry, &entry->var.Attributes, |
92 | &entry->var.DataSize, entry->var.Data); | 96 | &entry->var.DataSize, entry->var.Data); |
93 | size = entry->var.DataSize; | 97 | size = entry->var.DataSize; |
98 | memcpy(*cb_data->buf, entry->var.Data, | ||
99 | (size_t)min_t(unsigned long, EFIVARS_DATA_SIZE_MAX, size)); | ||
94 | 100 | ||
95 | *cb_data->buf = kmemdup(entry->var.Data, size, GFP_KERNEL); | ||
96 | if (*cb_data->buf == NULL) | ||
97 | return -ENOMEM; | ||
98 | return size; | 101 | return size; |
99 | } | 102 | } |
100 | 103 | ||
104 | /** | ||
105 | * efi_pstore_scan_sysfs_enter | ||
106 | * @entry: scanning entry | ||
107 | * @next: next entry | ||
108 | * @head: list head | ||
109 | */ | ||
110 | static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos, | ||
111 | struct efivar_entry *next, | ||
112 | struct list_head *head) | ||
113 | { | ||
114 | pos->scanning = true; | ||
115 | if (&next->list != head) | ||
116 | next->scanning = true; | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * __efi_pstore_scan_sysfs_exit | ||
121 | * @entry: deleting entry | ||
122 | * @turn_off_scanning: Check if a scanning flag should be turned off | ||
123 | */ | ||
124 | static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry, | ||
125 | bool turn_off_scanning) | ||
126 | { | ||
127 | if (entry->deleting) { | ||
128 | list_del(&entry->list); | ||
129 | efivar_entry_iter_end(); | ||
130 | efivar_unregister(entry); | ||
131 | efivar_entry_iter_begin(); | ||
132 | } else if (turn_off_scanning) | ||
133 | entry->scanning = false; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * efi_pstore_scan_sysfs_exit | ||
138 | * @pos: scanning entry | ||
139 | * @next: next entry | ||
140 | * @head: list head | ||
141 | * @stop: a flag checking if scanning will stop | ||
142 | */ | ||
143 | static void efi_pstore_scan_sysfs_exit(struct efivar_entry *pos, | ||
144 | struct efivar_entry *next, | ||
145 | struct list_head *head, bool stop) | ||
146 | { | ||
147 | __efi_pstore_scan_sysfs_exit(pos, true); | ||
148 | if (stop) | ||
149 | __efi_pstore_scan_sysfs_exit(next, &next->list != head); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * efi_pstore_sysfs_entry_iter | ||
154 | * | ||
155 | * @data: function-specific data to pass to callback | ||
156 | * @pos: entry to begin iterating from | ||
157 | * | ||
158 | * You MUST call efivar_enter_iter_begin() before this function, and | ||
159 | * efivar_entry_iter_end() afterwards. | ||
160 | * | ||
161 | * It is possible to begin iteration from an arbitrary entry within | ||
162 | * the list by passing @pos. @pos is updated on return to point to | ||
163 | * the next entry of the last one passed to efi_pstore_read_func(). | ||
164 | * To begin iterating from the beginning of the list @pos must be %NULL. | ||
165 | */ | ||
166 | static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos) | ||
167 | { | ||
168 | struct efivar_entry *entry, *n; | ||
169 | struct list_head *head = &efivar_sysfs_list; | ||
170 | int size = 0; | ||
171 | |||
172 | if (!*pos) { | ||
173 | list_for_each_entry_safe(entry, n, head, list) { | ||
174 | efi_pstore_scan_sysfs_enter(entry, n, head); | ||
175 | |||
176 | size = efi_pstore_read_func(entry, data); | ||
177 | efi_pstore_scan_sysfs_exit(entry, n, head, size < 0); | ||
178 | if (size) | ||
179 | break; | ||
180 | } | ||
181 | *pos = n; | ||
182 | return size; | ||
183 | } | ||
184 | |||
185 | list_for_each_entry_safe_from((*pos), n, head, list) { | ||
186 | efi_pstore_scan_sysfs_enter((*pos), n, head); | ||
187 | |||
188 | size = efi_pstore_read_func((*pos), data); | ||
189 | efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0); | ||
190 | if (size) | ||
191 | break; | ||
192 | } | ||
193 | *pos = n; | ||
194 | return size; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * efi_pstore_read | ||
199 | * | ||
200 | * This function returns a size of NVRAM entry logged via efi_pstore_write(). | ||
201 | * The meaning and behavior of efi_pstore/pstore are as below. | ||
202 | * | ||
203 | * size > 0: Got data of an entry logged via efi_pstore_write() successfully, | ||
204 | * and pstore filesystem will continue reading subsequent entries. | ||
205 | * size == 0: Entry was not logged via efi_pstore_write(), | ||
206 | * and efi_pstore driver will continue reading subsequent entries. | ||
207 | * size < 0: Failed to get data of entry logging via efi_pstore_write(), | ||
208 | * and pstore will stop reading entry. | ||
209 | */ | ||
101 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | 210 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, |
102 | int *count, struct timespec *timespec, | 211 | int *count, struct timespec *timespec, |
103 | char **buf, bool *compressed, | 212 | char **buf, bool *compressed, |
104 | struct pstore_info *psi) | 213 | struct pstore_info *psi) |
105 | { | 214 | { |
106 | struct pstore_read_data data; | 215 | struct pstore_read_data data; |
216 | ssize_t size; | ||
107 | 217 | ||
108 | data.id = id; | 218 | data.id = id; |
109 | data.type = type; | 219 | data.type = type; |
@@ -112,8 +222,17 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |||
112 | data.compressed = compressed; | 222 | data.compressed = compressed; |
113 | data.buf = buf; | 223 | data.buf = buf; |
114 | 224 | ||
115 | return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, | 225 | *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); |
116 | (struct efivar_entry **)&psi->data); | 226 | if (!*data.buf) |
227 | return -ENOMEM; | ||
228 | |||
229 | efivar_entry_iter_begin(); | ||
230 | size = efi_pstore_sysfs_entry_iter(&data, | ||
231 | (struct efivar_entry **)&psi->data); | ||
232 | efivar_entry_iter_end(); | ||
233 | if (size <= 0) | ||
234 | kfree(*data.buf); | ||
235 | return size; | ||
117 | } | 236 | } |
118 | 237 | ||
119 | static int efi_pstore_write(enum pstore_type_id type, | 238 | static int efi_pstore_write(enum pstore_type_id type, |
@@ -184,9 +303,17 @@ static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) | |||
184 | return 0; | 303 | return 0; |
185 | } | 304 | } |
186 | 305 | ||
306 | if (entry->scanning) { | ||
307 | /* | ||
308 | * Skip deletion because this entry will be deleted | ||
309 | * after scanning is completed. | ||
310 | */ | ||
311 | entry->deleting = true; | ||
312 | } else | ||
313 | list_del(&entry->list); | ||
314 | |||
187 | /* found */ | 315 | /* found */ |
188 | __efivar_entry_delete(entry); | 316 | __efivar_entry_delete(entry); |
189 | list_del(&entry->list); | ||
190 | 317 | ||
191 | return 1; | 318 | return 1; |
192 | } | 319 | } |
@@ -199,14 +326,16 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
199 | char name[DUMP_NAME_LEN]; | 326 | char name[DUMP_NAME_LEN]; |
200 | efi_char16_t efi_name[DUMP_NAME_LEN]; | 327 | efi_char16_t efi_name[DUMP_NAME_LEN]; |
201 | int found, i; | 328 | int found, i; |
329 | unsigned int part; | ||
202 | 330 | ||
203 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | 331 | do_div(id, 1000); |
204 | time.tv_sec); | 332 | part = do_div(id, 100); |
333 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, time.tv_sec); | ||
205 | 334 | ||
206 | for (i = 0; i < DUMP_NAME_LEN; i++) | 335 | for (i = 0; i < DUMP_NAME_LEN; i++) |
207 | efi_name[i] = name[i]; | 336 | efi_name[i] = name[i]; |
208 | 337 | ||
209 | edata.id = id; | 338 | edata.id = part; |
210 | edata.type = type; | 339 | edata.type = type; |
211 | edata.count = count; | 340 | edata.count = count; |
212 | edata.time = time; | 341 | edata.time = time; |
@@ -214,10 +343,12 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
214 | 343 | ||
215 | efivar_entry_iter_begin(); | 344 | efivar_entry_iter_begin(); |
216 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); | 345 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); |
217 | efivar_entry_iter_end(); | ||
218 | 346 | ||
219 | if (found) | 347 | if (found && !entry->scanning) { |
348 | efivar_entry_iter_end(); | ||
220 | efivar_unregister(entry); | 349 | efivar_unregister(entry); |
350 | } else | ||
351 | efivar_entry_iter_end(); | ||
221 | 352 | ||
222 | return 0; | 353 | return 0; |
223 | } | 354 | } |
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 933eb027d527..3dc248239197 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c | |||
@@ -383,12 +383,16 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
383 | else if (__efivar_entry_delete(entry)) | 383 | else if (__efivar_entry_delete(entry)) |
384 | err = -EIO; | 384 | err = -EIO; |
385 | 385 | ||
386 | efivar_entry_iter_end(); | 386 | if (err) { |
387 | 387 | efivar_entry_iter_end(); | |
388 | if (err) | ||
389 | return err; | 388 | return err; |
389 | } | ||
390 | 390 | ||
391 | efivar_unregister(entry); | 391 | if (!entry->scanning) { |
392 | efivar_entry_iter_end(); | ||
393 | efivar_unregister(entry); | ||
394 | } else | ||
395 | efivar_entry_iter_end(); | ||
392 | 396 | ||
393 | /* It's dead Jim.... */ | 397 | /* It's dead Jim.... */ |
394 | return count; | 398 | return count; |
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 391c67b182d9..b22659cccca4 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
@@ -683,8 +683,16 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | |||
683 | if (!found) | 683 | if (!found) |
684 | return NULL; | 684 | return NULL; |
685 | 685 | ||
686 | if (remove) | 686 | if (remove) { |
687 | list_del(&entry->list); | 687 | if (entry->scanning) { |
688 | /* | ||
689 | * The entry will be deleted | ||
690 | * after scanning is completed. | ||
691 | */ | ||
692 | entry->deleting = true; | ||
693 | } else | ||
694 | list_del(&entry->list); | ||
695 | } | ||
688 | 696 | ||
689 | return entry; | 697 | return entry; |
690 | } | 698 | } |
diff --git a/include/linux/efi.h b/include/linux/efi.h index bc5687d0f315..11ce6784a196 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -801,6 +801,8 @@ struct efivar_entry { | |||
801 | struct efi_variable var; | 801 | struct efi_variable var; |
802 | struct list_head list; | 802 | struct list_head list; |
803 | struct kobject kobj; | 803 | struct kobject kobj; |
804 | bool scanning; | ||
805 | bool deleting; | ||
804 | }; | 806 | }; |
805 | 807 | ||
806 | 808 | ||
@@ -866,6 +868,8 @@ void efivar_run_worker(void); | |||
866 | #if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE) | 868 | #if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE) |
867 | int efivars_sysfs_init(void); | 869 | int efivars_sysfs_init(void); |
868 | 870 | ||
871 | #define EFIVARS_DATA_SIZE_MAX 1024 | ||
872 | |||
869 | #endif /* CONFIG_EFI_VARS */ | 873 | #endif /* CONFIG_EFI_VARS */ |
870 | 874 | ||
871 | #endif /* _LINUX_EFI_H */ | 875 | #endif /* _LINUX_EFI_H */ |