Merge dffe86df26 ("wifi: mt76: do not run mt76_unregister_device() on unregistered hw") into android14-6.1-lts

Steps on the way to 6.1.113

Change-Id: I0d5bfdc8d4e5fe6d4c6e82cb762ce3818286e411
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2024-11-10 12:35:15 +00:00
28 changed files with 426 additions and 148 deletions

View File

@@ -593,8 +593,7 @@ config PPC64_BIG_ENDIAN_ELF_ABI_V2
bool "Build big-endian kernel using ELF ABI V2 (EXPERIMENTAL)" bool "Build big-endian kernel using ELF ABI V2 (EXPERIMENTAL)"
depends on PPC64 && CPU_BIG_ENDIAN depends on PPC64 && CPU_BIG_ENDIAN
depends on CC_HAS_ELFV2 depends on CC_HAS_ELFV2
depends on LD_IS_BFD && LD_VERSION >= 22400 depends on LD_VERSION >= 22400 || LLD_VERSION >= 150000
default n
help help
This builds the kernel image using the "Power Architecture 64-Bit ELF This builds the kernel image using the "Power Architecture 64-Bit ELF
V2 ABI Specification", which has a reduced stack overhead and faster V2 ABI Specification", which has a reduced stack overhead and faster

View File

@@ -12,6 +12,7 @@
#include <asm/insn.h> #include <asm/insn.h>
#include <asm/insn-eval.h> #include <asm/insn-eval.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/traps.h>
/* TDX module Call Leaf IDs */ /* TDX module Call Leaf IDs */
#define TDX_GET_INFO 1 #define TDX_GET_INFO 1
@@ -371,6 +372,11 @@ static int handle_mmio(struct pt_regs *regs, struct ve_info *ve)
return -EINVAL; return -EINVAL;
} }
if (!fault_in_kernel_space(ve->gla)) {
WARN_ONCE(1, "Access to userspace address is not supported");
return -EINVAL;
}
/* /*
* Reject EPT violation #VEs that split pages. * Reject EPT violation #VEs that split pages.
* *

View File

@@ -62,7 +62,11 @@ extern u64 arch_irq_stat(void);
#if IS_ENABLED(CONFIG_KVM_INTEL) #if IS_ENABLED(CONFIG_KVM_INTEL)
static inline void kvm_set_cpu_l1tf_flush_l1d(void) /*
* This function is called from noinstr interrupt contexts
* and must be inlined to not get instrumentation.
*/
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
{ {
__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1); __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
} }
@@ -77,7 +81,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d); return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
} }
#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */ #else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
static inline void kvm_set_cpu_l1tf_flush_l1d(void) { } static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */ #endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
#endif /* _ASM_X86_HARDIRQ_H */ #endif /* _ASM_X86_HARDIRQ_H */

View File

