4.13.9-stable review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 2/11 x86/apic: Silence "FW_BUG TSC_DEADLINE disabled due to Errata" on hypervisors
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini <[email protected]>
commit cc6afe2240298049585e86b1ade85efc8a7f225d upstream.
Commit 594a30fb1242 ("x86/apic: Silence "FW_BUG TSC_DEADLINE disabled due to Errata" on CPUs without the feature", 2017-08-30) was also about silencing the warning on VirtualBox; however, KVM does expose the TSC deadline timer, and it's virtualized so that it is immune from CPU errata.
Therefore, booting 4.13 with "-cpu Haswell" shows this in the logs:
[ 0.000000] [Firmware Bug]: TSC_DEADLINE disabled due to Errata;
please update microcode to version: 0xb2 (or later)Even if you had a hypervisor that does _not_ virtualize the TSC deadline and rather exposes the hardware one, it should be the hypervisors task to update microcode and possibly hide the flag from CPUID. So just hide the message when running on _any_ hypervisor, not just those that do not support the TSC deadline timer.
The older check still makes sense, so keep it.
--- arch/x86/kernel/apic/apic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kernel/apic/apic.c +2 -1
@@ -602,7 +602,8 @@ static void apic_check_deadline_errata(vconst struct x86_cpu_id *m;u32 rev; -if (!boot_cpu_has (X86_FEATURE_TSC_DEADLINE_TIMER )) +if (!boot_cpu_has (X86_FEATURE_TSC_DEADLINE_TIMER ) || +boot_cpu_has (X86_FEATURE_HYPERVISOR ))return ; m =x86_match_cpu (deadline_match);
Greg Kroah-Hartman
maintainercover 4.13.9-stable review
This is the start of the stable review cycle for the 4.13.9 release. There are 11 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Oct 21 13:16:37 UTC 2017. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.13.9-rc1.gz
or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.13.y
and the diffstat can be found below.
thanks,
greg k-h
-------------
Pseudo-Shortlog of commits:
Greg Kroah-Hartman <[email protected]>
Linux 4.13.9-rc1
Stephen Hemminger <[email protected]>
vmbus: more host signalling avoidance
Stephen Hemminger <[email protected]>
vmbus: eliminate duplicate cached index
Stephen Hemminger <[email protected]>
vmbus: refactor hv_signal_on_read
Stephen Hemminger <[email protected]>
vmbus: simplify hv_ringbuffer_read
K. Y. Srinivasan <[email protected]>
Drivers: hv: vmbus: Fix bugs in rescind handling
K. Y. Srinivasan <[email protected]>
Drivers: hv: vmbus: Fix rescind handling issues
Alex Manoussakis <[email protected]>
HID: hid-elecom: extend to fix descriptor for HUGE trackball
Will Deacon <[email protected]>
mm: page_vma_mapped: ensure pmd is loaded with READ_ONCE outside of lock
Mark Rutland <[email protected]>
perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
Paolo Bonzini <[email protected]>
x86/apic: Silence "FW_BUG TSC_DEADLINE disabled due to Errata" on hypervisors
Hans de Goede <[email protected]>
x86/apic: Silence "FW_BUG TSC_DEADLINE disabled due to Errata" on CPUs without the feature
-------------
Diffstat:
Makefile | 4 +- arch/x86/kernel/apic/apic.c | 7 +- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 2 + drivers/hid/hid-elecom.c | 13 +++- drivers/hid/hid-ids.h | 2 + drivers/hv/channel.c | 20 ++++- drivers/hv/channel_mgmt.c | 54 ++++++++++---- drivers/hv/ring_buffer.c | 162 ++++++++++++++--------------------------- drivers/hv/vmbus_drv.c | 6 +- include/linux/hyperv.h | 67 +---------------- mm/page_vma_mapped.c | 25 +++---- tools/perf/util/parse-events.c | 9 ++- tools/perf/util/pmu.c | 56 ++++++++++---- tools/perf/util/pmu.h | 1 + 15 files changed, 195 insertions(+), 234 deletions(-)
Greg Kroah-Hartman
maintainerPATCH 6/11 Drivers: hv: vmbus: Fix rescind handling issues
4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: K. Y. Srinivasan <[email protected]>
commit 6f3d791f300618caf82a2be0c27456edd76d5164 upstream.
This patch handles the following issues that were observed when we are handling racing channel offer message and rescind message for the same offer:
1. Since the host does not respond to messages on a rescinded channel, in the current code, we could be indefinitely blocked on the vmbus_open() call.
2. When a rescinded channel is being closed, if there is a pending interrupt on the channel, we could end up freeing the channel that the interrupt handler would run on.
--- drivers/hv/channel.c | 14 ++++++++++++++ drivers/hv/channel_mgmt.c | 29 ++++++++++++++++++++++++++--- drivers/hv/vmbus_drv.c | 3 +++ include/linux/hyperv.h | 2 ++ 4 files changed, 45 insertions(+), 3 deletions(-)
drivers/hv/channel.c +14 -0
@@ -177,6 +177,11 @@ int vmbus_open(struct vmbus_channel *new &vmbus_connection.chn_msg_list);spin_unlock_irqrestore (&vmbus_connection.channelmsg_lock, flags); +if (newchannel->rescind) { + err = -ENODEV ; + goto error_free_gpadl; + } + ret =vmbus_post_msg (open_msg,sizeof (struct vmbus_channel_open_channel ), true);
@@ -421,6 +426,11 @@ int vmbus_establish_gpadl(struct vmbus_cspin_unlock_irqrestore (&vmbus_connection.channelmsg_lock, flags); +if (channel->rescind) { + ret = -ENODEV ; + goto cleanup; + } + ret =vmbus_post_msg (gpadlmsg, msginfo->msgsize -sizeof (*msginfo), true);if (ret !=0 )
@@ -494,6 +504,10 @@ int vmbus_teardown_gpadl(struct vmbus_chlist_add_tail (&info->msglistentry, &vmbus_connection.chn_msg_list);spin_unlock_irqrestore (&vmbus_connection.channelmsg_lock, flags); + +if (channel->rescind) + goto post_msg_err; + ret =vmbus_post_msg (msg,sizeof (struct vmbus_channel_gpadl_teardown ), true);
drivers/hv/channel_mgmt.c +26 -3
@@ -451,6 +451,12 @@ static void vmbus_process_offer(struct v/* Make sure this is a new offer */ mutex_lock (&vmbus_connection.channel_mutex); +/* +* Now that we have acquired the channel_mutex, +* we can release the potentially racing rescind thread. +*/ +atomic_dec (&vmbus_connection.offer_in_progress); +list_for_each_entry (channel, &vmbus_connection.chn_list, listentry) { if (!uuid_le_cmp(channel->offermsg.offer.if_type, newchannel->offermsg.offer.if_type) &&
@@ -481,7 +487,6 @@ static void vmbus_process_offer(struct v channel->num_sc++;spin_unlock_irqrestore (&channel->lock, flags); }else { -atomic_dec (&vmbus_connection.offer_in_progress); goto err_free_chan; } }
@@ -510,7 +515,6 @@ static void vmbus_process_offer(struct vif (!fnew) {if (channel->sc_creation_callback !=NULL ) channel->sc_creation_callback (newchannel); -atomic_dec (&vmbus_connection.offer_in_progress);return ; }
@@ -541,7 +545,7 @@ static void vmbus_process_offer(struct v goto err_deq_chan; } -atomic_dec (&vmbus_connection.offer_in_progress); + newchannel->probe_done = true;return ; err_deq_chan:
@@ -882,8 +886,27 @@ static void vmbus_onoffer_rescind(struct channel->rescind = true;spin_unlock_irqrestore (&channel->lock, flags); +/* +* Now that we have posted the rescind state, perform +* rescind related cleanup. +*/ vmbus_rescind_cleanup (channel); +/* +* Now wait for offer handling to complete. +*/ +while (READ_ONCE (channel->probe_done) == false) { +/* +* We wait here until any channel offer is currently +* being processed. +*/ +msleep (1 ); + } + +/* +* At this point, the rescind handling can proceed safely. +*/ +if (channel->device_obj) {if (channel->chn_rescind_callback) { channel->chn_rescind_callback (channel);
drivers/hv/vmbus_drv.c +3 -0
@@ -940,6 +940,9 @@ static void vmbus_chan_sched(struct hv_pif (channel->offermsg.child_relid != relid)continue ; +if (channel->rescind) +continue ; +switch (channel->callback_mode) {case HV_CALL_ISR :vmbus_channel_isr (channel);
include/linux/hyperv.h +2 -0
@@ -895,6 +895,8 @@ struct vmbus_channel {*/ enum hv_numa_policy affinity_policy; +bool probe_done; + };static inline bool is_hvsock_channel (const struct vmbus_channel *c)
Greg Kroah-Hartman
maintainerPATCH 1/11 x86/apic: Silence "FW_BUG TSC_DEADLINE disabled due to Errata" on CPUs without the feature
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede <[email protected]>
commit 594a30fb12424717a41c62323d2a8bf167dbccad upstream.
When booting 4.13 on a VirtualBox VM on a Skylake host the following error shows up in the logs:
[ 0.000000] [Firmware Bug]: TSC_DEADLINE disabled due to Errata;
please update microcode to version: 0xb2 (or later)This is caused by apic_check_deadline_errata() only checking CPU model and not the X86_FEATURE_TSC_DEADLINE_TIMER flag (which VirtualBox does NOT export to the guest), combined with VirtualBox not exporting the micro-code version to the guest.
This commit adds a check for X86_FEATURE_TSC_DEADLINE_TIMER to apic_check_deadline_errata(), silencing this error on VirtualBox VMs.
--- arch/x86/kernel/apic/apic.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/x86/kernel/apic/apic.c +5 -1
@@ -599,9 +599,13 @@ static const struct x86_cpu_id deadline_static void apic_check_deadline_errata (void ) { -const struct x86_cpu_id *m =x86_match_cpu (deadline_match); +const struct x86_cpu_id *m;u32 rev; +if (!boot_cpu_has (X86_FEATURE_TSC_DEADLINE_TIMER )) +return ; + + m =x86_match_cpu (deadline_match);if (!m)return ;
Greg Kroah-Hartman
maintainerPATCH 3/11 perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit 66ec11919a0f96e936bb731fdbc2851316077d26 upstream.
Currently, perf record is broken on arm/arm64 systems when the PMU is specified explicitly as part of the event, e.g.
$ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
In such cases, perf record fails to open events unless perf_event_paranoid is set to -1, even if the PMU in question supports mode exclusion. Further, even when perf_event_paranoid is toggled, no samples are recorded.
This is an unintended side effect of commit:
e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
... which assumes that if a PMU has an associated cpu_map, it is an uncore PMU, and forces events for such PMUs to be system-wide.
This is not true for arm/arm64 systems, which can have heterogeneous CPUs. To account for this, multiple CPU PMUs are exposed, each with a "cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM PMUs do not have a "cpumask" file, and only have a "cpus" file. For the gory details as to why, see commit:
7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
Given all of this, we can instead identify uncore PMUs by explicitly checking for a "cpumask" file, and restore arm/arm64 PMU support back to a working state. This patch does so, adding a new perf_pmu::is_uncore field, and splitting the existing cpumask parsing so that it can be reused.
Tested-by Will Deacon <[email protected]>
--- tools/perf/util/parse-events.c | 9 +++--- tools/perf/util/pmu.c | 56 ++++++++++++++++++++++++++++++----------- tools/perf/util/pmu.h | 1 3 files changed, 47 insertions(+), 19 deletions(-)
tools/perf/util/parse-events.c +5 -4
@@ -309,10 +309,11 @@ static char *get_config_name(struct liststatic struct perf_evsel *__add_event (struct list_head *list,int *idx,struct perf_event_attr *attr, -char *name,struct cpu_map *cpus, +char *name,struct perf_pmu *pmu,struct list_head *config_terms) {struct perf_evsel *evsel; +struct cpu_map *cpus = pmu ? pmu->cpus :NULL ;event_attr_init (attr);
@@ -323,7 +324,7 @@ __add_event(struct list_head *list, int (*idx)++; evsel->cpus =cpu_map__get (cpus); evsel->own_cpus =cpu_map__get (cpus); - evsel->system_wide = !!cpus; + evsel->system_wide = pmu ? pmu->is_uncore : false;if (name) evsel->name =strdup (name);
@@ -1232,7 +1233,7 @@ int parse_events_add_pmu(struct parse_evif (!head_config) { attr.type = pmu->type; - evsel =__add_event (list, &data->idx, &attr,NULL , pmu->cpus,NULL ); + evsel =__add_event (list, &data->idx, &attr,NULL , pmu,NULL );return evsel ?0 : -ENOMEM ; }
@@ -1253,7 +1254,7 @@ int parse_events_add_pmu(struct parse_evreturn -EINVAL ; evsel =__add_event (list, &data->idx, &attr, -get_config_name (head_config), pmu->cpus, +get_config_name (head_config), pmu, &config_terms);if (evsel) { evsel->unit = info.unit;
tools/perf/util/pmu.c +41 -15
84 lines not on this page · raw message
tools/perf/util/pmu.h +1 -0
@@ -22,6 +22,7 @@ struct perf_pmu {char *name;__u32 type;bool selectable; +bool is_uncore;struct perf_event_attr *default_config;struct cpu_map *cpus;struct list_head format;/* HEAD struct perf_pmu_format -> list */
Greg Kroah-Hartman
maintainerPATCH 4/11 mm: page_vma_mapped: ensure pmd is loaded with READ_ONCE outside of lock
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Will Deacon <[email protected]>
commit a7b100953aa33a5bbdc3e5e7f2241b9c0704606e upstream.
Loading the pmd without holding the pmd_lock exposes us to races with concurrent updaters of the page tables but, worse still, it also allows the compiler to cache the pmd value in a register and reuse it later on, even if we've performed a READ_ONCE in between and seen a more recent value.
In the case of page_vma_mapped_walk, this leads to the following crash when the pmd loaded for the initial pmd_trans_huge check is all zeroes and a subsequent valid table entry is loaded by check_pmd. We then proceed into map_pte, but the compiler re-uses the zero entry inside pte_offset_map, resulting in a junk pointer being installed in pvmw->pte:
PC is at check_pte+0x20/0x170
LR is at page_vma_mapped_walk+0x2e0/0x540
[...]
Process doio (pid: 2463, stack limit = 0xffff00000f2e8000)
Call trace:
check_pte+0x20/0x170
page_vma_mapped_walk+0x2e0/0x540
page_mkclean_one+0xac/0x278
rmap_walk_file+0xf0/0x238
rmap_walk+0x64/0xa0
page_mkclean+0x90/0xa8
clear_page_dirty_for_io+0x84/0x2a8
mpage_submit_page+0x34/0x98
mpage_process_page_bufs+0x164/0x170
mpage_prepare_extent_to_map+0x134/0x2b8
ext4_writepages+0x484/0xe30
do_writepages+0x44/0xe8
__filemap_fdatawrite_range+0xbc/0x110
file_write_and_wait_range+0x48/0xd8
ext4_sync_file+0x80/0x4b8
vfs_fsync_range+0x64/0xc0
SyS_msync+0x194/0x1e8This patch fixes the problem by ensuring that READ_ONCE is used before the initial checks on the pmd, and this value is subsequently used when checking whether or not the pmd is present. pmd_check is removed and the pmd_present check is inlined directly.
--- mm/page_vma_mapped.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
mm/page_vma_mapped.c +10 -15
@@ -6,17 +6,6 @@#include "internal.h" -static inline bool check_pmd (struct page_vma_mapped_walk *pvmw) -{ -pmd_t pmde; -/* -* Make sure we don't re-load pmd between present and !trans_huge check. -* We need a consistent view. -*/ - pmde =READ_ONCE (*pvmw->pmd); -return pmd_present (pmde) && !pmd_trans_huge (pmde); -} -static inline bool not_found (struct page_vma_mapped_walk *pvmw) {page_vma_mapped_walk_done (pvmw);
@@ -106,6 +95,7 @@ bool page_vma_mapped_walk(struct page_vmpgd_t *pgd;p4d_t *p4d;pud_t *pud; +pmd_t pmde;/* The only possible pmd mapping has been handled on last iteration */ if (pvmw->pmd && !pvmw->pte)
@@ -138,7 +128,13 @@ restart:if (!pud_present (*pud))return false; pvmw->pmd =pmd_offset (pud, pvmw->address); -if (pmd_trans_huge (*pvmw->pmd)) { +/* +* Make sure the pmd value isn't cached in a register by the +* compiler and used as a stale value after we've observed a +* subsequent update. +*/ + pmde =READ_ONCE (*pvmw->pmd); +if (pmd_trans_huge (pmde)) { pvmw->ptl =pmd_lock (mm, pvmw->pmd);if (!pmd_present (*pvmw->pmd))return not_found (pvmw);
@@ -153,9 +149,8 @@ restart:spin_unlock (pvmw->ptl); pvmw->ptl =NULL ; } - }else { -if (!check_pmd (pvmw)) -return false; + }else if (!pmd_present (pmde)) { +return false; }if (!map_pte (pvmw)) goto next_pte;
Greg Kroah-Hartman
maintainerPATCH 5/11 HID: hid-elecom: extend to fix descriptor for HUGE trackball
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Manoussakis <[email protected]>
commit a0933a456ff83a3b5ffa3a1903e0b8de4a56adf5 upstream.
In addition to DEFT, Elecom introduced a larger trackball called HUGE, in both wired (M-HT1URBK) and wireless (M-HT1DRBK) versions. It has the same buttons and behavior as the DEFT. This patch adds the two relevant USB IDs to enable operation of the three Fn buttons on the top of the device.
--- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 2 ++ drivers/hid/hid-elecom.c | 13 +++++++++---- drivers/hid/hid-ids.h | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-)
drivers/hid/Kconfig +1 -0
@@ -281,6 +281,7 @@ config HID_ELECOM Support for ELECOM devices: - BM084 Bluetooth Mouse - DEFT Trackball (Wired and wireless) + - HUGE Trackball (Wired and wireless) config HID_ELO tristate "ELO USB 4000/4500 touchscreen"
drivers/hid/hid-core.c +2 -0
@@ -2031,6 +2031,8 @@ static const struct hid_device_id hid_ha { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, #endif #if IS_ENABLED(CONFIG_HID_ELO) { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
drivers/hid/hid-elecom.c +9 -4
@@ -3,6 +3,7 @@* Copyright (c) 2010 Richard Nauber <[email protected]> * Copyright (c) 2016 Yuxuan Shui <[email protected]> * Copyright (c) 2017 Diego Elio Pettenò <[email protected]> +* Copyright (c) 2017 Alex Manoussakis <[email protected]> */ /*
@@ -32,9 +33,11 @@ static __u8 *elecom_report_fixup(structbreak ;case USB_DEVICE_ID_ELECOM_DEFT_WIRED :case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS : -/* The DEFT trackball has eight buttons, but its descriptor only -* reports five, disabling the three Fn buttons on the top of -* the mouse. +case USB_DEVICE_ID_ELECOM_HUGE_WIRED : +case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS : +/* The DEFT/HUGE trackball has eight buttons, but its descriptor +* only reports five, disabling the three Fn buttons on the top +* of the mouse. * * Apply the following diff to the descriptor: *
@@ -62,7 +65,7 @@ static __u8 *elecom_report_fixup(struct* End Collection, End Collection, */ if (*rsize ==213 && rdesc[13 ] ==5 && rdesc[21 ] ==5 ) { -hid_info (hdev,"Fixing up Elecom DEFT Fn buttons\n" ); +hid_info (hdev,"Fixing up Elecom DEFT/HUGE Fn buttons\n" ); rdesc[13 ] =8 ;/* Button/Variable Report Count */ rdesc[21 ] =8 ;/* Button/Variable Usage Maximum */ rdesc[29 ] =0 ;/* Button/Constant Report Count */
@@ -76,6 +79,8 @@ static const struct hid_device_id elecom { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, { } };MODULE_DEVICE_TABLE (hid, elecom_devices);
drivers/hid/hid-ids.h +2 -0
@@ -366,6 +366,8 @@#define USB_DEVICE_ID_ELECOM_BM084 0x0061#define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe#define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff +#define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c +#define USB_DEVICE_ID_ELECOM_HUGE_WIRELESS 0x010d#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34#define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004
Greg Kroah-Hartman
maintainerPATCH 7/11 Drivers: hv: vmbus: Fix bugs in rescind handling
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: K. Y. Srinivasan <[email protected]>
commit 192b2d78722ffea188e5ec6ae5d55010dce05a4b upstream.
This patch addresses the following bugs in the current rescind handling code:
1. Fixes a race condition where we may be invoking hv_process_channel_removal() on an already freed channel.
2. Prevents indefinite wait when rescinding sub-channels by correctly setting the probe_complete state.
I would like to thank Dexuan for patiently reviewing earlier versions of this patch and identifying many of the issues fixed here.
Greg, please apply this to 4.14-final.
--- drivers/hv/channel.c | 6 +++--- drivers/hv/channel_mgmt.c | 37 ++++++++++++++++++------------------- drivers/hv/vmbus_drv.c | 3 +-- include/linux/hyperv.h | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-)
drivers/hv/channel.c +3 -3
@@ -640,6 +640,7 @@ void vmbus_close(struct vmbus_channel *c*/ return ; } +mutex_lock (&vmbus_connection.channel_mutex);/* * Close all the sub-channels first and then close the * primary channel.
@@ -648,16 +649,15 @@ void vmbus_close(struct vmbus_channel *c cur_channel = list_entry(cur, struct vmbus_channel, sc_list);vmbus_close_internal (cur_channel);if (cur_channel->rescind) { -mutex_lock (&vmbus_connection.channel_mutex); -hv_process_channel_removal (cur_channel, +hv_process_channel_removal ( cur_channel->offermsg.child_relid); -mutex_unlock (&vmbus_connection.channel_mutex); } }/* * Now close the primary. */ vmbus_close_internal (channel); +mutex_unlock (&vmbus_connection.channel_mutex); }EXPORT_SYMBOL_GPL (vmbus_close);
drivers/hv/channel_mgmt.c +18 -19
@@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(structspin_lock_irqsave (&vmbus_connection.channelmsg_lock, flags); - + channel->rescind = true;list_for_each_entry (msginfo, &vmbus_connection.chn_msg_list, msglistentry) {
@@ -381,14 +381,21 @@ static void vmbus_release_relid(u32 reli true); } -void hv_process_channel_removal (struct vmbus_channel *channel,u32 relid) +void hv_process_channel_removal (u32 relid) {unsigned long flags; -struct vmbus_channel *primary_channel; +struct vmbus_channel *primary_channel, *channel; -BUG_ON (!channel->rescind);BUG_ON (!mutex_is_locked (&vmbus_connection.channel_mutex)); +/* +* Make sure channel is valid as we may have raced. +*/ + channel =relid2channel (relid); +if (!channel) +return ; + +BUG_ON (!channel->rescind);if (channel->target_cpu !=get_cpu ()) {put_cpu (); smp_call_function_single(channel->target_cpu,
@@ -515,6 +522,7 @@ static void vmbus_process_offer(struct vif (!fnew) {if (channel->sc_creation_callback !=NULL ) channel->sc_creation_callback (newchannel); + newchannel->probe_done = true;return ; }
@@ -843,7 +851,6 @@ static void vmbus_onoffer_rescind(struct {struct vmbus_channel_rescind_offer *rescind;struct vmbus_channel *channel; -unsigned long flags;struct device *dev; rescind = (struct vmbus_channel_rescind_offer *)hdr;
@@ -882,16 +889,6 @@ static void vmbus_onoffer_rescind(structreturn ; } -spin_lock_irqsave (&channel->lock, flags); - channel->rescind = true; -spin_unlock_irqrestore (&channel->lock, flags); - -/* -* Now that we have posted the rescind state, perform -* rescind related cleanup. -*/ -vmbus_rescind_cleanup (channel); -/* * Now wait for offer handling to complete. */
@@ -910,6 +907,7 @@ static void vmbus_onoffer_rescind(structif (channel->device_obj) {if (channel->chn_rescind_callback) { channel->chn_rescind_callback (channel); +vmbus_rescind_cleanup (channel);return ; }/*
@@ -918,6 +916,7 @@ static void vmbus_onoffer_rescind(struct*/ dev =get_device (&channel->device_obj->device);if (dev) { +vmbus_rescind_cleanup (channel);vmbus_device_unregister (channel->device_obj);put_device (dev); }
@@ -930,16 +929,16 @@ static void vmbus_onoffer_rescind(struct* 1. Close all sub-channels first * 2. Then close the primary channel. */ +mutex_lock (&vmbus_connection.channel_mutex); +vmbus_rescind_cleanup (channel);if (channel->state ==CHANNEL_OPEN_STATE ) {/* * The channel is currently not open; * it is safe for us to cleanup the channel. */ -mutex_lock (&vmbus_connection.channel_mutex); -hv_process_channel_removal (channel, - channel->offermsg.child_relid); -mutex_unlock (&vmbus_connection.channel_mutex); +hv_process_channel_removal (rescind->child_relid); } +mutex_unlock (&vmbus_connection.channel_mutex); } }
drivers/hv/vmbus_drv.c +1 -2
@@ -768,8 +768,7 @@ static void vmbus_device_release(structstruct vmbus_channel *channel = hv_dev->channel;mutex_lock (&vmbus_connection.channel_mutex); -hv_process_channel_removal (channel, - channel->offermsg.child_relid); +hv_process_channel_removal (channel->offermsg.child_relid);mutex_unlock (&vmbus_connection.channel_mutex);kfree (hv_dev);
include/linux/hyperv.h +1 -1
@@ -1455,7 +1455,7 @@ extern bool vmbus_prep_negotiate_resp(st const int *srv_version, int srv_vercnt, int *nego_fw_version, int *nego_srv_version); -void hv_process_channel_removal (struct vmbus_channel *channel,u32 relid); +void hv_process_channel_removal (u32 relid);void vmbus_setevent (struct vmbus_channel *channel);/*
Greg Kroah-Hartman
maintainerPATCH 8/11 vmbus: simplify hv_ringbuffer_read
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
commit 4226ff69a3dff78bead7d9a270423cd21f8d40b8 upstream.
With new iterator functions (and the double mapping) the ring buffer read function can be greatly simplified.
--- drivers/hv/ring_buffer.c | 116 ++++++----------------------------------------- 1 file changed, 16 insertions(+), 100 deletions(-)
drivers/hv/ring_buffer.c +16 -100
@@ -94,30 +94,6 @@ hv_set_next_write_location(struct hv_rin ring_info->ring_buffer->write_index = next_write_location; } -/* Get the next read location for the specified ring buffer. */ -static inline u32 -hv_get_next_read_location (const struct hv_ring_buffer_info *ring_info) -{ -return ring_info->ring_buffer->read_index; -} - -/* -* Get the next read location + offset for the specified ring buffer. -* This allows the caller to skip. -*/ -static inline u32 -hv_get_next_readlocation_withoffset (const struct hv_ring_buffer_info *ring_info, -u32 offset) -{ -u32 next = ring_info->ring_buffer->read_index; - - next += offset; -if (next >= ring_info->ring_datasize) - next -= ring_info->ring_datasize; - -return next; -} -/* Set the next read location for the specified ring buffer. */ static inline void hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
@@ -142,29 +118,6 @@ hv_get_ring_bufferindices(struct hv_ring }/* -* Helper routine to copy to source from ring buffer. -* Assume there is enough room. Handles wrap-around in src case only!! -*/ -static u32 hv_copyfrom_ringbuffer ( -const struct hv_ring_buffer_info *ring_info, -void *dest, -u32 destlen, -u32 start_read_offset) -{ -void *ring_buffer =hv_get_ring_buffer (ring_info); -u32 ring_buffer_size =hv_get_ring_buffersize (ring_info); - -memcpy (dest, ring_buffer + start_read_offset, destlen); - - start_read_offset += destlen; -if (start_read_offset >= ring_buffer_size) - start_read_offset -= ring_buffer_size; - -return start_read_offset; -} - - -/* * Helper routine to copy from source to ring buffer. * Assume there is enough room. Handles wrap-around in dest case only!! */
@@ -334,33 +287,22 @@ int hv_ringbuffer_write(struct vmbus_chareturn 0 ; } -static inline void -init_cached_read_index (struct hv_ring_buffer_info *rbi) -{ - rbi->cached_read_index = rbi->ring_buffer->read_index; -} -int hv_ringbuffer_read (struct vmbus_channel *channel,void *buffer,u32 buflen,u32 *buffer_actual_len,u64 *requestid,bool raw) { -u32 bytes_avail_toread; -u32 next_read_location; -u64 prev_indices =0 ; -struct vmpacket_descriptor desc; -u32 offset; -u32 packetlen; -struct hv_ring_buffer_info *inring_info = &channel->inbound; +struct vmpacket_descriptor *desc; +u32 packetlen, offset; -if (buflen <=0 ) +if (unlikely (buflen ==0 ))return -EINVAL ; *buffer_actual_len =0 ; *requestid =0 ; - bytes_avail_toread =hv_get_bytes_to_read (inring_info);/* Make sure there is something to read */ -if (bytes_avail_toread <sizeof (desc)) { + desc =hv_pkt_iter_first (channel); +if (desc ==NULL ) {/* * No error is set when there is even no header, drivers are * supposed to analyze buffer_actual_len.
@@ -368,48 +310,22 @@ int hv_ringbuffer_read(struct vmbus_chanreturn 0 ; } -init_cached_read_index (inring_info); - - next_read_location =hv_get_next_read_location (inring_info); - next_read_location =hv_copyfrom_ringbuffer (inring_info, &desc, -sizeof (desc), - next_read_location); - - offset = raw ?0 : (desc.offset8 <<3 ); - packetlen = (desc.len8 <<3 ) - offset; + offset = raw ?0 : (desc->offset8 <<3 ); + packetlen = (desc->len8 <<3 ) - offset; *buffer_actual_len = packetlen; - *requestid = desc.trans_id; - -if (bytes_avail_toread < packetlen + offset) -return -EAGAIN ; + *requestid = desc->trans_id; -if (packetlen > buflen) +if (unlikely (packetlen > buflen))return -ENOBUFS ; - next_read_location = -hv_get_next_readlocation_withoffset (inring_info, offset); +/* since ring is double mapped, only one copy is necessary */ +memcpy (buffer, (const char *)desc + offset, packetlen); - next_read_location =hv_copyfrom_ringbuffer (inring_info, - buffer, - packetlen, - next_read_location); - - next_read_location =hv_copyfrom_ringbuffer (inring_info, - &prev_indices, -sizeof (u64), - next_read_location); +/* Advance ring index to next packet descriptor */ +__hv_pkt_iter_next (channel, desc); -/* -* Make sure all reads are done before we update the read index since -* the writer may start writing to the read area once the read index -* is updated. -*/ -virt_mb (); - -/* Update the read index */ -hv_set_next_read_location (inring_info, next_read_location); - -hv_signal_on_read (channel); +/* Notify host of update */ +hv_pkt_iter_close (channel);return 0 ; }
@@ -442,7 +358,7 @@ struct vmpacket_descriptor *hv_pkt_iter_struct hv_ring_buffer_info *rbi = &channel->inbound;/* set state for later hv_signal_on_read() */ -init_cached_read_index (rbi); + rbi->cached_read_index = rbi->ring_buffer->read_index;if (hv_pkt_iter_avail (rbi) <sizeof (struct vmpacket_descriptor ))return NULL ;
Greg Kroah-Hartman
maintainerPATCH 9/11 vmbus: refactor hv_signal_on_read
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
commit 8dd45f2ab005a1f3301296059b23b03ec3dbf79b upstream.
The function hv_signal_on_read was defined in hyperv.h and only used in one place in ring_buffer code. Clearer to just move it inline there.
--- drivers/hv/ring_buffer.c | 32 ++++++++++++++++++++++++++++-- include/linux/hyperv.h | 49 ----------------------------------------------- 2 files changed, 30 insertions(+), 51 deletions(-)
drivers/hv/ring_buffer.c +30 -2
@@ -29,6 +29,7 @@#include <linux/uio.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/prefetch.h> #include "hyperv_vmbus.h"
@@ -357,7 +358,7 @@ struct vmpacket_descriptor *hv_pkt_iter_ {struct hv_ring_buffer_info *rbi = &channel->inbound; -/* set state for later hv_signal_on_read() */ +/* set state for later hv_pkt_iter_close */ rbi->cached_read_index = rbi->ring_buffer->read_index;if (hv_pkt_iter_avail (rbi) <sizeof (struct vmpacket_descriptor ))
@@ -400,6 +401,8 @@ EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);void hv_pkt_iter_close (struct vmbus_channel *channel) {struct hv_ring_buffer_info *rbi = &channel->inbound; +u32 cur_write_sz, cached_write_sz; +u32 pending_sz;/* * Make sure all reads are done before we update the read index since
@@ -409,6 +412,31 @@ void hv_pkt_iter_close(struct vmbus_chanvirt_rmb (); rbi->ring_buffer->read_index = rbi->priv_read_index; -hv_signal_on_read (channel); +/* +* Issue a full memory barrier before making the signaling decision. +* Here is the reason for having this barrier: +* If the reading of the pend_sz (in this function) +* were to be reordered and read before we commit the new read +* index (in the calling function) we could +* have a problem. If the host were to set the pending_sz after we +* have sampled pending_sz and go to sleep before we commit the +* read index, we could miss sending the interrupt. Issue a full +* memory barrier to address this. +*/ +virt_mb (); + + pending_sz =READ_ONCE (rbi->ring_buffer->pending_send_sz); +/* If the other end is not blocked on write don't bother. */ +if (pending_sz ==0 ) +return ; + + cur_write_sz =hv_get_bytes_to_write (rbi); + +if (cur_write_sz < pending_sz) +return ; + + cached_write_sz =hv_get_cached_bytes_to_write (rbi); +if (cached_write_sz < pending_sz) +vmbus_setevent (channel); }EXPORT_SYMBOL_GPL (hv_pkt_iter_close);
include/linux/hyperv.h +0 -49
55 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 10/11 vmbus: eliminate duplicate cached index
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
commit 05d00bc94ac27d220d8a78e365d7fa3a26dcca17 upstream.
Don't need cached read index anymore now that packet iterator is used. The iterator has the original read index until the visible read_index is updated.
--- drivers/hv/ring_buffer.c | 17 ++++------------- include/linux/hyperv.h | 14 -------------- 2 files changed, 4 insertions(+), 27 deletions(-)
drivers/hv/ring_buffer.c +4 -13
@@ -358,9 +358,6 @@ struct vmpacket_descriptor *hv_pkt_iter_ {struct hv_ring_buffer_info *rbi = &channel->inbound; -/* set state for later hv_pkt_iter_close */ - rbi->cached_read_index = rbi->ring_buffer->read_index; -if (hv_pkt_iter_avail (rbi) <sizeof (struct vmpacket_descriptor ))return NULL ;
@@ -388,10 +385,7 @@ __hv_pkt_iter_next(struct vmbus_channel rbi->priv_read_index -= dsize;/* more data? */ -if (hv_pkt_iter_avail (rbi) <sizeof (struct vmpacket_descriptor )) -return NULL ; -else -return hv_get_ring_buffer (rbi) + rbi->priv_read_index; +return hv_pkt_iter_first (channel); }EXPORT_SYMBOL_GPL (__hv_pkt_iter_next);
@@ -401,7 +395,7 @@ EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);void hv_pkt_iter_close (struct vmbus_channel *channel) {struct hv_ring_buffer_info *rbi = &channel->inbound; -u32 cur_write_sz, cached_write_sz; +u32 orig_write_sz =hv_get_bytes_to_write (rbi);u32 pending_sz;/*
@@ -430,13 +424,10 @@ void hv_pkt_iter_close(struct vmbus_chanif (pending_sz ==0 )return ; - cur_write_sz =hv_get_bytes_to_write (rbi); - -if (cur_write_sz < pending_sz) +if (hv_get_bytes_to_write (rbi) < pending_sz)return ; - cached_write_sz =hv_get_cached_bytes_to_write (rbi); -if (cached_write_sz < pending_sz) +if (orig_write_sz < pending_sz)vmbus_setevent (channel); }EXPORT_SYMBOL_GPL (hv_pkt_iter_close);
include/linux/hyperv.h +0 -14
@@ -127,7 +127,6 @@ struct hv_ring_buffer_info {u32 ring_data_startoffset;u32 priv_write_index;u32 priv_read_index; -u32 cached_read_index; };/*
@@ -180,19 +179,6 @@ static inline u32 hv_get_bytes_to_write(return write; } -static inline u32 hv_get_cached_bytes_to_write ( -const struct hv_ring_buffer_info *rbi) -{ -u32 read_loc, write_loc, dsize, write; - - dsize = rbi->ring_datasize; - read_loc = rbi->cached_read_index; - write_loc = rbi->ring_buffer->write_index; - - write = write_loc >= read_loc ? dsize - (write_loc - read_loc) : - read_loc - write_loc; -return write; -}/* * VMBUS version is 32 bit entity broken up into * two 16 bit quantities: major_number. minor_number.
Greg Kroah-Hartman
maintainerPATCH 11/11 vmbus: more host signalling avoidance
In reply to Greg Kroah-Hartman4.13-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
commit 03bad714a1619c0074eb44d6f217c505fe27030f upstream.
Don't signal host if it has disabled interrupts for that ring buffer. Check the feature bit to see if host supports pending send size flag.
--- drivers/hv/ring_buffer.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
drivers/hv/ring_buffer.c +19 -8
@@ -396,7 +396,6 @@ void hv_pkt_iter_close(struct vmbus_chan {struct hv_ring_buffer_info *rbi = &channel->inbound;u32 orig_write_sz =hv_get_bytes_to_write (rbi); -u32 pending_sz;/* * Make sure all reads are done before we update the read index since
@@ -419,15 +418,27 @@ void hv_pkt_iter_close(struct vmbus_chan*/ virt_mb (); - pending_sz =READ_ONCE (rbi->ring_buffer->pending_send_sz); -/* If the other end is not blocked on write don't bother. */ -if (pending_sz ==0 ) +/* If host has disabled notifications then skip */ +if (rbi->ring_buffer->interrupt_mask)return ; -if (hv_get_bytes_to_write (rbi) < pending_sz) -return ; +if (rbi->ring_buffer->feature_bits.feat_pending_send_sz) { +u32 pending_sz =READ_ONCE (rbi->ring_buffer->pending_send_sz); + +/* +* If there was space before we began iteration, +* then host was not blocked. Also handles case where +* pending_sz is zero then host has nothing pending +* and does not need to be signaled. +*/ +if (orig_write_sz > pending_sz) +return ; + +/* If pending write will not fit, don't give false hope. */ +if (hv_get_bytes_to_write (rbi) < pending_sz) +return ; + } -if (orig_write_sz < pending_sz) -vmbus_setevent (channel); +vmbus_setevent (channel); }EXPORT_SYMBOL_GPL (hv_pkt_iter_close);
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.13.9 release. There are 11 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Oct 21 13:16:37 UTC 2017. Anything received after that time might be too late.
Build results:
total: 145 pass: 145 fail: 0 Qemu test results: total: 123 pass: 123 fail: 0
Detauls are available at http://kerneltests.org/builders.
Guenter
Greg Kroah-Hartman
maintainerQuoted 11 lines · Guenter Roeck
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 4.13.9 release. There are 11 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat Oct 21 13:16:37 UTC 2017. Anything received after that time might be too late.
Quoted 6 lines
Build results:
total: 145 pass: 145 fail: 0 Qemu test results: total: 123 pass: 123 fail: 0Detauls are available at http://kerneltests.org/builders.
Thanks for testing all of these and letting me know.
greg k-h