diff options
author | 2017-10-21 16:16:08 -0400 | |
---|---|---|
committer | 2017-10-21 16:16:08 -0400 | |
commit | 62163c3e2846e0b8240d82bce060059c8bd2b598 (patch) | |
tree | 2e78b0a6db0dd57133e64ee745e7bb3a5bd729e1 | |
parent | Linux patch 4.13.8 (diff) | |
download | linux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.tar.gz linux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.tar.bz2 linux-patches-62163c3e2846e0b8240d82bce060059c8bd2b598.zip |
Linux patch 4.13.94.13-11
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1008_linux-4.13.9.patch | 903 |
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 */ |