@@ -13,15 +13,18 @@
#include <asm/irq_stack.h> #include <asm/irq_stack.h>
typedef void (*idtentry_t)(struct pt_regs *regs);
/** /**
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points * DECLARE_IDTENTRY - Declare functions for simple IDT entry points
* No error code pushed by hardware * No error code pushed by hardware
* @vector: Vector number (ignored for C) * @vector: Vector number (ignored for C)
* @func: Function name of the entry point * @func: Function name of the entry point
* *
* Declares three functions: * Declares four functions:
* - The ASM entry point: asm_##func * - The ASM entry point: asm_##func
* - The XEN PV trap entry point: xen_##func (maybe unused) * - The XEN PV trap entry point: xen_##func (maybe unused)
* - The C handler called from the FRED event dispatcher (maybe unused)
* - The C handler called from the ASM entry point * - The C handler called from the ASM entry point
* *
* Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it * Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it
@@ -31,6 +34,7 @@
#define DECLARE_IDTENTRY(vector, func) \ #define DECLARE_IDTENTRY(vector, func) \
asmlinkage void asm_##func(void); \ asmlinkage void asm_##func(void); \
asmlinkage void xen_asm_##func(void); \ asmlinkage void xen_asm_##func(void); \
void fred_##func(struct pt_regs *regs); \
__visible void func(struct pt_regs *regs) __visible void func(struct pt_regs *regs)
/** /**
@@ -137,6 +141,17 @@ static __always_inline void __##func(struct pt_regs *regs, \
#define DEFINE_IDTENTRY_RAW(func) \ #define DEFINE_IDTENTRY_RAW(func) \
__visible noinstr void func(struct pt_regs *regs) __visible noinstr void func(struct pt_regs *regs)
/**
* DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points
* @func: Function name of the entry point
*
* @func is called from the FRED event dispatcher with interrupts disabled.
*
* See @DEFINE_IDTENTRY_RAW for further details.
*/
#define DEFINE_FREDENTRY_RAW(func) \
noinstr void fred_##func(struct pt_regs *regs)
/** /**
* DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points
* Error code pushed by hardware * Error code pushed by hardware
@@ -197,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
u32 vector = (u32)(u8)error_code; \ u32 vector = (u32)(u8)error_code; \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
kvm_set_cpu_l1tf_flush_l1d(); \
run_irq_on_irqstack_cond(__##func, regs, vector); \ run_irq_on_irqstack_cond(__##func, regs, vector); \
instrumentation_end(); \ instrumentation_end(); \
irqentry_exit(regs, state); \ irqentry_exit(regs, state); \
@@ -233,17 +248,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector)
#define DEFINE_IDTENTRY_SYSVEC(func) \ #define DEFINE_IDTENTRY_SYSVEC(func) \
static void __##func(struct pt_regs *regs); \ static void __##func(struct pt_regs *regs); \
\ \
static __always_inline void instr_##func(struct pt_regs *regs) \
{ \
run_sysvec_on_irqstack_cond(__##func, regs); \
} \
\
__visible noinstr void func(struct pt_regs *regs) \ __visible noinstr void func(struct pt_regs *regs) \
{ \ { \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
kvm_set_cpu_l1tf_flush_l1d(); \ instr_##func (regs); \
run_sysvec_on_irqstack_cond(__##func, regs); \
instrumentation_end(); \ instrumentation_end(); \
irqentry_exit(regs, state); \ irqentry_exit(regs, state); \
} \ } \
\ \
void fred_##func(struct pt_regs *regs) \
{ \
instr_##func (regs); \
} \
\
static noinline void __##func(struct pt_regs *regs) static noinline void __##func(struct pt_regs *regs)
/** /**
@@ -260,19 +285,29 @@ static noinline void __##func(struct pt_regs *regs)
#define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func) \ #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func) \
static __always_inline void __##func(struct pt_regs *regs); \ static __always_inline void __##func(struct pt_regs *regs); \
\ \
static __always_inline void instr_##func(struct pt_regs *regs) \
{ \
__irq_enter_raw(); \
__##func (regs); \
__irq_exit_raw(); \
} \
\
__visible noinstr void func(struct pt_regs *regs) \ __visible noinstr void func(struct pt_regs *regs) \
{ \ { \
irqentry_state_t state = irqentry_enter(regs); \ irqentry_state_t state = irqentry_enter(regs); \
\ \
kvm_set_cpu_l1tf_flush_l1d(); \
instrumentation_begin(); \ instrumentation_begin(); \
__irq_enter_raw(); \ instr_##func (regs); \
kvm_set_cpu_l1tf_flush_l1d(); \
__##func (regs); \
__irq_exit_raw(); \
instrumentation_end(); \ instrumentation_end(); \
irqentry_exit(regs, state); \ irqentry_exit(regs, state); \
} \ } \
\ \
void fred_##func(struct pt_regs *regs) \
{ \
instr_##func (regs); \
} \
\
static __always_inline void __##func(struct pt_regs *regs) static __always_inline void __##func(struct pt_regs *regs)
/** /**
@@ -410,15 +445,18 @@ __visible noinstr void func(struct pt_regs *regs, \
/* C-Code mapping */ /* C-Code mapping */
#define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW #define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW
#define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW #define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW
#define DEFINE_FREDENTRY_NMI DEFINE_FREDENTRY_RAW
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
#define DECLARE_IDTENTRY_MCE DECLARE_IDTENTRY_IST #define DECLARE_IDTENTRY_MCE DECLARE_IDTENTRY_IST
#define DEFINE_IDTENTRY_MCE DEFINE_IDTENTRY_IST #define DEFINE_IDTENTRY_MCE DEFINE_IDTENTRY_IST
#define DEFINE_IDTENTRY_MCE_USER DEFINE_IDTENTRY_NOIST #define DEFINE_IDTENTRY_MCE_USER DEFINE_IDTENTRY_NOIST
#define DEFINE_FREDENTRY_MCE DEFINE_FREDENTRY_RAW
#define DECLARE_IDTENTRY_DEBUG DECLARE_IDTENTRY_IST #define DECLARE_IDTENTRY_DEBUG DECLARE_IDTENTRY_IST
#define DEFINE_IDTENTRY_DEBUG DEFINE_IDTENTRY_IST #define DEFINE_IDTENTRY_DEBUG DEFINE_IDTENTRY_IST
#define DEFINE_IDTENTRY_DEBUG_USER DEFINE_IDTENTRY_NOIST #define DEFINE_IDTENTRY_DEBUG_USER DEFINE_IDTENTRY_NOIST
#define DEFINE_FREDENTRY_DEBUG DEFINE_FREDENTRY_RAW
#endif #endif
#else /* !__ASSEMBLY__ */ #else /* !__ASSEMBLY__ */
@@ -660,23 +698,36 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_MOVE_CLEANUP_VECTOR, sysvec_irq_move_cleanup);
DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR, sysvec_reboot); DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR, sysvec_reboot);
DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR, sysvec_call_function_single); DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR, sysvec_call_function_single);
DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR, sysvec_call_function); DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR, sysvec_call_function);
#else
# define fred_sysvec_reschedule_ipi NULL
# define fred_sysvec_reboot NULL
# define fred_sysvec_call_function_single NULL
# define fred_sysvec_call_function NULL
#endif #endif
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
# ifdef CONFIG_X86_MCE_THRESHOLD # ifdef CONFIG_X86_MCE_THRESHOLD
DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR, sysvec_threshold); DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR, sysvec_threshold);
# else
# define fred_sysvec_threshold NULL
# endif # endif
# ifdef CONFIG_X86_MCE_AMD # ifdef CONFIG_X86_MCE_AMD
DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR, sysvec_deferred_error); DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR, sysvec_deferred_error);
# else
# define fred_sysvec_deferred_error NULL
# endif # endif
# ifdef CONFIG_X86_THERMAL_VECTOR # ifdef CONFIG_X86_THERMAL_VECTOR
DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR, sysvec_thermal); DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR, sysvec_thermal);
# else
# define fred_sysvec_thermal NULL
# endif # endif
# ifdef CONFIG_IRQ_WORK # ifdef CONFIG_IRQ_WORK
DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work); DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work);
# else
# define fred_sysvec_irq_work NULL
# endif # endif
#endif #endif
@@ -684,12 +735,16 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work);
DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR, sysvec_kvm_posted_intr_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR, sysvec_kvm_posted_intr_ipi);
DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_ipi);
DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested_ipi);
#else
# define fred_sysvec_kvm_posted_intr_ipi NULL
# define fred_sysvec_kvm_posted_intr_wakeup_ipi NULL
# define fred_sysvec_kvm_posted_intr_nested_ipi NULL
#endif #endif
#if IS_ENABLED(CONFIG_HYPERV) #if IS_ENABLED(CONFIG_HYPERV)
DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback); DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback);
DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment); DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment);
DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0); DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0);
#endif #endif
#if IS_ENABLED(CONFIG_ACRN_GUEST) #if IS_ENABLED(CONFIG_ACRN_GUEST)

View File

