commit:     68139056db38086bc47aad0b9dca0f83afcda2ef
Author:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
AuthorDate: Tue Jan 13 14:32:45 2026 +0000
Commit:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
CommitDate: Tue Jan 13 14:32:45 2026 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=68139056

Linux patch 6.12.65

Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org>

 0000_README              |   4 +
 1064_linux-6.12.65.patch | 766 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 770 insertions(+)

diff --git a/0000_README b/0000_README
index f387afa9..f6514460 100644
--- a/0000_README
+++ b/0000_README
@@ -299,6 +299,10 @@ Patch:  1063_linux-6.12.64.patch
 From:   https://www.kernel.org
 Desc:   Linux 6.12.64
 
+Patch:  1064_linux-6.12.65.patch
+From:   https://www.kernel.org
+Desc:   Linux 6.12.65
+
 Patch:  1500_fortify-copy-size-value-range-tracking-fix.patch
 From:   https://git.kernel.org/
 Desc:   fortify: Hide run-time copy size from value range tracking

diff --git a/1064_linux-6.12.65.patch b/1064_linux-6.12.65.patch
new file mode 100644
index 00000000..c92c69bc
--- /dev/null
+++ b/1064_linux-6.12.65.patch
@@ -0,0 +1,766 @@
+diff --git a/Makefile b/Makefile
+index e8e272e1187b54..ab23f9796ac431 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 6
+ PATCHLEVEL = 12
+-SUBLEVEL = 64
++SUBLEVEL = 65
+ EXTRAVERSION =
+ NAME = Baby Opossum Posse
+ 
+diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
+index abcfdd3c291835..8c4e2b1e3de0ed 100644
+--- a/drivers/char/virtio_console.c
++++ b/drivers/char/virtio_console.c
+@@ -1579,8 +1579,8 @@ static void handle_control_message(struct virtio_device 
*vdev,
+               break;
+       case VIRTIO_CONSOLE_RESIZE: {
+               struct {
+-                      __virtio16 rows;
+                       __virtio16 cols;
++                      __virtio16 rows;
+               } size;
+ 
+               if (!is_console_port(port))
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index d0f4f7c2ae4d94..9d8cb44c26c70e 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -600,9 +600,6 @@ static bool turbo_is_disabled(void)
+ {
+       u64 misc_en;
+ 
+-      if (!cpu_feature_enabled(X86_FEATURE_IDA))
+-              return true;
+-
+       rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
+ 
+       return !!(misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
+@@ -2018,7 +2015,8 @@ static u64 atom_get_val(struct cpudata *cpudata, int 
pstate)
+       u32 vid;
+ 
+       val = (u64)pstate << 8;
+-      if (READ_ONCE(global.no_turbo) && !READ_ONCE(global.turbo_disabled))
++      if (READ_ONCE(global.no_turbo) && !READ_ONCE(global.turbo_disabled) &&
++          cpu_feature_enabled(X86_FEATURE_IDA))
+               val |= (u64)1 << 32;
+ 
+       vid_fp = cpudata->vid.min + mul_fp(
+@@ -2183,7 +2181,8 @@ static u64 core_get_val(struct cpudata *cpudata, int 
pstate)
+       u64 val;
+ 
+       val = (u64)pstate << 8;
+-      if (READ_ONCE(global.no_turbo) && !READ_ONCE(global.turbo_disabled))
++      if (READ_ONCE(global.no_turbo) && !READ_ONCE(global.turbo_disabled) &&
++          cpu_feature_enabled(X86_FEATURE_IDA))
+               val |= (u64)1 << 32;
+ 
+       return val;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+index 37d53578825b33..211d67a2e48dd9 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+@@ -2747,10 +2747,12 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void 
*data, struct drm_file *filp)
+       case AMDGPU_VM_OP_RESERVE_VMID:
+               /* We only have requirement to reserve vmid from gfxhub */
+               if (!fpriv->vm.reserved_vmid[AMDGPU_GFXHUB(0)]) {
+-                      amdgpu_vmid_alloc_reserved(adev, AMDGPU_GFXHUB(0));
++                      int r = amdgpu_vmid_alloc_reserved(adev, 
AMDGPU_GFXHUB(0));
++
++                      if (r)
++                              return r;
+                       fpriv->vm.reserved_vmid[AMDGPU_GFXHUB(0)] = true;
+               }
+-
+               break;
+       case AMDGPU_VM_OP_UNRESERVE_VMID:
+               if (fpriv->vm.reserved_vmid[AMDGPU_GFXHUB(0)]) {
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index 8659cb0bc7e6d3..e1816ae8699dd1 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -816,16 +816,11 @@ static void iommu_enable_command_buffer(struct amd_iommu 
*iommu)
+ 
+       BUG_ON(iommu->cmd_buf == NULL);
+ 
+-      if (!is_kdump_kernel()) {
+-              /*
+-               * Command buffer is re-used for kdump kernel and setting
+-               * of MMIO register is not required.
+-               */
+-              entry = iommu_virt_to_phys(iommu->cmd_buf);
+-              entry |= MMIO_CMD_SIZE_512;
+-              memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET,
+-                          &entry, sizeof(entry));
+-      }
++      entry = iommu_virt_to_phys(iommu->cmd_buf);
++      entry |= MMIO_CMD_SIZE_512;
++
++      memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET,
++                  &entry, sizeof(entry));
+ 
+       amd_iommu_reset_cmd_buffer(iommu);
+ }
+@@ -874,15 +869,10 @@ static void iommu_enable_event_buffer(struct amd_iommu 
*iommu)
+ 
+       BUG_ON(iommu->evt_buf == NULL);
+ 
+-      if (!is_kdump_kernel()) {
+-              /*
+-               * Event buffer is re-used for kdump kernel and setting
+-               * of MMIO register is not required.
+-               */
+-              entry = iommu_virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
+-              memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
+-                          &entry, sizeof(entry));
+-      }
++      entry = iommu_virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
++
++      memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
++                  &entry, sizeof(entry));
+ 
+       /* set head and tail to zero manually */
+       writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+diff --git a/drivers/net/phy/mediatek-ge-soc.c 
b/drivers/net/phy/mediatek-ge-soc.c
+index f4f9412d0cd7e2..4b2a9a5444c576 100644
+--- a/drivers/net/phy/mediatek-ge-soc.c
++++ b/drivers/net/phy/mediatek-ge-soc.c
+@@ -1082,9 +1082,9 @@ static int mt798x_phy_calibration(struct phy_device 
*phydev)
+       }
+ 
+       buf = (u32 *)nvmem_cell_read(cell, &len);
++      nvmem_cell_put(cell);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+-      nvmem_cell_put(cell);
+ 
+       if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) {
+               phydev_err(phydev, "invalid efuse data\n");
+diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
+index 4f231f8aae7d4c..778346039ded43 100644
+--- a/drivers/pwm/pwm-stm32.c
++++ b/drivers/pwm/pwm-stm32.c
+@@ -458,8 +458,7 @@ static int stm32_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
+               return 0;
+       }
+ 
+-      if (state->polarity != pwm->state.polarity)
+-              stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
++      stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
+ 
+       ret = stm32_pwm_config(priv, pwm->hwpwm,
+                              state->duty_cycle, state->period);
+diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
+index 3ff96ae31bf6de..c5fe3b2a53e827 100644
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -65,11 +65,9 @@ struct br_ip_list {
+ #define BR_DEFAULT_AGEING_TIME        (300 * HZ)
+ 
+ struct net_bridge;
+-void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br,
+-                           unsigned int cmd, struct ifreq *ifr,
++void brioctl_set(int (*hook)(struct net *net, unsigned int cmd,
+                            void __user *uarg));
+-int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
+-                struct ifreq *ifr, void __user *uarg);
++int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg);
+ 
+ #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
+ int br_multicast_list_adjacent(struct net_device *dev,
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 13b4bd7355c14c..20f9287d23a572 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -2238,13 +2238,13 @@ static inline int folio_expected_ref_count(const 
struct folio *folio)
+       const int order = folio_order(folio);
+       int ref_count = 0;
+ 
+-      if (WARN_ON_ONCE(folio_test_slab(folio)))
++      if (WARN_ON_ONCE(page_has_type(&folio->page) && 
!folio_test_hugetlb(folio)))
+               return 0;
+ 
+-      if (folio_test_anon(folio)) {
+-              /* One reference per page from the swapcache. */
+-              ref_count += folio_test_swapcache(folio) << order;
+-      } else if (!((unsigned long)folio->mapping & PAGE_MAPPING_FLAGS)) {
++      /* One reference per page from the swapcache. */
++      ref_count += folio_test_swapcache(folio) << order;
++
++      if (!folio_test_anon(folio)) {
+               /* One reference per page from the pagecache. */
+               ref_count += !!folio->mapping << order;
+               /* One reference from PG_private. */
+diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h
+index 4237daa5ac7a25..3cf27591fe905d 100644
+--- a/include/linux/sched/topology.h
++++ b/include/linux/sched/topology.h
+@@ -106,6 +106,9 @@ struct sched_domain {
+       unsigned int nr_balance_failed; /* initialise to 0 */
+ 
+       /* idle_balance() stats */
++      unsigned int newidle_call;
++      unsigned int newidle_success;
++      unsigned int newidle_ratio;
+       u64 max_newidle_lb_cost;
+       unsigned long last_decay_max_lb_cost;
+ 
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index 4b1953b6c76ab4..b1895b330ff0a3 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -118,6 +118,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp);
+ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp);
+ 
+ DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
++DEFINE_PER_CPU(struct rnd_state, sched_rnd_state);
+ 
+ #ifdef CONFIG_SCHED_DEBUG
+ /*
+@@ -8335,6 +8336,8 @@ void __init sched_init_smp(void)
+ {
+       sched_init_numa(NUMA_NO_NODE);
+ 
++      prandom_init_once(&sched_rnd_state);
++
+       /*
+        * There's no userspace yet to cause hotplug operations; hence all the
+        * CPU masks are stable and all blatant races in the below code cannot
+diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
+index 22dc54aab8dd63..1436d6bb86ec44 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -12186,24 +12186,43 @@ void update_max_interval(void)
+       max_load_balance_interval = HZ*num_online_cpus()/10;
+ }
+ 
+-static inline bool update_newidle_cost(struct sched_domain *sd, u64 cost)
++static inline void update_newidle_stats(struct sched_domain *sd, unsigned int 
success)
+ {
++      sd->newidle_call++;
++      sd->newidle_success += success;
++
++      if (sd->newidle_call >= 1024) {
++              sd->newidle_ratio = sd->newidle_success;
++              sd->newidle_call /= 2;
++              sd->newidle_success /= 2;
++      }
++}
++
++static inline bool
++update_newidle_cost(struct sched_domain *sd, u64 cost, unsigned int success)
++{
++      unsigned long next_decay = sd->last_decay_max_lb_cost + HZ;
++      unsigned long now = jiffies;
++
++      if (cost)
++              update_newidle_stats(sd, success);
++
+       if (cost > sd->max_newidle_lb_cost) {
+               /*
+                * Track max cost of a domain to make sure to not delay the
+                * next wakeup on the CPU.
+                */
+               sd->max_newidle_lb_cost = cost;
+-              sd->last_decay_max_lb_cost = jiffies;
+-      } else if (time_after(jiffies, sd->last_decay_max_lb_cost + HZ)) {
++              sd->last_decay_max_lb_cost = now;
++
++      } else if (time_after(now, next_decay)) {
+               /*
+                * Decay the newidle max times by ~1% per second to ensure that
+                * it is not outdated and the current max cost is actually
+                * shorter.
+                */
+               sd->max_newidle_lb_cost = (sd->max_newidle_lb_cost * 253) / 256;
+-              sd->last_decay_max_lb_cost = jiffies;
+-
++              sd->last_decay_max_lb_cost = now;
+               return true;
+       }
+ 
+@@ -12235,7 +12254,7 @@ static void sched_balance_domains(struct rq *rq, enum 
cpu_idle_type idle)
+                * Decay the newidle max times here because this is a regular
+                * visit to all the domains.
+                */
+-              need_decay = update_newidle_cost(sd, 0);
++              need_decay = update_newidle_cost(sd, 0, 0);
+               max_cost += sd->max_newidle_lb_cost;
+ 
+               /*
+@@ -12864,14 +12883,16 @@ static int sched_balance_newidle(struct rq *this_rq, 
struct rq_flags *rf)
+ 
+       rcu_read_lock();
+       sd = rcu_dereference_check_sched_domain(this_rq->sd);
++      if (!sd) {
++              rcu_read_unlock();
++              goto out;
++      }
+ 
+       if (!get_rd_overloaded(this_rq->rd) ||
+-          (sd && this_rq->avg_idle < sd->max_newidle_lb_cost)) {
++          this_rq->avg_idle < sd->max_newidle_lb_cost) {
+ 
+-              if (sd)
+-                      update_next_balance(sd, &next_balance);
++              update_next_balance(sd, &next_balance);
+               rcu_read_unlock();
+-
+               goto out;
+       }
+       rcu_read_unlock();
+@@ -12891,6 +12912,22 @@ static int sched_balance_newidle(struct rq *this_rq, 
struct rq_flags *rf)
+                       break;
+ 
+               if (sd->flags & SD_BALANCE_NEWIDLE) {
++                      unsigned int weight = 1;
++
++                      if (sched_feat(NI_RANDOM)) {
++                              /*
++                               * Throw a 1k sided dice; and only run
++                               * newidle_balance according to the success
++                               * rate.
++                               */
++                              u32 d1k = sched_rng() % 1024;
++                              weight = 1 + sd->newidle_ratio;
++                              if (d1k > weight) {
++                                      update_newidle_stats(sd, 0);
++                                      continue;
++                              }
++                              weight = (1024 + weight/2) / weight;
++                      }
+ 
+                       pulled_task = sched_balance_rq(this_cpu, this_rq,
+                                                  sd, CPU_NEWLY_IDLE,
+@@ -12898,10 +12935,14 @@ static int sched_balance_newidle(struct rq *this_rq, 
struct rq_flags *rf)
+ 
+                       t1 = sched_clock_cpu(this_cpu);
+                       domain_cost = t1 - t0;
+-                      update_newidle_cost(sd, domain_cost);
+-
+                       curr_cost += domain_cost;
+                       t0 = t1;
++
++                      /*
++                       * Track max cost of a domain to make sure to not delay 
the
++                       * next wakeup on the CPU.
++                       */
++                      update_newidle_cost(sd, domain_cost, weight * 
!!pulled_task);
+               }
+ 
+               /*
+diff --git a/kernel/sched/features.h b/kernel/sched/features.h
+index 050d7503064e3a..da8ec0c23f25ff 100644
+--- a/kernel/sched/features.h
++++ b/kernel/sched/features.h
+@@ -122,3 +122,8 @@ SCHED_FEAT(WA_BIAS, true)
+ SCHED_FEAT(UTIL_EST, true)
+ 
+ SCHED_FEAT(LATENCY_WARN, false)
++
++/*
++ * Do newidle balancing proportional to its success rate using randomization.
++ */
++SCHED_FEAT(NI_RANDOM, true)
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index 6070331772ea71..62f90dcb10a18c 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -5,6 +5,7 @@
+ #ifndef _KERNEL_SCHED_SCHED_H
+ #define _KERNEL_SCHED_SCHED_H
+ 
++#include <linux/prandom.h>
+ #include <linux/sched/affinity.h>
+ #include <linux/sched/autogroup.h>
+ #include <linux/sched/cpufreq.h>
+@@ -1348,6 +1349,12 @@ static inline bool is_migration_disabled(struct 
task_struct *p)
+ }
+ 
+ DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
++DECLARE_PER_CPU(struct rnd_state, sched_rnd_state);
++
++static inline u32 sched_rng(void)
++{
++      return prandom_u32_state(this_cpu_ptr(&sched_rnd_state));
++}
+ 
+ #define cpu_rq(cpu)           (&per_cpu(runqueues, (cpu)))
+ #define this_rq()             this_cpu_ptr(&runqueues)
+diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
+index 4bd825c24e2646..bd8b2b30157097 100644
+--- a/kernel/sched/topology.c
++++ b/kernel/sched/topology.c
+@@ -1632,6 +1632,12 @@ sd_init(struct sched_domain_topology_level *tl,
+ 
+               .last_balance           = jiffies,
+               .balance_interval       = sd_weight,
++
++              /* 50% success rate */
++              .newidle_call           = 512,
++              .newidle_success        = 256,
++              .newidle_ratio          = 512,
++
+               .max_newidle_lb_cost    = 0,
+               .last_decay_max_lb_cost = jiffies,
+               .child                  = child,
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index 765c890e6a843a..9d43bd47da263c 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -744,6 +744,17 @@ buddy_merge_likely(unsigned long pfn, unsigned long 
buddy_pfn,
+                       NULL) != NULL;
+ }
+ 
++static void change_pageblock_range(struct page *pageblock_page,
++                                 int start_order, int migratetype)
++{
++      int nr_pageblocks = 1 << (start_order - pageblock_order);
++
++      while (nr_pageblocks--) {
++              set_pageblock_migratetype(pageblock_page, migratetype);
++              pageblock_page += pageblock_nr_pages;
++      }
++}
++
+ /*
+  * Freeing function for a buddy system allocator.
+  *
+@@ -830,7 +841,7 @@ static inline void __free_one_page(struct page *page,
+                        * expand() down the line puts the sub-blocks
+                        * on the right freelists.
+                        */
+-                      set_pageblock_migratetype(buddy, migratetype);
++                      change_pageblock_range(buddy, order, migratetype);
+               }
+ 
+               combined_pfn = buddy_pfn & pfn;
+@@ -1817,17 +1828,6 @@ move:
+ }
+ #endif /* CONFIG_MEMORY_ISOLATION */
+ 
+-static void change_pageblock_range(struct page *pageblock_page,
+-                                      int start_order, int migratetype)
+-{
+-      int nr_pageblocks = 1 << (start_order - pageblock_order);
+-
+-      while (nr_pageblocks--) {
+-              set_pageblock_migratetype(pageblock_page, migratetype);
+-              pageblock_page += pageblock_nr_pages;
+-      }
+-}
+-
+ /*
+  * When we are falling back to another migratetype during allocation, try to
+  * steal extra free pages from the same pageblocks to satisfy further
+diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
+index f213ed10836185..6bc0a11f2ed3e6 100644
+--- a/net/bridge/br_ioctl.c
++++ b/net/bridge/br_ioctl.c
+@@ -394,10 +394,26 @@ static int old_deviceless(struct net *net, void __user 
*data)
+       return -EOPNOTSUPP;
+ }
+ 
+-int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd,
+-                struct ifreq *ifr, void __user *uarg)
++int br_ioctl_stub(struct net *net, unsigned int cmd, void __user *uarg)
+ {
+       int ret = -EOPNOTSUPP;
++      struct ifreq ifr;
++
++      if (cmd == SIOCBRADDIF || cmd == SIOCBRDELIF) {
++              void __user *data;
++              char *colon;
++
++              if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
++                      return -EPERM;
++
++              if (get_user_ifreq(&ifr, &data, uarg))
++                      return -EFAULT;
++
++              ifr.ifr_name[IFNAMSIZ - 1] = 0;
++              colon = strchr(ifr.ifr_name, ':');
++              if (colon)
++                      *colon = 0;
++      }
+ 
+       rtnl_lock();
+ 
+@@ -430,7 +446,21 @@ int br_ioctl_stub(struct net *net, struct net_bridge *br, 
unsigned int cmd,
+               break;
+       case SIOCBRADDIF:
+       case SIOCBRDELIF:
+-              ret = add_del_if(br, ifr->ifr_ifindex, cmd == SIOCBRADDIF);
++      {
++              struct net_device *dev;
++
++              dev = __dev_get_by_name(net, ifr.ifr_name);
++              if (!dev || !netif_device_present(dev)) {
++                      ret = -ENODEV;
++                      break;
++              }
++              if (!netif_is_bridge_master(dev)) {
++                      ret = -EOPNOTSUPP;
++                      break;
++              }
++
++              ret = add_del_if(netdev_priv(dev), ifr.ifr_ifindex, cmd == 
SIOCBRADDIF);
++      }
+               break;
+       }
+ 
+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
+index a2e59108a5dc8a..b2e4e2d04f02b8 100644
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -953,8 +953,7 @@ br_port_get_check_rtnl(const struct net_device *dev)
+ /* br_ioctl.c */
+ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
+                         void __user *data, int cmd);
+-int br_ioctl_stub(struct net *net, struct net_bridge *br, unsigned int cmd,
+-                struct ifreq *ifr, void __user *uarg);
++int br_ioctl_stub(struct net *net, unsigned int cmd, void __user *uarg);
+ 
+ /* br_multicast.c */
+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
+index 473c437b6b5386..81cd8df798c0a0 100644
+--- a/net/core/dev_ioctl.c
++++ b/net/core/dev_ioctl.c
+@@ -514,7 +514,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, 
void __user *data,
+       int err;
+       struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
+       const struct net_device_ops *ops;
+-      netdevice_tracker dev_tracker;
+ 
+       if (!dev)
+               return -ENODEV;
+@@ -577,19 +576,6 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, 
void __user *data,
+       case SIOCWANDEV:
+               return dev_siocwandev(dev, &ifr->ifr_settings);
+ 
+-      case SIOCBRADDIF:
+-      case SIOCBRDELIF:
+-              if (!netif_device_present(dev))
+-                      return -ENODEV;
+-              if (!netif_is_bridge_master(dev))
+-                      return -EOPNOTSUPP;
+-              netdev_hold(dev, &dev_tracker, GFP_KERNEL);
+-              rtnl_unlock();
+-              err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
+-              netdev_put(dev, &dev_tracker);
+-              rtnl_lock();
+-              return err;
+-
+       case SIOCDEVPRIVATE ... SIOCDEVPRIVATE + 15:
+               return dev_siocdevprivate(dev, ifr, data, cmd);
+ 
+@@ -770,8 +756,6 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct 
ifreq *ifr,
+       case SIOCBONDRELEASE:
+       case SIOCBONDSETHWADDR:
+       case SIOCBONDCHANGEACTIVE:
+-      case SIOCBRADDIF:
+-      case SIOCBRDELIF:
+       case SIOCSHWTSTAMP:
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+                       return -EPERM;
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index ea6fe21c96c555..e4a3ce716f6b54 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -3426,6 +3426,11 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+           rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
+               return RX_DROP_U_RUNT_ACTION;
+ 
++      /* Drop non-broadcast Beacon frames */
++      if (ieee80211_is_beacon(mgmt->frame_control) &&
++          !is_broadcast_ether_addr(mgmt->da))
++              return RX_DROP_MONITOR;
++
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+           ieee80211_is_beacon(mgmt->frame_control) &&
+           !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+diff --git a/net/mptcp/options.c b/net/mptcp/options.c
+index bc089388530b8f..b9c8205fadbf13 100644
+--- a/net/mptcp/options.c
++++ b/net/mptcp/options.c
+@@ -408,6 +408,16 @@ bool mptcp_syn_options(struct sock *sk, const struct 
sk_buff *skb,
+        */
+       subflow->snd_isn = TCP_SKB_CB(skb)->end_seq;
+       if (subflow->request_mptcp) {
++              if (unlikely(subflow_simultaneous_connect(sk))) {
++                      WARN_ON_ONCE(!mptcp_try_fallback(sk));
++
++                      /* Ensure mptcp_finish_connect() will not process the
++                       * MPC handshake.
++                       */
++                      subflow->request_mptcp = 0;
++                      return false;
++              }
++
+               opts->suboptions = OPTION_MPTCP_MPC_SYN;
+               opts->csum_reqd = mptcp_is_checksum_enabled(sock_net(sk));
+               opts->allow_join_id0 = mptcp_allow_join_id0(sock_net(sk));
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index aab3c96ecd1c3d..790feade9bf2bf 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -2478,10 +2478,10 @@ bool __mptcp_retransmit_pending_data(struct sock *sk)
+  */
+ static void __mptcp_subflow_disconnect(struct sock *ssk,
+                                      struct mptcp_subflow_context *subflow,
+-                                     unsigned int flags)
++                                     bool fastclosing)
+ {
+       if (((1 << ssk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
+-          subflow->send_fastclose) {
++          fastclosing) {
+               /* The MPTCP code never wait on the subflow sockets, TCP-level
+                * disconnect should never fail
+                */
+@@ -2533,7 +2533,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct 
sock *ssk,
+ 
+       need_push = (flags & MPTCP_CF_PUSH) && 
__mptcp_retransmit_pending_data(sk);
+       if (!dispose_it) {
+-              __mptcp_subflow_disconnect(ssk, subflow, flags);
++              __mptcp_subflow_disconnect(ssk, subflow, msk->fastclosing);
+               release_sock(ssk);
+ 
+               goto out;
+@@ -2845,6 +2845,7 @@ static void mptcp_do_fastclose(struct sock *sk)
+       struct mptcp_sock *msk = mptcp_sk(sk);
+ 
+       mptcp_set_state(sk, TCP_CLOSE);
++      msk->fastclosing = 1;
+ 
+       /* Explicitly send the fastclose reset as need */
+       if (__mptcp_check_fallback(msk))
+@@ -3362,6 +3363,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
+       msk->bytes_sent = 0;
+       msk->bytes_retrans = 0;
+       msk->rcvspace_init = 0;
++      msk->fastclosing = 0;
+ 
+       WRITE_ONCE(sk->sk_shutdown, 0);
+       sk_error_report(sk);
+diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
+index 73b8423506779d..bdec5ad9defb98 100644
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -316,7 +316,8 @@ struct mptcp_sock {
+                       fastopening:1,
+                       in_accept_queue:1,
+                       free_first:1,
+-                      rcvspace_init:1;
++                      rcvspace_init:1,
++                      fastclosing:1;
+       u32             notsent_lowat;
+       int             keepalive_cnt;
+       int             keepalive_idle;
+@@ -1283,10 +1284,8 @@ static inline bool subflow_simultaneous_connect(struct 
sock *sk)
+ {
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+ 
+-      return (1 << sk->sk_state) &
+-             (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | 
TCPF_CLOSING) &&
+-             is_active_ssk(subflow) &&
+-             !subflow->conn_finished;
++      /* Note that the sk state implies !subflow->conn_finished. */
++      return sk->sk_state == TCP_SYN_RECV && is_active_ssk(subflow);
+ }
+ 
+ #ifdef CONFIG_SYN_COOKIES
+diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
+index e3d4ed49e5885c..1618483b05e8ab 100644
+--- a/net/mptcp/subflow.c
++++ b/net/mptcp/subflow.c
+@@ -1848,18 +1848,10 @@ static void subflow_state_change(struct sock *sk)
+ {
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+       struct sock *parent = subflow->conn;
+-      struct mptcp_sock *msk;
++      struct mptcp_sock *msk = mptcp_sk(parent);
+ 
+       __subflow_state_change(sk);
+ 
+-      msk = mptcp_sk(parent);
+-      if (subflow_simultaneous_connect(sk)) {
+-              WARN_ON_ONCE(!mptcp_try_fallback(sk));
+-              pr_fallback(msk);
+-              subflow->conn_finished = 1;
+-              mptcp_propagate_state(parent, sk, subflow, NULL);
+-      }
+-
+       /* as recvmsg() does not acquire the subflow socket for ssk selection
+        * a fin packet carrying a DSS can be unnoticed if we don't trigger
+        * the data available machinery here.
+diff --git a/net/socket.c b/net/socket.c
+index 042451f01c6520..a0f6f8b3376d5d 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -1173,12 +1173,10 @@ static ssize_t sock_write_iter(struct kiocb *iocb, 
struct iov_iter *from)
+  */
+ 
+ static DEFINE_MUTEX(br_ioctl_mutex);
+-static int (*br_ioctl_hook)(struct net *net, struct net_bridge *br,
+-                          unsigned int cmd, struct ifreq *ifr,
++static int (*br_ioctl_hook)(struct net *net, unsigned int cmd,
+                           void __user *uarg);
+ 
+-void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br,
+-                           unsigned int cmd, struct ifreq *ifr,
++void brioctl_set(int (*hook)(struct net *net, unsigned int cmd,
+                            void __user *uarg))
+ {
+       mutex_lock(&br_ioctl_mutex);
+@@ -1187,8 +1185,7 @@ void brioctl_set(int (*hook)(struct net *net, struct 
net_bridge *br,
+ }
+ EXPORT_SYMBOL(brioctl_set);
+ 
+-int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
+-                struct ifreq *ifr, void __user *uarg)
++int br_ioctl_call(struct net *net, unsigned int cmd, void __user *uarg)
+ {
+       int err = -ENOPKG;
+ 
+@@ -1197,7 +1194,7 @@ int br_ioctl_call(struct net *net, struct net_bridge 
*br, unsigned int cmd,
+ 
+       mutex_lock(&br_ioctl_mutex);
+       if (br_ioctl_hook)
+-              err = br_ioctl_hook(net, br, cmd, ifr, uarg);
++              err = br_ioctl_hook(net, cmd, uarg);
+       mutex_unlock(&br_ioctl_mutex);
+ 
+       return err;
+@@ -1297,7 +1294,9 @@ static long sock_ioctl(struct file *file, unsigned cmd, 
unsigned long arg)
+               case SIOCSIFBR:
+               case SIOCBRADDBR:
+               case SIOCBRDELBR:
+-                      err = br_ioctl_call(net, NULL, cmd, NULL, argp);
++              case SIOCBRADDIF:
++              case SIOCBRDELIF:
++                      err = br_ioctl_call(net, cmd, argp);
+                       break;
+               case SIOCGIFVLAN:
+               case SIOCSIFVLAN:
+@@ -3466,6 +3465,8 @@ static int compat_sock_ioctl_trans(struct file *file, 
struct socket *sock,
+       case SIOCGPGRP:
+       case SIOCBRADDBR:
+       case SIOCBRDELBR:
++      case SIOCBRADDIF:
++      case SIOCBRDELIF:
+       case SIOCGIFVLAN:
+       case SIOCSIFVLAN:
+       case SIOCGSKNS:
+@@ -3505,8 +3506,6 @@ static int compat_sock_ioctl_trans(struct file *file, 
struct socket *sock,
+       case SIOCGIFPFLAGS:
+       case SIOCGIFTXQLEN:
+       case SIOCSIFTXQLEN:
+-      case SIOCBRADDIF:
+-      case SIOCBRDELIF:
+       case SIOCGIFNAME:
+       case SIOCSIFNAME:
+       case SIOCGMIIPHY:

Reply via email to