summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2017-10-21 16:16:08 -0400
committerMike Pagano <mpagano@gentoo.org>2017-10-21 16:16:08 -0400
commit62163c3e2846e0b8240d82bce060059c8bd2b598 (patch)
tree2e78b0a6db0dd57133e64ee745e7bb3a5bd729e1
parentLinux patch 4.13.8 (diff)
downloadlinux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.tar.gz
linux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.tar.bz2
linux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.zip
Linux patch 4.13.94.13-11
-rw-r--r--0000_README4
-rw-r--r--1008_linux-4.13.9.patch903
2 files changed, 907 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 37fc5da9..9628e897 100644
--- a/0000_README
+++ b/0000_README
@@ -75,6 +75,10 @@ Patch: 1007_linux-4.13.8.patch
From: http://www.kernel.org
Desc: Linux 4.13.8
+Patch: 1008_linux-4.13.9.patch
+From: http://www.kernel.org
+Desc: Linux 4.13.9
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1008_linux-4.13.9.patch b/1008_linux-4.13.9.patch
new file mode 100644
index 00000000..fb55923c
--- /dev/null
+++ b/1008_linux-4.13.9.patch
@@ -0,0 +1,903 @@
+diff --git a/Makefile b/Makefile
+index 66ec023da822..aa0267950444 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 13
+-SUBLEVEL = 8
++SUBLEVEL = 9
+ EXTRAVERSION =
+ NAME = Fearless Coyote
+
+diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
+index 98b3dd8cf2bf..a7be1b4283a0 100644
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -599,9 +599,14 @@ static const struct x86_cpu_id deadline_match[] = {
+
+ 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) ||
++ boot_cpu_has(X86_FEATURE_HYPERVISOR))
++ return;
++
++ m = x86_match_cpu(deadline_match);
+ if (!m)
+ return;
+
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index 3cd60f460b61..8b27211f6c50 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -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"
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index 9017dcc14502..efb3501b4123 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -2031,6 +2031,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
+ { 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) },
+diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
+index e2c7465df69f..54aeea57d209 100644
+--- a/drivers/hid/hid-elecom.c
++++ b/drivers/hid/hid-elecom.c
+@@ -3,6 +3,7 @@
+ * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
+ * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
+ * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu>
++ * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org>
+ */
+
+ /*
+@@ -32,9 +33,11 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ break;
+ 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 hid_device *hdev, __u8 *rdesc,
+ * 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_devices[] = {
+ { 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);
+diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
+index c9ba4c6db74c..1333ac5c6597 100644
+--- a/drivers/hid/hid-ids.h
++++ b/drivers/hid/hid-ids.h
+@@ -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
+diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
+index e57cc40cb768..be3fccab07fe 100644
+--- a/drivers/hv/channel.c
++++ b/drivers/hv/channel.c
+@@ -177,6 +177,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
+ &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_channel *channel, void *kbuffer,
+
+ spin_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_channel *channel, u32 gpadl_handle)
+ list_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);
+
+@@ -626,6 +640,7 @@ void vmbus_close(struct vmbus_channel *channel)
+ */
+ return;
+ }
++ mutex_lock(&vmbus_connection.channel_mutex);
+ /*
+ * Close all the sub-channels first and then close the
+ * primary channel.
+@@ -634,16 +649,15 @@ void vmbus_close(struct vmbus_channel *channel)
+ 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);
+
+diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
+index 037361158074..18c94ed02562 100644
+--- a/drivers/hv/channel_mgmt.c
++++ b/drivers/hv/channel_mgmt.c
+@@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(struct vmbus_channel *channel)
+
+
+ spin_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 relid)
+ 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,
+@@ -451,6 +458,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
+ /* 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 +494,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
+ channel->num_sc++;
+ spin_unlock_irqrestore(&channel->lock, flags);
+ } else {
+- atomic_dec(&vmbus_connection.offer_in_progress);
+ goto err_free_chan;
+ }
+ }
+@@ -510,7 +522,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
+ if (!fnew) {
+ if (channel->sc_creation_callback != NULL)
+ channel->sc_creation_callback(newchannel);
+- atomic_dec(&vmbus_connection.offer_in_progress);
++ newchannel->probe_done = true;
+ return;
+ }
+
+@@ -541,7 +553,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
+ goto err_deq_chan;
+ }
+
+- atomic_dec(&vmbus_connection.offer_in_progress);
++ newchannel->probe_done = true;
+ return;
+
+ err_deq_chan:
+@@ -839,7 +851,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+ {
+ struct vmbus_channel_rescind_offer *rescind;
+ struct vmbus_channel *channel;
+- unsigned long flags;
+ struct device *dev;
+
+ rescind = (struct vmbus_channel_rescind_offer *)hdr;
+@@ -878,15 +889,25 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+ return;
+ }
+
+- spin_lock_irqsave(&channel->lock, flags);
+- channel->rescind = true;
+- spin_unlock_irqrestore(&channel->lock, flags);
++ /*
++ * 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);
++ }
+
+- vmbus_rescind_cleanup(channel);
++ /*
++ * At this point, the rescind handling can proceed safely.
++ */
+
+ if (channel->device_obj) {
+ if (channel->chn_rescind_callback) {
+ channel->chn_rescind_callback(channel);
++ vmbus_rescind_cleanup(channel);
+ return;
+ }
+ /*
+@@ -895,6 +916,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+ */
+ dev = get_device(&channel->device_obj->device);
+ if (dev) {
++ vmbus_rescind_cleanup(channel);
+ vmbus_device_unregister(channel->device_obj);
+ put_device(dev);
+ }
+@@ -907,16 +929,16 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+ * 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);
+ }
+ }
+
+diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
+index 1f450c39a9b0..741daa6e2fc7 100644
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -29,6 +29,7 @@
+ #include <linux/uio.h>
+ #include <linux/vmalloc.h>
+ #include <linux/slab.h>
++#include <linux/prefetch.h>
+
+ #include "hyperv_vmbus.h"
+
+@@ -94,30 +95,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
+ 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,
+@@ -141,29 +118,6 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
+ return (u64)ring_info->ring_buffer->write_index << 32;
+ }
+
+-/*
+- * 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 +288,22 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
+ return 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;
+-
+- if (buflen <= 0)
++ struct vmpacket_descriptor *desc;
++ u32 packetlen, offset;
++
++ 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 +311,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
+ return 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);
++ /* Advance ring index to next packet descriptor */
++ __hv_pkt_iter_next(channel, desc);
+
+- next_read_location = hv_copyfrom_ringbuffer(inring_info,
+- &prev_indices,
+- sizeof(u64),
+- next_read_location);
+-
+- /*
+- * 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;
+ }
+@@ -441,9 +358,6 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
+ {
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+- /* set state for later hv_signal_on_read() */
+- init_cached_read_index(rbi);
+-
+ if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ return NULL;
+
+@@ -471,10 +385,7 @@ __hv_pkt_iter_next(struct vmbus_channel *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);
+
+@@ -484,6 +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 orig_write_sz = hv_get_bytes_to_write(rbi);
+
+ /*
+ * Make sure all reads are done before we update the read index since
+@@ -493,6 +405,40 @@ void hv_pkt_iter_close(struct vmbus_channel *channel)
+ virt_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();
++
++ /* If host has disabled notifications then skip */
++ if (rbi->ring_buffer->interrupt_mask)
++ 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;
++ }
++
++ vmbus_setevent(channel);
+ }
+ EXPORT_SYMBOL_GPL(hv_pkt_iter_close);
+diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
+index ed84e96715a0..5ad627044dd1 100644
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -768,8 +768,7 @@ static void vmbus_device_release(struct device *device)
+ struct 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);
+
+@@ -940,6 +939,9 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
+ if (channel->offermsg.child_relid != relid)
+ continue;
+
++ if (channel->rescind)
++ continue;
++
+ switch (channel->callback_mode) {
+ case HV_CALL_ISR:
+ vmbus_channel_isr(channel);
+diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
+index b7d7bbec74e0..3647085dab0a 100644
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -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(const struct hv_ring_buffer_info *rbi)
+ 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.
+@@ -895,6 +881,8 @@ struct vmbus_channel {
+ */
+ enum hv_numa_policy affinity_policy;
+
++ bool probe_done;
++
+ };
+
+ static inline bool is_hvsock_channel(const struct vmbus_channel *c)
+@@ -1453,7 +1441,7 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf,
+ 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);
+ /*
+@@ -1473,55 +1461,6 @@ hv_get_ring_buffer(const struct hv_ring_buffer_info *ring_info)
+ return ring_info->ring_buffer->buffer;
+ }
+
+-/*
+- * To optimize the flow management on the send-side,
+- * when the sender is blocked because of lack of
+- * sufficient space in the ring buffer, potential the
+- * consumer of the ring buffer can signal the producer.
+- * This is controlled by the following parameters:
+- *
+- * 1. pending_send_sz: This is the size in bytes that the
+- * producer is trying to send.
+- * 2. The feature bit feat_pending_send_sz set to indicate if
+- * the consumer of the ring will signal when the ring
+- * state transitions from being full to a state where
+- * there is room for the producer to send the pending packet.
+- */
+-
+-static inline void hv_signal_on_read(struct vmbus_channel *channel)
+-{
+- u32 cur_write_sz, cached_write_sz;
+- u32 pending_sz;
+- struct hv_ring_buffer_info *rbi = &channel->inbound;
+-
+- /*
+- * 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);
+-}
+-
+ /*
+ * Mask off host interrupt callback notifications
+ */
+diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c
+index 8ec6ba230bb9..6b9311631aa1 100644
+--- a/mm/page_vma_mapped.c
++++ b/mm/page_vma_mapped.c
+@@ -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_vma_mapped_walk *pvmw)
+ pgd_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 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
+ 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 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
+ 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;
+diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
+index 01e779b91c8e..2e3ffc3bc483 100644
+--- a/tools/perf/util/parse-events.c
++++ b/tools/perf/util/parse-events.c
+@@ -309,10 +309,11 @@ static char *get_config_name(struct list_head *head_terms)
+ static 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,
+ (*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_events_evlist *data,
+
+ if (!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_events_evlist *data,
+ return -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;
+diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
+index ac16a9db1fb5..1c4d7b4e4fb5 100644
+--- a/tools/perf/util/pmu.c
++++ b/tools/perf/util/pmu.c
+@@ -470,17 +470,36 @@ static void pmu_read_sysfs(void)
+ closedir(dir);
+ }
+
++static struct cpu_map *__pmu_cpumask(const char *path)
++{
++ FILE *file;
++ struct cpu_map *cpus;
++
++ file = fopen(path, "r");
++ if (!file)
++ return NULL;
++
++ cpus = cpu_map__read(file);
++ fclose(file);
++ return cpus;
++}
++
++/*
++ * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
++ * may have a "cpus" file.
++ */
++#define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask"
++#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"
++
+ static struct cpu_map *pmu_cpumask(const char *name)
+ {
+- struct stat st;
+ char path[PATH_MAX];
+- FILE *file;
+ struct cpu_map *cpus;
+ const char *sysfs = sysfs__mountpoint();
+ const char *templates[] = {
+- "%s/bus/event_source/devices/%s/cpumask",
+- "%s/bus/event_source/devices/%s/cpus",
+- NULL
++ CPUS_TEMPLATE_UNCORE,
++ CPUS_TEMPLATE_CPU,
++ NULL
+ };
+ const char **template;
+
+@@ -489,20 +508,25 @@ static struct cpu_map *pmu_cpumask(const char *name)
+
+ for (template = templates; *template; template++) {
+ snprintf(path, PATH_MAX, *template, sysfs, name);
+- if (stat(path, &st) == 0)
+- break;
++ cpus = __pmu_cpumask(path);
++ if (cpus)
++ return cpus;
+ }
+
+- if (!*template)
+- return NULL;
++ return NULL;
++}
+
+- file = fopen(path, "r");
+- if (!file)
+- return NULL;
++static bool pmu_is_uncore(const char *name)
++{
++ char path[PATH_MAX];
++ struct cpu_map *cpus;
++ const char *sysfs = sysfs__mountpoint();
+
+- cpus = cpu_map__read(file);
+- fclose(file);
+- return cpus;
++ snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
++ cpus = __pmu_cpumask(path);
++ cpu_map__put(cpus);
++
++ return !!cpus;
+ }
+
+ /*
+@@ -617,6 +641,8 @@ static struct perf_pmu *pmu_lookup(const char *name)
+
+ pmu->cpus = pmu_cpumask(name);
+
++ pmu->is_uncore = pmu_is_uncore(name);
++
+ INIT_LIST_HEAD(&pmu->format);
+ INIT_LIST_HEAD(&pmu->aliases);
+ list_splice(&format, &pmu->format);
+diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
+index 389e9729331f..fe0de0502ce2 100644
+--- a/tools/perf/util/pmu.h
++++ b/tools/perf/util/pmu.h
+@@ -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 */