@@ -170,6 +170,13 @@ struct aspeed_i2c_bus {
static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus); static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
{
bus->master_state = ASPEED_I2C_MASTER_STOP;
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
}
static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
{ {
unsigned long time_left, flags; unsigned long time_left, flags;
@@ -187,7 +194,7 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
command); command);
reinit_completion(&bus->cmd_complete); reinit_completion(&bus->cmd_complete);
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG); aspeed_i2c_do_stop(bus);
spin_unlock_irqrestore(&bus->lock, flags); spin_unlock_irqrestore(&bus->lock, flags);
time_left = wait_for_completion_timeout( time_left = wait_for_completion_timeout(
@@ -390,13 +397,6 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
writel(command, bus->base + ASPEED_I2C_CMD_REG); writel(command, bus->base + ASPEED_I2C_CMD_REG);
} }
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
{
bus->master_state = ASPEED_I2C_MASTER_STOP;
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
}
/* precondition: bus.lock has been acquired. */ /* precondition: bus.lock has been acquired. */
static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus)
{ {

View File

@@ -99,8 +99,7 @@ static int sch_transaction(void)
if (retries > MAX_RETRIES) { if (retries > MAX_RETRIES) {
dev_err(&sch_adapter.dev, "SMBus Timeout!\n"); dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT; result = -ETIMEDOUT;
} } else if (temp & 0x04) {
if (temp & 0x04) {
result = -EIO; result = -EIO;
dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be " dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
"locked until next hard reset. (sorry!)\n"); "locked until next hard reset. (sorry!)\n");

View File

@@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data)
/* Compatible Asahi Kasei Compass parts */ /* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset { enum asahi_compass_chipset {
AKXXXX = 0,
AK8975, AK8975,
AK8963, AK8963,
AK09911, AK09911,
@@ -248,7 +247,7 @@ struct ak_def {
}; };
static const struct ak_def ak_def_array[] = { static const struct ak_def ak_def_array[] = {
{ [AK8975] = {
.type = AK8975, .type = AK8975,
.raw_to_gauss = ak8975_raw_to_gauss, .raw_to_gauss = ak8975_raw_to_gauss,
.range = 4096, .range = 4096,
@@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL, AK8975_REG_HYL,
AK8975_REG_HZL}, AK8975_REG_HZL},
}, },
{ [AK8963] = {
.type = AK8963, .type = AK8963,
.raw_to_gauss = ak8963_09911_raw_to_gauss, .raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8190, .range = 8190,
@@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = {
AK8975_REG_HYL, AK8975_REG_HYL,
AK8975_REG_HZL}, AK8975_REG_HZL},
}, },
{ [AK09911] = {
.type = AK09911, .type = AK09911,
.raw_to_gauss = ak8963_09911_raw_to_gauss, .raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8192, .range = 8192,
@@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL, AK09912_REG_HYL,
AK09912_REG_HZL}, AK09912_REG_HZL},
}, },
{ [AK09912] = {
.type = AK09912, .type = AK09912,
.raw_to_gauss = ak09912_raw_to_gauss, .raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752, .range = 32752,
@@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = {
AK09912_REG_HYL, AK09912_REG_HYL,
AK09912_REG_HZL}, AK09912_REG_HZL},
}, },
{ [AK09916] = {
.type = AK09916, .type = AK09916,
.raw_to_gauss = ak09912_raw_to_gauss, .raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752, .range = 32752,

View File

@@ -522,6 +522,7 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht,
if (ret) if (ret)
return ret; return ret;
set_bit(MT76_STATE_REGISTERED, &phy->state);
phy->dev->phys[phy->band_idx] = phy; phy->dev->phys[phy->band_idx] = phy;
return 0; return 0;
@@ -532,6 +533,9 @@ void mt76_unregister_phy(struct mt76_phy *phy)
{ {
struct mt76_dev *dev = phy->dev; struct mt76_dev *dev = phy->dev;
if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
return;
mt76_tx_status_check(dev, true); mt76_tx_status_check(dev, true);
ieee80211_unregister_hw(phy->hw); ieee80211_unregister_hw(phy->hw);
dev->phys[phy->band_idx] = NULL; dev->phys[phy->band_idx] = NULL;
@@ -654,6 +658,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
return ret; return ret;
WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
set_bit(MT76_STATE_REGISTERED, &phy->state);
sched_set_fifo_low(dev->tx_worker.task); sched_set_fifo_low(dev->tx_worker.task);
return 0; return 0;
@@ -664,6 +669,9 @@ void mt76_unregister_device(struct mt76_dev *dev)
{ {
struct ieee80211_hw *hw = dev->hw; struct ieee80211_hw *hw = dev->hw;
if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
return;
if (IS_ENABLED(CONFIG_MT76_LEDS)) if (IS_ENABLED(CONFIG_MT76_LEDS))
mt76_led_cleanup(dev); mt76_led_cleanup(dev);
mt76_tx_status_check(dev, true); mt76_tx_status_check(dev, true);

View File

@@ -388,6 +388,7 @@ struct mt76_tx_cb {
enum { enum {
MT76_STATE_INITIALIZED, MT76_STATE_INITIALIZED,
MT76_STATE_REGISTERED,
MT76_STATE_RUNNING, MT76_STATE_RUNNING,
MT76_STATE_MCU_RUNNING, MT76_STATE_MCU_RUNNING,
MT76_SCANNING, MT76_SCANNING,

View File

@@ -579,7 +579,19 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev)
{ {
pci_bridge_wait_for_secondary_bus(pci_dev, "resume"); int ret;
ret = pci_bridge_wait_for_secondary_bus(pci_dev, "resume");
if (ret) {
/*
* The downstream link failed to come up, so mark the
* devices below as disconnected to make sure we don't
* attempt to resume them.
*/
pci_walk_bus(pci_dev->subordinate, pci_dev_set_disconnected,
NULL);
return;
}
/* /*
* When powering on a bridge from D3cold, the whole hierarchy may be * When powering on a bridge from D3cold, the whole hierarchy may be

View File

@@ -1671,7 +1671,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
idx = 0; idx = 0;
while (cmn->dtc[j].counters[idx]) while (cmn->dtc[j].counters[idx])
if (++idx == CMN_DT_NUM_COUNTERS) if (++idx == CMN_DT_NUM_COUNTERS)
goto free_dtms; return -ENOSPC;
} }
hw->dtc_idx[j] = idx; hw->dtc_idx[j] = idx;
} }

View File

@@ -148,7 +148,10 @@ static void parport_attach(struct parport *port)
return; return;
} }
index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL); index = ida_alloc(&pps_client_index, GFP_KERNEL);
if (index < 0)
goto err_free_device;
memset(&pps_client_cb, 0, sizeof(pps_client_cb)); memset(&pps_client_cb, 0, sizeof(pps_client_cb));
pps_client_cb.private = device; pps_client_cb.private = device;
pps_client_cb.irq_func = parport_irq; pps_client_cb.irq_func = parport_irq;
@@ -159,7 +162,7 @@ static void parport_attach(struct parport *port)
index); index);
if (!device->pardev) { if (!device->pardev) {
pr_err("couldn't register with %s\n", port->name); pr_err("couldn't register with %s\n", port->name);
goto err_free; goto err_free_ida;
} }
if (parport_claim_or_block(device->pardev) < 0) { if (parport_claim_or_block(device->pardev) < 0) {
@@ -187,8 +190,9 @@ err_release_dev:
parport_release(device->pardev); parport_release(device->pardev);
err_unregister_dev: err_unregister_dev:
parport_unregister_device(device->pardev); parport_unregister_device(device->pardev);
err_free: err_free_ida:
ida_simple_remove(&pps_client_index, index); ida_free(&pps_client_index, index);
err_free_device:
kfree(device); kfree(device);
} }
@@ -208,7 +212,7 @@ static void parport_detach(struct parport *port)
pps_unregister_source(device->pps); pps_unregister_source(device->pps);
parport_release(pardev); parport_release(pardev);
parport_unregister_device(pardev); parport_unregister_device(pardev);
ida_simple_remove(&pps_client_index, device->index); ida_free(&pps_client_index, device->index);
kfree(device); kfree(device);
} }

View File

@@ -413,8 +413,10 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
return -ENODEV; return -ENODEV;
} }
if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN)) if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN)) {
mutex_unlock(&dev->io_mutex);
return -EIO; return -EIO;
}
spin_lock_irq(&dev->lock); spin_lock_irq(&dev->lock);
scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu); scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);

View File

@@ -1530,6 +1530,7 @@ void xas_create_range(struct xa_state *);
#ifdef CONFIG_XARRAY_MULTI #ifdef CONFIG_XARRAY_MULTI
int xa_get_order(struct xarray *, unsigned long index); int xa_get_order(struct xarray *, unsigned long index);
int xas_get_order(struct xa_state *xas);
void xas_split(struct xa_state *, void *entry, unsigned int order); void xas_split(struct xa_state *, void *entry, unsigned int order);
void xas_split_alloc(struct xa_state *, void *entry, unsigned int order, gfp_t); void xas_split_alloc(struct xa_state *, void *entry, unsigned int order, gfp_t);
#else #else
@@ -1538,6 +1539,11 @@ static inline int xa_get_order(struct xarray *xa, unsigned long index)
return 0; return 0;
} }
static inline int xas_get_order(struct xa_state *xas)
{
return 0;
}
static inline void xas_split(struct xa_state *xas, void *entry, static inline void xas_split(struct xa_state *xas, void *entry,
unsigned int order) unsigned int order)
{ {

View File

@@ -772,6 +772,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
} }
bool icmp_global_allow(void); bool icmp_global_allow(void);
void icmp_global_consume(void);
extern int sysctl_icmp_msgs_per_sec; extern int sysctl_icmp_msgs_per_sec;
extern int sysctl_icmp_msgs_burst; extern int sysctl_icmp_msgs_burst;

View File

@@ -95,6 +95,8 @@ enum
ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */ ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */
ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */ ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */
ICMP_MIB_CSUMERRORS, /* InCsumErrors */ ICMP_MIB_CSUMERRORS, /* InCsumErrors */
ICMP_MIB_RATELIMITGLOBAL, /* OutRateLimitGlobal */
ICMP_MIB_RATELIMITHOST, /* OutRateLimitHost */
__ICMP_MIB_MAX __ICMP_MIB_MAX
}; };
@@ -112,6 +114,7 @@ enum
ICMP6_MIB_OUTMSGS, /* OutMsgs */ ICMP6_MIB_OUTMSGS, /* OutMsgs */
ICMP6_MIB_OUTERRORS, /* OutErrors */ ICMP6_MIB_OUTERRORS, /* OutErrors */
ICMP6_MIB_CSUMERRORS, /* InCsumErrors */ ICMP6_MIB_CSUMERRORS, /* InCsumErrors */
ICMP6_MIB_RATELIMITHOST, /* OutRateLimitHost */
__ICMP6_MIB_MAX __ICMP6_MIB_MAX
}; };

