Currently we register the pass-through serio port when we probe the F03 RMI
function, and then, in sensor configure phase, we unmask interrupts.
Unfortunately this is too late, as other drivers are free probe devices
attached to the serio port as soon as it is probed. Because interrupts are
masked, the IO times out, which may result in not being able to detect
trackpoints on the pass-through port.
To fix the issue we implement open() and close() methods for the
pass-through serio port and unmask interrupts from there. We also move
creation of the pass-through port form probe to configure stage, as RMI
driver does not enable transport interrupt until all functions are probed
(we should change this, but this is a separate topic).
We also try to clear the pending data before unmasking interrupts, because
some devices like to spam the system with multiple 0xaa 0x00 announcements,
which may interfere with us trying to query ID of the device.
Fixes: c5e8848fc98e ("Input: synaptics-rmi4 - add support for F03")
Cc: stable(a)vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov(a)gmail.com>
---
drivers/input/rmi4/rmi_f03.c | 64 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 54 insertions(+), 10 deletions(-)
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index ad71a5e768dc4..7ccbb370a9a81 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -32,6 +32,7 @@ struct f03_data {
struct rmi_function *fn;
struct serio *serio;
+ bool serio_registered;
unsigned int overwrite_buttons;
@@ -138,6 +139,37 @@ static int rmi_f03_initialize(struct f03_data *f03)
return 0;
}
+static int rmi_f03_pt_open(struct serio *serio)
+{
+ struct f03_data *f03 = serio->port_data;
+ struct rmi_function *fn = f03->fn;
+ const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+ const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
+ u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
+ int error;
+
+ /*
+ * Consume any pending data. Some devices like to spam with
+ * 0xaa 0x00 announcements which may confuse us as we try to
+ * probe the device.
+ */
+ error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
+ if (!error)
+ rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+ "%s: Consumed %*ph (%d) from PS2 guest\n",
+ __func__, ob_len, obs, ob_len);
+
+ return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+}
+
+static void rmi_f03_pt_close(struct serio *serio)
+{
+ struct f03_data *f03 = serio->port_data;
+ struct rmi_function *fn = f03->fn;
+
+ fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
+}
+
static int rmi_f03_register_pt(struct f03_data *f03)
{
struct serio *serio;
@@ -148,6 +180,8 @@ static int rmi_f03_register_pt(struct f03_data *f03)
serio->id.type = SERIO_PS_PSTHRU;
serio->write = rmi_f03_pt_write;
+ serio->open = rmi_f03_pt_open;
+ serio->close = rmi_f03_pt_close;
serio->port_data = f03;
strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
@@ -184,17 +218,27 @@ static int rmi_f03_probe(struct rmi_function *fn)
f03->device_count);
dev_set_drvdata(dev, f03);
-
- error = rmi_f03_register_pt(f03);
- if (error)
- return error;
-
return 0;
}
static int rmi_f03_config(struct rmi_function *fn)
{
- fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+ int error;
+
+ if (!f03->serio_registered) {
+ error = rmi_f03_register_pt(f03);
+ if (error)
+ return error;
+
+ f03->serio_registered = true;
+ } else {
+ /*
+ * We must be re-configuring the sensor, just enable
+ * interrupts for this function.
+ */
+ fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+ }
return 0;
}
@@ -204,7 +248,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
- u16 data_addr = fn->fd.data_base_addr;
+ const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
u8 ob_status;
@@ -226,8 +270,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
drvdata->attn_data.size -= ob_len;
} else {
/* Grab all of the data registers, and check them for data */
- error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
- &obs, ob_len);
+ error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
if (error) {
dev_err(&fn->dev,
"%s: Failed to read F03 output buffers: %d\n",
@@ -266,7 +309,8 @@ static void rmi_f03_remove(struct rmi_function *fn)
{
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
- serio_unregister_port(f03->serio);
+ if (f03->serio_registered)
+ serio_unregister_port(f03->serio);
}
struct rmi_function_handler rmi_f03_handler = {
--
2.16.0.rc1.238.g530d649a79-goog
Tetsuo reported random crashes under memory pressure on 32-bit x86
system and tracked down to change that introduced
page_vma_mapped_walk().
The root cause of the issue is the faulty pointer math in check_pte().
As ->pte may point to an arbitrary page we have to check that they are
belong to the section before doing math. Otherwise it may lead to weird
results.
It wasn't noticed until now as mem_map[] is virtually contiguous on
flatmem or vmemmap sparsemem. Pointer arithmetic just works against all
'struct page' pointers. But with classic sparsemem, it doesn't because
each section memap is allocated separately and so consecutive pfns
crossing two sections might have struct pages at completely unrelated
addresses.
Let's restructure code a bit and replace pointer arithmetic with
operations on pfns.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov(a)linux.intel.com>
Reported-by: Tetsuo Handa <penguin-kernel(a)i-love.sakura.ne.jp>
Fixes: ace71a19cec5 ("mm: introduce page_vma_mapped_walk()")
Cc: stable(a)vger.kernel.org
---
v2:
- Do not use uninitialized 'pfn' for !MIGRATION case (Michal)
---
include/linux/swapops.h | 21 +++++++++++++++++
mm/page_vma_mapped.c | 63 +++++++++++++++++++++++++++++--------------------
2 files changed, 59 insertions(+), 25 deletions(-)
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 9c5a2628d6ce..1d3877c39a00 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -124,6 +124,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry)
return unlikely(swp_type(entry) == SWP_DEVICE_WRITE);
}
+static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry)
+{
+ return swp_offset(entry);
+}
+
static inline struct page *device_private_entry_to_page(swp_entry_t entry)
{
return pfn_to_page(swp_offset(entry));
@@ -154,6 +159,11 @@ static inline bool is_write_device_private_entry(swp_entry_t entry)
return false;
}
+static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry)
+{
+ return 0;
+}
+
static inline struct page *device_private_entry_to_page(swp_entry_t entry)
{
return NULL;
@@ -189,6 +199,11 @@ static inline int is_write_migration_entry(swp_entry_t entry)
return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE);
}
+static inline unsigned long migration_entry_to_pfn(swp_entry_t entry)
+{
+ return swp_offset(entry);
+}
+
static inline struct page *migration_entry_to_page(swp_entry_t entry)
{
struct page *p = pfn_to_page(swp_offset(entry));
@@ -218,6 +233,12 @@ static inline int is_migration_entry(swp_entry_t swp)
{
return 0;
}
+
+static inline unsigned long migration_entry_to_pfn(swp_entry_t entry)
+{
+ return 0;
+}
+
static inline struct page *migration_entry_to_page(swp_entry_t entry)
{
return NULL;
diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c
index d22b84310f6d..956015614395 100644
--- a/mm/page_vma_mapped.c
+++ b/mm/page_vma_mapped.c
@@ -30,10 +30,29 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw)
return true;
}
+/**
+ * check_pte - check if @pvmw->page is mapped at the @pvmw->pte
+ *
+ * page_vma_mapped_walk() found a place where @pvmw->page is *potentially*
+ * mapped. check_pte() has to validate this.
+ *
+ * @pvmw->pte may point to empty PTE, swap PTE or PTE pointing to arbitrary
+ * page.
+ *
+ * If PVMW_MIGRATION flag is set, returns true if @pvmw->pte contains migration
+ * entry that points to @pvmw->page or any subpage in case of THP.
+ *
+ * If PVMW_MIGRATION flag is not set, returns true if @pvmw->pte points to
+ * @pvmw->page or any subpage in case of THP.
+ *
+ * Otherwise, return false.
+ *
+ */
static bool check_pte(struct page_vma_mapped_walk *pvmw)
{
+ unsigned long pfn;
+
if (pvmw->flags & PVMW_MIGRATION) {
-#ifdef CONFIG_MIGRATION
swp_entry_t entry;
if (!is_swap_pte(*pvmw->pte))
return false;
@@ -41,37 +60,31 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw)
if (!is_migration_entry(entry))
return false;
- if (migration_entry_to_page(entry) - pvmw->page >=
- hpage_nr_pages(pvmw->page)) {
- return false;
- }
- if (migration_entry_to_page(entry) < pvmw->page)
- return false;
-#else
- WARN_ON_ONCE(1);
-#endif
- } else {
- if (is_swap_pte(*pvmw->pte)) {
- swp_entry_t entry;
- entry = pte_to_swp_entry(*pvmw->pte);
- if (is_device_private_entry(entry) &&
- device_private_entry_to_page(entry) == pvmw->page)
- return true;
- }
+ pfn = migration_entry_to_pfn(entry);
+ } else if (is_swap_pte(*pvmw->pte)) {
+ swp_entry_t entry;
- if (!pte_present(*pvmw->pte))
+ /* Handle un-addressable ZONE_DEVICE memory */
+ entry = pte_to_swp_entry(*pvmw->pte);
+ if (!is_device_private_entry(entry))
return false;
- /* THP can be referenced by any subpage */
- if (pte_page(*pvmw->pte) - pvmw->page >=
- hpage_nr_pages(pvmw->page)) {
- return false;
- }
- if (pte_page(*pvmw->pte) < pvmw->page)
+ pfn = device_private_entry_to_pfn(entry);
+ } else {
+ if (!pte_present(*pvmw->pte))
return false;
+
+ pfn = pte_pfn(*pvmw->pte);
}
+ if (pfn < page_to_pfn(pvmw->page))
+ return false;
+
+ /* THP can be referenced by any subpage */
+ if (pfn - page_to_pfn(pvmw->page) >= hpage_nr_pages(pvmw->page))
+ return false;
+
return true;
}
--
2.15.1
From: "Steven Rostedt (VMware)" <rostedt(a)goodmis.org>
Since enums do not get converted by the TRACE_EVENT macro into their values,
the event format displaces the enum name and not the value. This breaks
tools like perf and trace-cmd that need to interpret the raw binary data. To
solve this, an enum map was created to convert these enums into their actual
numbers on boot up. This is done by TRACE_EVENTS() adding a
TRACE_DEFINE_ENUM() macro.
Some enums were not being converted. This was caused by an optization that
had a bug in it.
All calls get checked against this enum map to see if it should be converted
or not, and it compares the call's system to the system that the enum map
was created under. If they match, then they call is processed.
To cut down on the number of iterations needed to find the maps with a
matching system, since calls and maps are grouped by system, when a match is
made, the index into the map array is saved, so that the next call, if it
belongs to the same system as the previous call, could start right at that
array index and not have to scan all the previous arrays.
The problem was, the saved index was used as the variable to know if this is
a call in a new system or not. If the index was zero, it was assumed that
the call is in a new system and would keep incrementing the saved index
until it found a matching system. The issue arises when the first matching
system was at index zero. The next map, if it belonged to the same system,
would then think it was the first match and increment the index to one. If
the next call belong to the same system, it would begin its search of the
maps off by one, and miss the first enum that should be converted. This left
a single enum not converted properly.
Also add a comment to describe exactly what that index was for. It took me a
bit too long to figure out what I was thinking when debugging this issue.
Link: http://lkml.kernel.org/r/717BE572-2070-4C1E-9902-9F2E0FEDA4F8@oracle.com
Cc: stable(a)vger.kernel.org
Fixes: 0c564a538aa93 ("tracing: Add TRACE_DEFINE_ENUM() macro to map enums to their values")
Reported-by: Chuck Lever <chuck.lever(a)oracle.com>
Teste-by: Chuck Lever <chuck.lever(a)oracle.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt(a)goodmis.org>
---
kernel/trace/trace_events.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index ec0f9aa4e151..1b87157edbff 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2213,6 +2213,7 @@ void trace_event_eval_update(struct trace_eval_map **map, int len)
{
struct trace_event_call *call, *p;
const char *last_system = NULL;
+ bool first = false;
int last_i;
int i;
@@ -2220,15 +2221,28 @@ void trace_event_eval_update(struct trace_eval_map **map, int len)
list_for_each_entry_safe(call, p, &ftrace_events, list) {
/* events are usually grouped together with systems */
if (!last_system || call->class->system != last_system) {
+ first = true;
last_i = 0;
last_system = call->class->system;
}
+ /*
+ * Since calls are grouped by systems, the likelyhood that the
+ * next call in the iteration belongs to the same system as the
+ * previous call is high. As an optimization, we skip seaching
+ * for a map[] that matches the call's system if the last call
+ * was from the same system. That's what last_i is for. If the
+ * call has the same system as the previous call, then last_i
+ * will be the index of the first map[] that has a matching
+ * system.
+ */
for (i = last_i; i < len; i++) {
if (call->class->system == map[i]->system) {
/* Save the first system if need be */
- if (!last_i)
+ if (first) {
last_i = i;
+ first = false;
+ }
update_event_printk(call, map[i]);
}
}
--
2.13.2
This is a note to let you know that I've just added the patch titled
x86/mm: Clean up register saving in the __enc_copy() assembly code
to the 4.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=sum…
The filename of the patch is:
x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch
and it can be found in the queue-4.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <stable(a)vger.kernel.org> know about it.
>From 1303880179e67c59e801429b7e5d0f6b21137d99 Mon Sep 17 00:00:00 2001
From: Tom Lendacky <thomas.lendacky(a)amd.com>
Date: Wed, 10 Jan 2018 13:25:56 -0600
Subject: x86/mm: Clean up register saving in the __enc_copy() assembly code
From: Tom Lendacky <thomas.lendacky(a)amd.com>
commit 1303880179e67c59e801429b7e5d0f6b21137d99 upstream.
Clean up the use of PUSH and POP and when registers are saved in the
__enc_copy() assembly function in order to improve the readability of the code.
Move parameter register saving into general purpose registers earlier
in the code and move all the pushes to the beginning of the function
with corresponding pops at the end.
We do this to prepare fixes.
Tested-by: Gabriel Craciunescu <nix.or.die(a)gmail.com>
Signed-off-by: Tom Lendacky <thomas.lendacky(a)amd.com>
Reviewed-by: Borislav Petkov <bp(a)suse.de>
Cc: Borislav Petkov <bp(a)alien8.de>
Cc: Brijesh Singh <brijesh.singh(a)amd.com>
Cc: Linus Torvalds <torvalds(a)linux-foundation.org>
Cc: Peter Zijlstra <peterz(a)infradead.org>
Cc: Thomas Gleixner <tglx(a)linutronix.de>
Link: http://lkml.kernel.org/r/20180110192556.6026.74187.stgit@tlendack-t1.amdoff…
Signed-off-by: Ingo Molnar <mingo(a)kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
arch/x86/mm/mem_encrypt_boot.S | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
--- a/arch/x86/mm/mem_encrypt_boot.S
+++ b/arch/x86/mm/mem_encrypt_boot.S
@@ -103,20 +103,19 @@ ENTRY(__enc_copy)
orq $X86_CR4_PGE, %rdx
mov %rdx, %cr4
+ push %r15
+
+ movq %rcx, %r9 /* Save kernel length */
+ movq %rdi, %r10 /* Save encrypted kernel address */
+ movq %rsi, %r11 /* Save decrypted kernel address */
+
/* Set the PAT register PA5 entry to write-protect */
- push %rcx
movl $MSR_IA32_CR_PAT, %ecx
rdmsr
- push %rdx /* Save original PAT value */
+ mov %rdx, %r15 /* Save original PAT value */
andl $0xffff00ff, %edx /* Clear PA5 */
orl $0x00000500, %edx /* Set PA5 to WP */
wrmsr
- pop %rdx /* RDX contains original PAT value */
- pop %rcx
-
- movq %rcx, %r9 /* Save kernel length */
- movq %rdi, %r10 /* Save encrypted kernel address */
- movq %rsi, %r11 /* Save decrypted kernel address */
wbinvd /* Invalidate any cache entries */
@@ -138,12 +137,13 @@ ENTRY(__enc_copy)
jnz 1b /* Kernel length not zero? */
/* Restore PAT register */
- push %rdx /* Save original PAT value */
movl $MSR_IA32_CR_PAT, %ecx
rdmsr
- pop %rdx /* Restore original PAT value */
+ mov %r15, %rdx /* Restore original PAT value */
wrmsr
+ pop %r15
+
ret
.L__enc_copy_end:
ENDPROC(__enc_copy)
Patches currently in stable-queue which might be from thomas.lendacky(a)amd.com are
queue-4.14/x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch
queue-4.14/x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch
queue-4.14/x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch
queue-4.14/x86-retpoline-fill-rsb-on-context-switch-for-affected-cpus.patch
queue-4.14/x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch
queue-4.14/x86-retpoline-add-lfence-to-the-retpoline-rsb-filling-rsb-macros.patch
This is a note to let you know that I've just added the patch titled
x86/apic/vector: Fix off by one in error path
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=sum…
The filename of the patch is:
x86-apic-vector-fix-off-by-one-in-error-path.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <stable(a)vger.kernel.org> know about it.
>From 45d55e7bac4028af93f5fa324e69958a0b868e96 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx(a)linutronix.de>
Date: Tue, 16 Jan 2018 12:20:18 +0100
Subject: x86/apic/vector: Fix off by one in error path
From: Thomas Gleixner <tglx(a)linutronix.de>
commit 45d55e7bac4028af93f5fa324e69958a0b868e96 upstream.
Keith reported the following warning:
WARNING: CPU: 28 PID: 1420 at kernel/irq/matrix.c:222 irq_matrix_remove_managed+0x10f/0x120
x86_vector_free_irqs+0xa1/0x180
x86_vector_alloc_irqs+0x1e4/0x3a0
msi_domain_alloc+0x62/0x130
The reason for this is that if the vector allocation fails the error
handling code tries to free the failed vector as well, which causes the
above imbalance warning to trigger.
Adjust the error path to handle this correctly.
Fixes: b5dc8e6c21e7 ("x86/irq: Use hierarchical irqdomain to manage CPU interrupt vectors")
Reported-by: Keith Busch <keith.busch(a)intel.com>
Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
Tested-by: Keith Busch <keith.busch(a)intel.com>
Cc: stable(a)vger.kernel.org
Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1801161217300.1823@nanos
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
arch/x86/kernel/apic/vector.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -361,14 +361,17 @@ static int x86_vector_alloc_irqs(struct
irq_data->chip_data = data;
irq_data->hwirq = virq + i;
err = assign_irq_vector_policy(virq + i, node, data, info);
- if (err)
+ if (err) {
+ irq_data->chip_data = NULL;
+ free_apic_chip_data(data);
goto error;
+ }
}
return 0;
error:
- x86_vector_free_irqs(domain, virq, i + 1);
+ x86_vector_free_irqs(domain, virq, i);
return err;
}
Patches currently in stable-queue which might be from tglx(a)linutronix.de are
queue-4.9/futex-prevent-overflow-by-strengthen-input-validation.patch
queue-4.9/timers-unconditionally-check-deferrable-base.patch
queue-4.9/x86-apic-vector-fix-off-by-one-in-error-path.patch
queue-4.9/objtool-improve-error-message-for-bad-file-argument.patch
queue-4.9/x86-mm-pkeys-fix-fill_sig_info_pkey.patch
queue-4.9/x86-tsc-fix-erroneous-tsc-rate-on-skylake-xeon.patch
queue-4.9/sched-deadline-zero-out-positive-runtime-after-throttling-constrained-tasks.patch
queue-4.9/module-add-retpoline-tag-to-vermagic.patch
queue-4.9/x86-retpoline-fill-rsb-on-context-switch-for-affected-cpus.patch
queue-4.9/x86-retpoline-add-lfence-to-the-retpoline-rsb-filling-rsb-macros.patch
queue-4.9/x86-cpufeature-move-processor-tracing-out-of-scattered-features.patch
This is a note to let you know that I've just added the patch titled
x86/apic/vector: Fix off by one in error path
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=sum…
The filename of the patch is:
x86-apic-vector-fix-off-by-one-in-error-path.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <stable(a)vger.kernel.org> know about it.
>From 45d55e7bac4028af93f5fa324e69958a0b868e96 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx(a)linutronix.de>
Date: Tue, 16 Jan 2018 12:20:18 +0100
Subject: x86/apic/vector: Fix off by one in error path
From: Thomas Gleixner <tglx(a)linutronix.de>
commit 45d55e7bac4028af93f5fa324e69958a0b868e96 upstream.
Keith reported the following warning:
WARNING: CPU: 28 PID: 1420 at kernel/irq/matrix.c:222 irq_matrix_remove_managed+0x10f/0x120
x86_vector_free_irqs+0xa1/0x180
x86_vector_alloc_irqs+0x1e4/0x3a0
msi_domain_alloc+0x62/0x130
The reason for this is that if the vector allocation fails the error
handling code tries to free the failed vector as well, which causes the
above imbalance warning to trigger.
Adjust the error path to handle this correctly.
Fixes: b5dc8e6c21e7 ("x86/irq: Use hierarchical irqdomain to manage CPU interrupt vectors")
Reported-by: Keith Busch <keith.busch(a)intel.com>
Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
Tested-by: Keith Busch <keith.busch(a)intel.com>
Cc: stable(a)vger.kernel.org
Link: https://lkml.kernel.org/r/alpine.DEB.2.20.1801161217300.1823@nanos
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
---
arch/x86/kernel/apic/vector.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -359,14 +359,17 @@ static int x86_vector_alloc_irqs(struct
irq_data->chip_data = data;
irq_data->hwirq = virq + i;
err = assign_irq_vector_policy(virq + i, node, data, info);
- if (err)
+ if (err) {
+ irq_data->chip_data = NULL;
+ free_apic_chip_data(data);
goto error;
+ }
}
return 0;
error:
- x86_vector_free_irqs(domain, virq, i + 1);
+ x86_vector_free_irqs(domain, virq, i);
return err;
}
Patches currently in stable-queue which might be from tglx(a)linutronix.de are
queue-4.4/futex-prevent-overflow-by-strengthen-input-validation.patch
queue-4.4/x86-spectre-add-boot-time-option-to-select-spectre-v2-mitigation.patch
queue-4.4/x86-retpoline-irq32-convert-assembler-indirect-jumps.patch
queue-4.4/x86-retpoline-hyperv-convert-assembler-indirect-jumps.patch
queue-4.4/x86-apic-vector-fix-off-by-one-in-error-path.patch
queue-4.4/x86-retpoline-entry-convert-entry-assembler-indirect-jumps.patch
queue-4.4/x86-asm-use-register-variable-to-get-stack-pointer-value.patch
queue-4.4/x86-cpu-amd-make-lfence-a-serializing-instruction.patch
queue-4.4/x86-retpoline-ftrace-convert-ftrace-assembler-indirect-jumps.patch
queue-4.4/sched-deadline-zero-out-positive-runtime-after-throttling-constrained-tasks.patch
queue-4.4/x86-retpoline-crypto-convert-crypto-assembler-indirect-jumps.patch
queue-4.4/module-add-retpoline-tag-to-vermagic.patch
queue-4.4/x86-retpoline-xen-convert-xen-hypercall-indirect-jumps.patch
queue-4.4/x86-retpoline-checksum32-convert-assembler-indirect-jumps.patch
queue-4.4/x86-mm-32-move-setup_clear_cpu_cap-x86_feature_pcid-earlier.patch
queue-4.4/x86-retpoline-fill-return-stack-buffer-on-vmexit.patch
queue-4.4/x86-retpoline-add-lfence-to-the-retpoline-rsb-filling-rsb-macros.patch
queue-4.4/x86-retpoline-remove-compile-time-warning.patch
queue-4.4/x86-cpu-amd-use-lfence_rdtsc-in-preference-to-mfence_rdtsc.patch
queue-4.4/x86-retpoline-add-initial-retpoline-support.patch
queue-4.4/x86-asm-make-asm-alternative.h-safe-from-assembly.patch