commit:     62163c3e2846e0b8240d82bce060059c8bd2b598
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sat Oct 21 20:16:08 2017 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sat Oct 21 20:16:08 2017 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=62163c3e

Linux patch 4.13.9

 0000_README             |   4 +
 1008_linux-4.13.9.patch | 903 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 907 insertions(+)

diff --git a/0000_README b/0000_README
index 37fc5da..9628e89 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 0000000..fb55923
--- /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 <[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(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 */

Reply via email to