View File

@@ -6064,25 +6064,27 @@ static struct pending_free *get_pending_free(void)
static void free_zapped_rcu(struct rcu_head *cb); static void free_zapped_rcu(struct rcu_head *cb);
/* /*
* Schedule an RCU callback if no RCU callback is pending. Must be called with * See if we need to queue an RCU callback, must called with
* the graph lock held. * the lockdep lock held, returns false if either we don't have
*/ * any pending free or the callback is already scheduled.
static void call_rcu_zapped(struct pending_free *pf) * Otherwise, a call_rcu() must follow this function call.
*/
static bool prepare_call_rcu_zapped(struct pending_free *pf)
{ {
WARN_ON_ONCE(inside_selftest()); WARN_ON_ONCE(inside_selftest());
if (list_empty(&pf->zapped)) if (list_empty(&pf->zapped))
return; return false;
if (delayed_free.scheduled) if (delayed_free.scheduled)
return; return false;
delayed_free.scheduled = true; delayed_free.scheduled = true;
WARN_ON_ONCE(delayed_free.pf + delayed_free.index != pf); WARN_ON_ONCE(delayed_free.pf + delayed_free.index != pf);
delayed_free.index ^= 1; delayed_free.index ^= 1;
call_rcu(&delayed_free.rcu_head, free_zapped_rcu); return true;
} }
/* The caller must hold the graph lock. May be called from RCU context. */ /* The caller must hold the graph lock. May be called from RCU context. */
@@ -6108,6 +6110,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
{ {
struct pending_free *pf; struct pending_free *pf;
unsigned long flags; unsigned long flags;
bool need_callback;
if (WARN_ON_ONCE(ch != &delayed_free.rcu_head)) if (WARN_ON_ONCE(ch != &delayed_free.rcu_head))
return; return;
@@ -6119,14 +6122,18 @@ static void free_zapped_rcu(struct rcu_head *ch)
pf = delayed_free.pf + (delayed_free.index ^ 1); pf = delayed_free.pf + (delayed_free.index ^ 1);
__free_zapped_classes(pf); __free_zapped_classes(pf);
delayed_free.scheduled = false; delayed_free.scheduled = false;
need_callback =
/* prepare_call_rcu_zapped(delayed_free.pf + delayed_free.index);
* If there's anything on the open list, close and start a new callback.
*/
call_rcu_zapped(delayed_free.pf + delayed_free.index);
lockdep_unlock(); lockdep_unlock();
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
/*
* If there's pending free and its callback has not been scheduled,
* queue an RCU callback.
*/
if (need_callback)
call_rcu(&delayed_free.rcu_head, free_zapped_rcu);
} }
/* /*
@@ -6166,6 +6173,7 @@ static void lockdep_free_key_range_reg(void *start, unsigned long size)
{ {
struct pending_free *pf; struct pending_free *pf;
unsigned long flags; unsigned long flags;
bool need_callback;
init_data_structures_once(); init_data_structures_once();
@@ -6173,10 +6181,11 @@ static void lockdep_free_key_range_reg(void *start, unsigned long size)
lockdep_lock(); lockdep_lock();
pf = get_pending_free(); pf = get_pending_free();
__lockdep_free_key_range(pf, start, size); __lockdep_free_key_range(pf, start, size);
call_rcu_zapped(pf); need_callback = prepare_call_rcu_zapped(pf);
lockdep_unlock(); lockdep_unlock();
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
if (need_callback)
call_rcu(&delayed_free.rcu_head, free_zapped_rcu);
/* /*
* Wait for any possible iterators from look_up_lock_class() to pass * Wait for any possible iterators from look_up_lock_class() to pass
* before continuing to free the memory they refer to. * before continuing to free the memory they refer to.
@@ -6270,6 +6279,7 @@ static void lockdep_reset_lock_reg(struct lockdep_map *lock)
struct pending_free *pf; struct pending_free *pf;
unsigned long flags; unsigned long flags;
int locked; int locked;
bool need_callback = false;
raw_local_irq_save(flags); raw_local_irq_save(flags);
locked = graph_lock(); locked = graph_lock();
@@ -6278,11 +6288,13 @@ static void lockdep_reset_lock_reg(struct lockdep_map *lock)
pf = get_pending_free(); pf = get_pending_free();
__lockdep_reset_lock(pf, lock); __lockdep_reset_lock(pf, lock);
call_rcu_zapped(pf); need_callback = prepare_call_rcu_zapped(pf);
graph_unlock(); graph_unlock();
out_irq: out_irq:
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
if (need_callback)
call_rcu(&delayed_free.rcu_head, free_zapped_rcu);
} }
/* /*
@@ -6326,6 +6338,7 @@ void lockdep_unregister_key(struct lock_class_key *key)
struct pending_free *pf; struct pending_free *pf;
unsigned long flags; unsigned long flags;
bool found = false; bool found = false;
bool need_callback = false;
might_sleep(); might_sleep();
@@ -6346,11 +6359,14 @@ void lockdep_unregister_key(struct lock_class_key *key)
if (found) { if (found) {
pf = get_pending_free(); pf = get_pending_free();
__lockdep_free_key_range(pf, key, 1); __lockdep_free_key_range(pf, key, 1);
call_rcu_zapped(pf); need_callback = prepare_call_rcu_zapped(pf);
} }
lockdep_unlock(); lockdep_unlock();
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
if (need_callback)
call_rcu(&delayed_free.rcu_head, free_zapped_rcu);
/* Wait until is_dynamic_key() has finished accessing k->hash_entry. */ /* Wait until is_dynamic_key() has finished accessing k->hash_entry. */
synchronize_rcu(); synchronize_rcu();
} }

View File

@@ -5,7 +5,7 @@
# These are called from save_stack_trace() on slub debug path, # These are called from save_stack_trace() on slub debug path,
# and produce insane amounts of uninteresting coverage. # and produce insane amounts of uninteresting coverage.
KCOV_INSTRUMENT_module.o := n KCOV_INSTRUMENT_main.o := n
obj-y += main.o strict_rwx.o obj-y += main.o strict_rwx.o
obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o

View File

@@ -1756,6 +1756,97 @@ static noinline void check_get_order(struct xarray *xa)
} }
} }
static noinline void check_xas_get_order(struct xarray *xa)
{
XA_STATE(xas, xa, 0);
unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1;
unsigned int order;
unsigned long i, j;
for (order = 0; order < max_order; order++) {
for (i = 0; i < 10; i++) {
xas_set_order(&xas, i << order, order);
do {
xas_lock(&xas);
xas_store(&xas, xa_mk_value(i));
xas_unlock(&xas);
} while (xas_nomem(&xas, GFP_KERNEL));
for (j = i << order; j < (i + 1) << order; j++) {
xas_set_order(&xas, j, 0);
rcu_read_lock();
xas_load(&xas);
XA_BUG_ON(xa, xas_get_order(&xas) != order);
rcu_read_unlock();
}
xas_lock(&xas);
xas_set_order(&xas, i << order, order);
xas_store(&xas, NULL);
xas_unlock(&xas);
}
}
}
static noinline void check_xas_conflict_get_order(struct xarray *xa)
{
XA_STATE(xas, xa, 0);
void *entry;
int only_once;
unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1;
unsigned int order;
unsigned long i, j, k;
for (order = 0; order < max_order; order++) {
for (i = 0; i < 10; i++) {
xas_set_order(&xas, i << order, order);
do {
xas_lock(&xas);
xas_store(&xas, xa_mk_value(i));
xas_unlock(&xas);
} while (xas_nomem(&xas, GFP_KERNEL));
/*
* Ensure xas_get_order works with xas_for_each_conflict.
*/
j = i << order;
for (k = 0; k < order; k++) {
only_once = 0;
xas_set_order(&xas, j + (1 << k), k);
xas_lock(&xas);
xas_for_each_conflict(&xas, entry) {
XA_BUG_ON(xa, entry != xa_mk_value(i));
XA_BUG_ON(xa, xas_get_order(&xas) != order);
only_once++;
}
XA_BUG_ON(xa, only_once != 1);
xas_unlock(&xas);
}
if (order < max_order - 1) {
only_once = 0;
xas_set_order(&xas, (i & ~1UL) << order, order + 1);
xas_lock(&xas);
xas_for_each_conflict(&xas, entry) {
XA_BUG_ON(xa, entry != xa_mk_value(i));
XA_BUG_ON(xa, xas_get_order(&xas) != order);
only_once++;
}
XA_BUG_ON(xa, only_once != 1);
xas_unlock(&xas);
}
xas_set_order(&xas, i << order, order);
xas_lock(&xas);
xas_store(&xas, NULL);
xas_unlock(&xas);
}
}
}
static noinline void check_destroy(struct xarray *xa) static noinline void check_destroy(struct xarray *xa)
{ {
unsigned long index; unsigned long index;
@@ -1805,6 +1896,8 @@ static int xarray_checks(void)
check_reserve(&xa0); check_reserve(&xa0);
check_multi_store(&array); check_multi_store(&array);
check_get_order(&array); check_get_order(&array);
check_xas_get_order(&array);
check_xas_conflict_get_order(&array);
check_xa_alloc(); check_xa_alloc();
check_find(&array); check_find(&array);
check_find_entry(&array); check_find_entry(&array);

View File

@@ -1751,6 +1751,36 @@ unlock:
} }
EXPORT_SYMBOL(xa_store_range); EXPORT_SYMBOL(xa_store_range);
/**
* xas_get_order() - Get the order of an entry.
* @xas: XArray operation state.
*
* Called after xas_load, the xas should not be in an error state.
*
* Return: A number between 0 and 63 indicating the order of the entry.
*/
int xas_get_order(struct xa_state *xas)
{
int order = 0;
if (!xas->xa_node)
return 0;
for (;;) {
unsigned int slot = xas->xa_offset + (1 << order);
if (slot >= XA_CHUNK_SIZE)
break;
if (!xa_is_sibling(xa_entry(xas->xa, xas->xa_node, slot)))
break;
order++;
}
order += xas->xa_node->shift;
return order;
}
EXPORT_SYMBOL_GPL(xas_get_order);
/** /**
* xa_get_order() - Get the order of an entry. * xa_get_order() - Get the order of an entry.
* @xa: XArray. * @xa: XArray.
@@ -1761,30 +1791,13 @@ EXPORT_SYMBOL(xa_store_range);
int xa_get_order(struct xarray *xa, unsigned long index) int xa_get_order(struct xarray *xa, unsigned long index)
{ {
XA_STATE(xas, xa, index); XA_STATE(xas, xa, index);
void *entry;
int order = 0; int order = 0;
void *entry;
rcu_read_lock(); rcu_read_lock();
entry = xas_load(&xas); entry = xas_load(&xas);
if (entry)
if (!entry) order = xas_get_order(&xas);
goto unlock;
if (!xas.xa_node)
goto unlock;
for (;;) {
unsigned int slot = xas.xa_offset + (1 << order);
if (slot >= XA_CHUNK_SIZE)
break;
if (!xa_is_sibling(xas.xa_node->slots[slot]))
break;
order++;
}
order += xas.xa_node->shift;
unlock:
rcu_read_unlock(); rcu_read_unlock();
return order; return order;

View File

@@ -126,6 +126,7 @@ static int __damon_va_three_regions(struct mm_struct *mm,
* If this is too slow, it can be optimised to examine the maple * If this is too slow, it can be optimised to examine the maple
* tree gaps. * tree gaps.
*/ */
rcu_read_lock();
for_each_vma(vmi, vma) { for_each_vma(vmi, vma) {
unsigned long gap; unsigned long gap;
@@ -146,6 +147,7 @@ static int __damon_va_three_regions(struct mm_struct *mm,
next: next:
prev = vma; prev = vma;
} }
rcu_read_unlock();
if (!sz_range(&second_gap) || !sz_range(&first_gap)) if (!sz_range(&second_gap) || !sz_range(&first_gap))
return -EINVAL; return -EINVAL;

View File

@@ -861,6 +861,8 @@ noinline int __filemap_add_folio(struct address_space *mapping,
{ {
XA_STATE(xas, &mapping->i_pages, index); XA_STATE(xas, &mapping->i_pages, index);
int huge = folio_test_hugetlb(folio); int huge = folio_test_hugetlb(folio);
void *alloced_shadow = NULL;
int alloced_order = 0;
bool charged = false; bool charged = false;
long nr = 1; long nr = 1;
@@ -883,13 +885,10 @@ noinline int __filemap_add_folio(struct address_space *mapping,
folio->mapping = mapping; folio->mapping = mapping;
folio->index = xas.xa_index; folio->index = xas.xa_index;
do { for (;;) {
unsigned int order = xa_get_order(xas.xa, xas.xa_index); int order = -1, split_order = 0;
void *entry, *old = NULL; void *entry, *old = NULL;
if (order > folio_order(folio))
xas_split_alloc(&xas, xa_load(xas.xa, xas.xa_index),
order, gfp);
xas_lock_irq(&xas); xas_lock_irq(&xas);
xas_for_each_conflict(&xas, entry) { xas_for_each_conflict(&xas, entry) {
old = entry; old = entry;
@@ -897,19 +896,33 @@ noinline int __filemap_add_folio(struct address_space *mapping,
xas_set_err(&xas, -EEXIST); xas_set_err(&xas, -EEXIST);
goto unlock; goto unlock;
} }
/*
* If a larger entry exists,
* it will be the first and only entry iterated.
*/
if (order == -1)
order = xas_get_order(&xas);
}
/* entry may have changed before we re-acquire the lock */
if (alloced_order && (old != alloced_shadow || order != alloced_order)) {
xas_destroy(&xas);
alloced_order = 0;
} }
if (old) { if (old) {
if (shadowp) if (order > 0 && order > folio_order(folio)) {
*shadowp = old;
/* entry may have been split before we acquired lock */
order = xa_get_order(xas.xa, xas.xa_index);
if (order > folio_order(folio)) {
/* How to handle large swap entries? */ /* How to handle large swap entries? */
BUG_ON(shmem_mapping(mapping)); BUG_ON(shmem_mapping(mapping));
if (!alloced_order) {
split_order = order;
goto unlock;
}
xas_split(&xas, old, order); xas_split(&xas, old, order);
xas_reset(&xas); xas_reset(&xas);
} }
if (shadowp)
*shadowp = old;
} }
xas_store(&xas, folio); xas_store(&xas, folio);
@@ -925,9 +938,24 @@ noinline int __filemap_add_folio(struct address_space *mapping,
__lruvec_stat_mod_folio(folio, __lruvec_stat_mod_folio(folio,
NR_FILE_THPS, nr); NR_FILE_THPS, nr);
} }
unlock: unlock:
xas_unlock_irq(&xas); xas_unlock_irq(&xas);
} while (xas_nomem(&xas, gfp));
/* split needed, alloc here and retry. */
if (split_order) {
xas_split_alloc(&xas, old, split_order, gfp);
if (xas_error(&xas))
goto error;
alloced_shadow = old;
alloced_order = split_order;
xas_reset(&xas);
continue;
}
if (!xas_nomem(&xas, gfp))
break;
}
if (xas_error(&xas)) if (xas_error(&xas))
goto error; goto error;

View File

@@ -404,7 +404,7 @@ static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
if (gap + pad > gap) if (gap + pad > gap)
gap += pad; gap += pad;
if (gap < MIN_GAP) if (gap < MIN_GAP && MIN_GAP < MAX_GAP)
gap = MIN_GAP; gap = MIN_GAP;
else if (gap > MAX_GAP) else if (gap > MAX_GAP)
gap = MAX_GAP; gap = MAX_GAP;

View File

@@ -222,57 +222,59 @@ int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
int sysctl_icmp_msgs_burst __read_mostly = 50; int sysctl_icmp_msgs_burst __read_mostly = 50;
static struct { static struct {
spinlock_t lock; atomic_t credit;
u32 credit;
u32 stamp; u32 stamp;
} icmp_global = { } icmp_global;
.lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock),
};
/** /**
* icmp_global_allow - Are we allowed to send one more ICMP message ? * icmp_global_allow - Are we allowed to send one more ICMP message ?
* *
* Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec. * Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec.
* Returns false if we reached the limit and can not send another packet. * Returns false if we reached the limit and can not send another packet.
* Note: called with BH disabled * Works in tandem with icmp_global_consume().
*/ */
bool icmp_global_allow(void) bool icmp_global_allow(void)
{ {
u32 credit, delta, incr = 0, now = (u32)jiffies; u32 delta, now, oldstamp;
bool rc = false; int incr, new, old;
/* Check if token bucket is empty and cannot be refilled /* Note: many cpus could find this condition true.
* without taking the spinlock. The READ_ONCE() are paired * Then later icmp_global_consume() could consume more credits,
* with the following WRITE_ONCE() in this same function. * this is an acceptable race.
*/ */
if (!READ_ONCE(icmp_global.credit)) { if (atomic_read(&icmp_global.credit) > 0)
delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ); return true;
if (delta < HZ / 50)
return false;
}
spin_lock(&icmp_global.lock); now = jiffies;
delta = min_t(u32, now - icmp_global.stamp, HZ); oldstamp = READ_ONCE(icmp_global.stamp);
if (delta >= HZ / 50) { delta = min_t(u32, now - oldstamp, HZ);
incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ; if (delta < HZ / 50)
if (incr) return false;
WRITE_ONCE(icmp_global.stamp, now);
incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
if (!incr)
return false;
if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) {
old = atomic_read(&icmp_global.credit);
do {
new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst));
} while (!atomic_try_cmpxchg(&icmp_global.credit, &old, new));
} }
credit = min_t(u32, icmp_global.credit + incr, return true;
READ_ONCE(sysctl_icmp_msgs_burst));
if (credit) {
/* We want to use a credit of one in average, but need to randomize
* it for security reasons.
*/
credit = max_t(int, credit - prandom_u32_max(3), 0);
rc = true;
}
WRITE_ONCE(icmp_global.credit, credit);
spin_unlock(&icmp_global.lock);
return rc;
} }
EXPORT_SYMBOL(icmp_global_allow); EXPORT_SYMBOL(icmp_global_allow);
void icmp_global_consume(void)
{
int credits = get_random_u32_below(3);
/* Note: this might make icmp_global.credit negative. */
if (credits)
atomic_sub(credits, &icmp_global.credit);
}
EXPORT_SYMBOL(icmp_global_consume);
static bool icmpv4_mask_allow(struct net *net, int type, int code) static bool icmpv4_mask_allow(struct net *net, int type, int code)
{ {
if (type > NR_ICMP_TYPES) if (type > NR_ICMP_TYPES)
@@ -289,14 +291,17 @@ static bool icmpv4_mask_allow(struct net *net, int type, int code)
return false; return false;
} }
static bool icmpv4_global_allow(struct net *net, int type, int code) static bool icmpv4_global_allow(struct net *net, int type, int code,
bool *apply_ratelimit)
{ {
if (icmpv4_mask_allow(net, type, code)) if (icmpv4_mask_allow(net, type, code))
return true; return true;
if (icmp_global_allow()) if (icmp_global_allow()) {
*apply_ratelimit = true;
return true; return true;
}
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
return false; return false;
} }
@@ -305,15 +310,16 @@ static bool icmpv4_global_allow(struct net *net, int type, int code)
*/ */
static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
struct flowi4 *fl4, int type, int code) struct flowi4 *fl4, int type, int code,
bool apply_ratelimit)
{ {
struct dst_entry *dst = &rt->dst; struct dst_entry *dst = &rt->dst;
struct inet_peer *peer; struct inet_peer *peer;
bool rc = true; bool rc = true;
int vif; int vif;
if (icmpv4_mask_allow(net, type, code)) if (!apply_ratelimit)
goto out; return true;
/* No rate limit on loopback */ /* No rate limit on loopback */
if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
@@ -326,6 +332,10 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
if (peer) if (peer)
inet_putpeer(peer); inet_putpeer(peer);
out: out:
if (!rc)
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
else
icmp_global_consume();
return rc; return rc;
} }
@@ -397,6 +407,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct ipcm_cookie ipc; struct ipcm_cookie ipc;
struct rtable *rt = skb_rtable(skb); struct rtable *rt = skb_rtable(skb);
struct net *net = dev_net(rt->dst.dev); struct net *net = dev_net(rt->dst.dev);
bool apply_ratelimit = false;
struct flowi4 fl4; struct flowi4 fl4;
struct sock *sk; struct sock *sk;
struct inet_sock *inet; struct inet_sock *inet;
@@ -408,11 +419,11 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
if (ip_options_echo(net, &icmp_param->replyopts.opt.opt, skb)) if (ip_options_echo(net, &icmp_param->replyopts.opt.opt, skb))
return; return;
/* Needed by both icmp_global_allow and icmp_xmit_lock */ /* Needed by both icmpv4_global_allow and icmp_xmit_lock */
local_bh_disable(); local_bh_disable();
/* global icmp_msgs_per_sec */ /* is global icmp_msgs_per_sec exhausted ? */
if (!icmpv4_global_allow(net, type, code)) if (!icmpv4_global_allow(net, type, code, &apply_ratelimit))
goto out_bh_enable; goto out_bh_enable;
sk = icmp_xmit_lock(net); sk = icmp_xmit_lock(net);
@@ -445,7 +456,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
rt = ip_route_output_key(net, &fl4); rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt)) if (IS_ERR(rt))
goto out_unlock; goto out_unlock;
if (icmpv4_xrlim_allow(net, rt, &fl4, type, code)) if (icmpv4_xrlim_allow(net, rt, &fl4, type, code, apply_ratelimit))
icmp_push_reply(sk, icmp_param, &fl4, &ipc, &rt); icmp_push_reply(sk, icmp_param, &fl4, &ipc, &rt);
ip_rt_put(rt); ip_rt_put(rt);
out_unlock: out_unlock:
@@ -589,6 +600,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
int room; int room;
struct icmp_bxm icmp_param; struct icmp_bxm icmp_param;
struct rtable *rt = skb_rtable(skb_in); struct rtable *rt = skb_rtable(skb_in);
bool apply_ratelimit = false;
struct ipcm_cookie ipc; struct ipcm_cookie ipc;
struct flowi4 fl4; struct flowi4 fl4;
__be32 saddr; __be32 saddr;
@@ -670,7 +682,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
} }
} }
/* Needed by both icmp_global_allow and icmp_xmit_lock */ /* Needed by both icmpv4_global_allow and icmp_xmit_lock */
local_bh_disable(); local_bh_disable();
/* Check global sysctl_icmp_msgs_per_sec ratelimit, unless /* Check global sysctl_icmp_msgs_per_sec ratelimit, unless
@@ -678,7 +690,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
* loopback, then peer ratelimit still work (in icmpv4_xrlim_allow) * loopback, then peer ratelimit still work (in icmpv4_xrlim_allow)
*/ */
if (!(skb_in->dev && (skb_in->dev->flags&IFF_LOOPBACK)) && if (!(skb_in->dev && (skb_in->dev->flags&IFF_LOOPBACK)) &&
!icmpv4_global_allow(net, type, code)) !icmpv4_global_allow(net, type, code, &apply_ratelimit))
goto out_bh_enable; goto out_bh_enable;
sk = icmp_xmit_lock(net); sk = icmp_xmit_lock(net);
@@ -737,7 +749,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
goto out_unlock; goto out_unlock;
/* peer icmp_ratelimit */ /* peer icmp_ratelimit */
if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code, apply_ratelimit))
goto ende; goto ende;
/* RFC says return as much as we can without exceeding 576 bytes. */ /* RFC says return as much as we can without exceeding 576 bytes. */

View File

@@ -352,7 +352,7 @@ static void icmp_put(struct seq_file *seq)
seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors"); seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " In%s", icmpmibmap[i].name); seq_printf(seq, " In%s", icmpmibmap[i].name);
seq_puts(seq, " OutMsgs OutErrors"); seq_puts(seq, " OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost");
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " Out%s", icmpmibmap[i].name); seq_printf(seq, " Out%s", icmpmibmap[i].name);
seq_printf(seq, "\nIcmp: %lu %lu %lu", seq_printf(seq, "\nIcmp: %lu %lu %lu",
@@ -362,9 +362,11 @@ static void icmp_put(struct seq_file *seq)
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " %lu", seq_printf(seq, " %lu",
atomic_long_read(ptr + icmpmibmap[i].index)); atomic_long_read(ptr + icmpmibmap[i].index));
seq_printf(seq, " %lu %lu", seq_printf(seq, " %lu %lu %lu %lu",
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_RATELIMITGLOBAL),
snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_RATELIMITHOST));
for (i = 0; icmpmibmap[i].name; i++) for (i = 0; icmpmibmap[i].name; i++)
seq_printf(seq, " %lu", seq_printf(seq, " %lu",
atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));

View File

@@ -175,14 +175,17 @@ static bool icmpv6_mask_allow(struct net *net, int type)
return false; return false;
} }
static bool icmpv6_global_allow(struct net *net, int type) static bool icmpv6_global_allow(struct net *net, int type,
bool *apply_ratelimit)
{ {
if (icmpv6_mask_allow(net, type)) if (icmpv6_mask_allow(net, type))
return true; return true;
if (icmp_global_allow()) if (icmp_global_allow()) {
*apply_ratelimit = true;
return true; return true;
}
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
return false; return false;
} }
@@ -190,13 +193,13 @@ static bool icmpv6_global_allow(struct net *net, int type)
* Check the ICMP output rate limit * Check the ICMP output rate limit
*/ */
static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
struct flowi6 *fl6) struct flowi6 *fl6, bool apply_ratelimit)
{ {
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct dst_entry *dst; struct dst_entry *dst;
bool res = false; bool res = false;
if (icmpv6_mask_allow(net, type)) if (!apply_ratelimit)
return true; return true;
/* /*
@@ -224,6 +227,11 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
if (peer) if (peer)
inet_putpeer(peer); inet_putpeer(peer);
} }
if (!res)
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST);
else
icmp_global_consume();
dst_release(dst); dst_release(dst);
return res; return res;
} }
@@ -450,6 +458,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
struct net *net; struct net *net;
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
const struct in6_addr *saddr = NULL; const struct in6_addr *saddr = NULL;
bool apply_ratelimit = false;
struct dst_entry *dst; struct dst_entry *dst;
struct icmp6hdr tmp_hdr; struct icmp6hdr tmp_hdr;
struct flowi6 fl6; struct flowi6 fl6;
@@ -531,11 +540,12 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
return; return;
} }
/* Needed by both icmp_global_allow and icmpv6_xmit_lock */ /* Needed by both icmpv6_global_allow and icmpv6_xmit_lock */
local_bh_disable(); local_bh_disable();
/* Check global sysctl_icmp_msgs_per_sec ratelimit */ /* Check global sysctl_icmp_msgs_per_sec ratelimit */
if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type)) if (!(skb->dev->flags & IFF_LOOPBACK) &&
!icmpv6_global_allow(net, type, &apply_ratelimit))
goto out_bh_enable; goto out_bh_enable;
mip6_addr_swap(skb, parm); mip6_addr_swap(skb, parm);
@@ -573,7 +583,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
np = inet6_sk(sk); np = inet6_sk(sk);
if (!icmpv6_xrlim_allow(sk, type, &fl6)) if (!icmpv6_xrlim_allow(sk, type, &fl6, apply_ratelimit))
goto out; goto out;
tmp_hdr.icmp6_type = type; tmp_hdr.icmp6_type = type;
@@ -715,6 +725,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
const struct in6_addr *saddr = NULL; const struct in6_addr *saddr = NULL;
struct icmp6hdr *icmph = icmp6_hdr(skb); struct icmp6hdr *icmph = icmp6_hdr(skb);
bool apply_ratelimit = false;
struct icmp6hdr tmp_hdr; struct icmp6hdr tmp_hdr;
struct flowi6 fl6; struct flowi6 fl6;
struct icmpv6_msg msg; struct icmpv6_msg msg;
@@ -778,8 +789,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
goto out; goto out;
/* Check the ratelimit */ /* Check the ratelimit */
if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) || if ((!(skb->dev->flags & IFF_LOOPBACK) &&
!icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6)) !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY, &apply_ratelimit)) ||
!icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6, apply_ratelimit))
goto out_dst_release; goto out_dst_release;
idev = __in6_dev_get(skb->dev); idev = __in6_dev_get(skb->dev);

View File

@@ -94,6 +94,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS), SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS), SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS),
SNMP_MIB_ITEM("Icmp6OutRateLimitHost", ICMP6_MIB_RATELIMITHOST),
SNMP_MIB_SENTINEL SNMP_MIB_SENTINEL
}; };

View File

@@ -24,7 +24,6 @@ static int __init bpf_lsm_init(void)
struct lsm_blob_sizes bpf_lsm_blob_sizes __lsm_ro_after_init = { struct lsm_blob_sizes bpf_lsm_blob_sizes __lsm_ro_after_init = {
.lbs_inode = sizeof(struct bpf_storage_blob), .lbs_inode = sizeof(struct bpf_storage_blob),
.lbs_task = sizeof(struct bpf_storage_blob),
}; };
DEFINE_LSM(bpf) = { DEFINE_LSM(bpf) = {