mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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:
@@ -593,8 +593,7 @@ config PPC64_BIG_ENDIAN_ELF_ABI_V2
|
||||
bool "Build big-endian kernel using ELF ABI V2 (EXPERIMENTAL)"
|
||||
depends on PPC64 && CPU_BIG_ENDIAN
|
||||
depends on CC_HAS_ELFV2
|
||||
depends on LD_IS_BFD && LD_VERSION >= 22400
|
||||
default n
|
||||
depends on LD_VERSION >= 22400 || LLD_VERSION >= 150000
|
||||
help
|
||||
This builds the kernel image using the "Power Architecture 64-Bit ELF
|
||||
V2 ABI Specification", which has a reduced stack overhead and faster
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <asm/insn.h>
|
||||
#include <asm/insn-eval.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
/* TDX module Call Leaf IDs */
|
||||
#define TDX_GET_INFO 1
|
||||
@@ -371,6 +372,11 @@ static int handle_mmio(struct pt_regs *regs, struct ve_info *ve)
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -62,7 +62,11 @@ extern u64 arch_irq_stat(void);
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
#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 /* _ASM_X86_HARDIRQ_H */
|
||||
|
||||
@@ -13,15 +13,18 @@
|
||||
|
||||
#include <asm/irq_stack.h>
|
||||
|
||||
typedef void (*idtentry_t)(struct pt_regs *regs);
|
||||
|
||||
/**
|
||||
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points
|
||||
* No error code pushed by hardware
|
||||
* @vector: Vector number (ignored for C)
|
||||
* @func: Function name of the entry point
|
||||
*
|
||||
* Declares three functions:
|
||||
* Declares four functions:
|
||||
* - The ASM entry point: asm_##func
|
||||
* - 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
|
||||
*
|
||||
* Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it
|
||||
@@ -31,6 +34,7 @@
|
||||
#define DECLARE_IDTENTRY(vector, func) \
|
||||
asmlinkage void asm_##func(void); \
|
||||
asmlinkage void xen_asm_##func(void); \
|
||||
void fred_##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) \
|
||||
__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
|
||||
* Error code pushed by hardware
|
||||
@@ -197,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \
|
||||
irqentry_state_t state = irqentry_enter(regs); \
|
||||
u32 vector = (u32)(u8)error_code; \
|
||||
\
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
instrumentation_begin(); \
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
run_irq_on_irqstack_cond(__##func, regs, vector); \
|
||||
instrumentation_end(); \
|
||||
irqentry_exit(regs, state); \
|
||||
@@ -233,17 +248,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector)
|
||||
#define DEFINE_IDTENTRY_SYSVEC(func) \
|
||||
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) \
|
||||
{ \
|
||||
irqentry_state_t state = irqentry_enter(regs); \
|
||||
\
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
instrumentation_begin(); \
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
run_sysvec_on_irqstack_cond(__##func, regs); \
|
||||
instr_##func (regs); \
|
||||
instrumentation_end(); \
|
||||
irqentry_exit(regs, state); \
|
||||
} \
|
||||
\
|
||||
void fred_##func(struct pt_regs *regs) \
|
||||
{ \
|
||||
instr_##func (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) \
|
||||
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) \
|
||||
{ \
|
||||
irqentry_state_t state = irqentry_enter(regs); \
|
||||
\
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
instrumentation_begin(); \
|
||||
__irq_enter_raw(); \
|
||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||
__##func (regs); \
|
||||
__irq_exit_raw(); \
|
||||
instr_##func (regs); \
|
||||
instrumentation_end(); \
|
||||
irqentry_exit(regs, state); \
|
||||
} \
|
||||
\
|
||||
void fred_##func(struct pt_regs *regs) \
|
||||
{ \
|
||||
instr_##func (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 */
|
||||
#define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW
|
||||
#define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW
|
||||
#define DEFINE_FREDENTRY_NMI DEFINE_FREDENTRY_RAW
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define DECLARE_IDTENTRY_MCE DECLARE_IDTENTRY_IST
|
||||
#define DEFINE_IDTENTRY_MCE DEFINE_IDTENTRY_IST
|
||||
#define DEFINE_IDTENTRY_MCE_USER DEFINE_IDTENTRY_NOIST
|
||||
#define DEFINE_FREDENTRY_MCE DEFINE_FREDENTRY_RAW
|
||||
|
||||
#define DECLARE_IDTENTRY_DEBUG DECLARE_IDTENTRY_IST
|
||||
#define DEFINE_IDTENTRY_DEBUG DEFINE_IDTENTRY_IST
|
||||
#define DEFINE_IDTENTRY_DEBUG_USER DEFINE_IDTENTRY_NOIST
|
||||
#define DEFINE_FREDENTRY_DEBUG DEFINE_FREDENTRY_RAW
|
||||
#endif
|
||||
|
||||
#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(CALL_FUNCTION_SINGLE_VECTOR, sysvec_call_function_single);
|
||||
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
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
# ifdef CONFIG_X86_MCE_THRESHOLD
|
||||
DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR, sysvec_threshold);
|
||||
# else
|
||||
# define fred_sysvec_threshold NULL
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_X86_MCE_AMD
|
||||
DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR, sysvec_deferred_error);
|
||||
# else
|
||||
# define fred_sysvec_deferred_error NULL
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_X86_THERMAL_VECTOR
|
||||
DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR, sysvec_thermal);
|
||||
# else
|
||||
# define fred_sysvec_thermal NULL
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_IRQ_WORK
|
||||
DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work);
|
||||
# else
|
||||
# define fred_sysvec_irq_work NULL
|
||||
# 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_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_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
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback);
|
||||
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
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACRN_GUEST)
|
||||
|
||||
@@ -170,6 +170,13 @@ struct aspeed_i2c_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)
|
||||
{
|
||||
unsigned long time_left, flags;
|
||||
@@ -187,7 +194,7 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
|
||||
command);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus)
|
||||
{
|
||||
|
||||
@@ -99,8 +99,7 @@ static int sch_transaction(void)
|
||||
if (retries > MAX_RETRIES) {
|
||||
dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
|
||||
result = -ETIMEDOUT;
|
||||
}
|
||||
if (temp & 0x04) {
|
||||
} else if (temp & 0x04) {
|
||||
result = -EIO;
|
||||
dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
|
||||
"locked until next hard reset. (sorry!)\n");
|
||||
|
||||
@@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data)
|
||||
|
||||
/* Compatible Asahi Kasei Compass parts */
|
||||
enum asahi_compass_chipset {
|
||||
AKXXXX = 0,
|
||||
AK8975,
|
||||
AK8963,
|
||||
AK09911,
|
||||
@@ -248,7 +247,7 @@ struct ak_def {
|
||||
};
|
||||
|
||||
static const struct ak_def ak_def_array[] = {
|
||||
{
|
||||
[AK8975] = {
|
||||
.type = AK8975,
|
||||
.raw_to_gauss = ak8975_raw_to_gauss,
|
||||
.range = 4096,
|
||||
@@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = {
|
||||
AK8975_REG_HYL,
|
||||
AK8975_REG_HZL},
|
||||
},
|
||||
{
|
||||
[AK8963] = {
|
||||
.type = AK8963,
|
||||
.raw_to_gauss = ak8963_09911_raw_to_gauss,
|
||||
.range = 8190,
|
||||
@@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = {
|
||||
AK8975_REG_HYL,
|
||||
AK8975_REG_HZL},
|
||||
},
|
||||
{
|
||||
[AK09911] = {
|
||||
.type = AK09911,
|
||||
.raw_to_gauss = ak8963_09911_raw_to_gauss,
|
||||
.range = 8192,
|
||||
@@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = {
|
||||
AK09912_REG_HYL,
|
||||
AK09912_REG_HZL},
|
||||
},
|
||||
{
|
||||
[AK09912] = {
|
||||
.type = AK09912,
|
||||
.raw_to_gauss = ak09912_raw_to_gauss,
|
||||
.range = 32752,
|
||||
@@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = {
|
||||
AK09912_REG_HYL,
|
||||
AK09912_REG_HZL},
|
||||
},
|
||||
{
|
||||
[AK09916] = {
|
||||
.type = AK09916,
|
||||
.raw_to_gauss = ak09912_raw_to_gauss,
|
||||
.range = 32752,
|
||||
|
||||
@@ -522,6 +522,7 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set_bit(MT76_STATE_REGISTERED, &phy->state);
|
||||
phy->dev->phys[phy->band_idx] = phy;
|
||||
|
||||
return 0;
|
||||
@@ -532,6 +533,9 @@ void mt76_unregister_phy(struct mt76_phy *phy)
|
||||
{
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
|
||||
if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
|
||||
return;
|
||||
|
||||
mt76_tx_status_check(dev, true);
|
||||
ieee80211_unregister_hw(phy->hw);
|
||||
dev->phys[phy->band_idx] = NULL;
|
||||
@@ -654,6 +658,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
|
||||
return ret;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
@@ -664,6 +669,9 @@ void mt76_unregister_device(struct mt76_dev *dev)
|
||||
{
|
||||
struct ieee80211_hw *hw = dev->hw;
|
||||
|
||||
if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
|
||||
return;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MT76_LEDS))
|
||||
mt76_led_cleanup(dev);
|
||||
mt76_tx_status_check(dev, true);
|
||||
|
||||
@@ -388,6 +388,7 @@ struct mt76_tx_cb {
|
||||
|
||||
enum {
|
||||
MT76_STATE_INITIALIZED,
|
||||
MT76_STATE_REGISTERED,
|
||||
MT76_STATE_RUNNING,
|
||||
MT76_STATE_MCU_RUNNING,
|
||||
MT76_SCANNING,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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
|
||||
|
||||
@@ -1671,7 +1671,7 @@ static int arm_cmn_event_add(struct perf_event *event, int flags)
|
||||
idx = 0;
|
||||
while (cmn->dtc[j].counters[idx])
|
||||
if (++idx == CMN_DT_NUM_COUNTERS)
|
||||
goto free_dtms;
|
||||
return -ENOSPC;
|
||||
}
|
||||
hw->dtc_idx[j] = idx;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,10 @@ static void parport_attach(struct parport *port)
|
||||
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));
|
||||
pps_client_cb.private = device;
|
||||
pps_client_cb.irq_func = parport_irq;
|
||||
@@ -159,7 +162,7 @@ static void parport_attach(struct parport *port)
|
||||
index);
|
||||
if (!device->pardev) {
|
||||
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) {
|
||||
@@ -187,8 +190,9 @@ err_release_dev:
|
||||
parport_release(device->pardev);
|
||||
err_unregister_dev:
|
||||
parport_unregister_device(device->pardev);
|
||||
err_free:
|
||||
ida_simple_remove(&pps_client_index, index);
|
||||
err_free_ida:
|
||||
ida_free(&pps_client_index, index);
|
||||
err_free_device:
|
||||
kfree(device);
|
||||
}
|
||||
|
||||
@@ -208,7 +212,7 @@ static void parport_detach(struct parport *port)
|
||||
pps_unregister_source(device->pps);
|
||||
parport_release(pardev);
|
||||
parport_unregister_device(pardev);
|
||||
ida_simple_remove(&pps_client_index, device->index);
|
||||
ida_free(&pps_client_index, device->index);
|
||||
kfree(device);
|
||||
}
|
||||
|
||||
|
||||
@@ -413,8 +413,10 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
|
||||
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;
|
||||
}
|
||||
|
||||
spin_lock_irq(&dev->lock);
|
||||
scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
|
||||
|
||||
@@ -1530,6 +1530,7 @@ void xas_create_range(struct xa_state *);
|
||||
|
||||
#ifdef CONFIG_XARRAY_MULTI
|
||||
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_alloc(struct xa_state *, void *entry, unsigned int order, gfp_t);
|
||||
#else
|
||||
@@ -1538,6 +1539,11 @@ static inline int xa_get_order(struct xarray *xa, unsigned long index)
|
||||
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,
|
||||
unsigned int order)
|
||||
{
|
||||
|
||||
@@ -772,6 +772,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
bool icmp_global_allow(void);
|
||||
void icmp_global_consume(void);
|
||||
|
||||
extern int sysctl_icmp_msgs_per_sec;
|
||||
extern int sysctl_icmp_msgs_burst;
|
||||
|
||||
|
||||
@@ -95,6 +95,8 @@ enum
|
||||
ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */
|
||||
ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */
|
||||
ICMP_MIB_CSUMERRORS, /* InCsumErrors */
|
||||
ICMP_MIB_RATELIMITGLOBAL, /* OutRateLimitGlobal */
|
||||
ICMP_MIB_RATELIMITHOST, /* OutRateLimitHost */
|
||||
__ICMP_MIB_MAX
|
||||
};
|
||||
|
||||
@@ -112,6 +114,7 @@ enum
|
||||
ICMP6_MIB_OUTMSGS, /* OutMsgs */
|
||||
ICMP6_MIB_OUTERRORS, /* OutErrors */
|
||||
ICMP6_MIB_CSUMERRORS, /* InCsumErrors */
|
||||
ICMP6_MIB_RATELIMITHOST, /* OutRateLimitHost */
|
||||
__ICMP6_MIB_MAX
|
||||
};
|
||||
|
||||
|
||||
@@ -6064,25 +6064,27 @@ static struct pending_free *get_pending_free(void)
|
||||
static void free_zapped_rcu(struct rcu_head *cb);
|
||||
|
||||
/*
|
||||
* Schedule an RCU callback if no RCU callback is pending. Must be called with
|
||||
* the graph lock held.
|
||||
*/
|
||||
static void call_rcu_zapped(struct pending_free *pf)
|
||||
* See if we need to queue an RCU callback, must called with
|
||||
* the lockdep lock held, returns false if either we don't have
|
||||
* any pending free or the callback is already scheduled.
|
||||
* Otherwise, a call_rcu() must follow this function call.
|
||||
*/
|
||||
static bool prepare_call_rcu_zapped(struct pending_free *pf)
|
||||
{
|
||||
WARN_ON_ONCE(inside_selftest());
|
||||
|
||||
if (list_empty(&pf->zapped))
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (delayed_free.scheduled)
|
||||
return;
|
||||
return false;
|
||||
|
||||
delayed_free.scheduled = true;
|
||||
|
||||
WARN_ON_ONCE(delayed_free.pf + delayed_free.index != pf);
|
||||
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. */
|
||||
@@ -6108,6 +6110,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
|
||||
{
|
||||
struct pending_free *pf;
|
||||
unsigned long flags;
|
||||
bool need_callback;
|
||||
|
||||
if (WARN_ON_ONCE(ch != &delayed_free.rcu_head))
|
||||
return;
|
||||
@@ -6119,14 +6122,18 @@ static void free_zapped_rcu(struct rcu_head *ch)
|
||||
pf = delayed_free.pf + (delayed_free.index ^ 1);
|
||||
__free_zapped_classes(pf);
|
||||
delayed_free.scheduled = false;
|
||||
|
||||
/*
|
||||
* If there's anything on the open list, close and start a new callback.
|
||||
*/
|
||||
call_rcu_zapped(delayed_free.pf + delayed_free.index);
|
||||
|
||||
need_callback =
|
||||
prepare_call_rcu_zapped(delayed_free.pf + delayed_free.index);
|
||||
lockdep_unlock();
|
||||
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;
|
||||
unsigned long flags;
|
||||
bool need_callback;
|
||||
|
||||
init_data_structures_once();
|
||||
|
||||
@@ -6173,10 +6181,11 @@ static void lockdep_free_key_range_reg(void *start, unsigned long size)
|
||||
lockdep_lock();
|
||||
pf = get_pending_free();
|
||||
__lockdep_free_key_range(pf, start, size);
|
||||
call_rcu_zapped(pf);
|
||||
need_callback = prepare_call_rcu_zapped(pf);
|
||||
lockdep_unlock();
|
||||
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
|
||||
* 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;
|
||||
unsigned long flags;
|
||||
int locked;
|
||||
bool need_callback = false;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
locked = graph_lock();
|
||||
@@ -6278,11 +6288,13 @@ static void lockdep_reset_lock_reg(struct lockdep_map *lock)
|
||||
|
||||
pf = get_pending_free();
|
||||
__lockdep_reset_lock(pf, lock);
|
||||
call_rcu_zapped(pf);
|
||||
need_callback = prepare_call_rcu_zapped(pf);
|
||||
|
||||
graph_unlock();
|
||||
out_irq:
|
||||
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;
|
||||
unsigned long flags;
|
||||
bool found = false;
|
||||
bool need_callback = false;
|
||||
|
||||
might_sleep();
|
||||
|
||||
@@ -6346,11 +6359,14 @@ void lockdep_unregister_key(struct lock_class_key *key)
|
||||
if (found) {
|
||||
pf = get_pending_free();
|
||||
__lockdep_free_key_range(pf, key, 1);
|
||||
call_rcu_zapped(pf);
|
||||
need_callback = prepare_call_rcu_zapped(pf);
|
||||
}
|
||||
lockdep_unlock();
|
||||
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. */
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# These are called from save_stack_trace() on slub debug path,
|
||||
# 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-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
unsigned long index;
|
||||
@@ -1805,6 +1896,8 @@ static int xarray_checks(void)
|
||||
check_reserve(&xa0);
|
||||
check_multi_store(&array);
|
||||
check_get_order(&array);
|
||||
check_xas_get_order(&array);
|
||||
check_xas_conflict_get_order(&array);
|
||||
check_xa_alloc();
|
||||
check_find(&array);
|
||||
check_find_entry(&array);
|
||||
|
||||
53
lib/xarray.c
53
lib/xarray.c
@@ -1751,6 +1751,36 @@ unlock:
|
||||
}
|
||||
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: XArray.
|
||||
@@ -1761,30 +1791,13 @@ EXPORT_SYMBOL(xa_store_range);
|
||||
int xa_get_order(struct xarray *xa, unsigned long index)
|
||||
{
|
||||
XA_STATE(xas, xa, index);
|
||||
void *entry;
|
||||
int order = 0;
|
||||
void *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
entry = xas_load(&xas);
|
||||
|
||||
if (!entry)
|
||||
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:
|
||||
if (entry)
|
||||
order = xas_get_order(&xas);
|
||||
rcu_read_unlock();
|
||||
|
||||
return order;
|
||||
|
||||
@@ -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
|
||||
* tree gaps.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for_each_vma(vmi, vma) {
|
||||
unsigned long gap;
|
||||
|
||||
@@ -146,6 +147,7 @@ static int __damon_va_three_regions(struct mm_struct *mm,
|
||||
next:
|
||||
prev = vma;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!sz_range(&second_gap) || !sz_range(&first_gap))
|
||||
return -EINVAL;
|
||||
|
||||
50
mm/filemap.c
50
mm/filemap.c
@@ -861,6 +861,8 @@ noinline int __filemap_add_folio(struct address_space *mapping,
|
||||
{
|
||||
XA_STATE(xas, &mapping->i_pages, index);
|
||||
int huge = folio_test_hugetlb(folio);
|
||||
void *alloced_shadow = NULL;
|
||||
int alloced_order = 0;
|
||||
bool charged = false;
|
||||
long nr = 1;
|
||||
|
||||
@@ -883,13 +885,10 @@ noinline int __filemap_add_folio(struct address_space *mapping,
|
||||
folio->mapping = mapping;
|
||||
folio->index = xas.xa_index;
|
||||
|
||||
do {
|
||||
unsigned int order = xa_get_order(xas.xa, xas.xa_index);
|
||||
for (;;) {
|
||||
int order = -1, split_order = 0;
|
||||
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_for_each_conflict(&xas, entry) {
|
||||
old = entry;
|
||||
@@ -897,19 +896,33 @@ noinline int __filemap_add_folio(struct address_space *mapping,
|
||||
xas_set_err(&xas, -EEXIST);
|
||||
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 (shadowp)
|
||||
*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)) {
|
||||
if (order > 0 && order > folio_order(folio)) {
|
||||
/* How to handle large swap entries? */
|
||||
BUG_ON(shmem_mapping(mapping));
|
||||
if (!alloced_order) {
|
||||
split_order = order;
|
||||
goto unlock;
|
||||
}
|
||||
xas_split(&xas, old, order);
|
||||
xas_reset(&xas);
|
||||
}
|
||||
if (shadowp)
|
||||
*shadowp = old;
|
||||
}
|
||||
|
||||
xas_store(&xas, folio);
|
||||
@@ -925,9 +938,24 @@ noinline int __filemap_add_folio(struct address_space *mapping,
|
||||
__lruvec_stat_mod_folio(folio,
|
||||
NR_FILE_THPS, nr);
|
||||
}
|
||||
|
||||
unlock:
|
||||
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))
|
||||
goto error;
|
||||
|
||||
@@ -404,7 +404,7 @@ static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
|
||||
if (gap + pad > gap)
|
||||
gap += pad;
|
||||
|
||||
if (gap < MIN_GAP)
|
||||
if (gap < MIN_GAP && MIN_GAP < MAX_GAP)
|
||||
gap = MIN_GAP;
|
||||
else if (gap > MAX_GAP)
|
||||
gap = MAX_GAP;
|
||||
|
||||
106
net/ipv4/icmp.c
106
net/ipv4/icmp.c
@@ -222,57 +222,59 @@ int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
|
||||
int sysctl_icmp_msgs_burst __read_mostly = 50;
|
||||
|
||||
static struct {
|
||||
spinlock_t lock;
|
||||
u32 credit;
|
||||
atomic_t credit;
|
||||
u32 stamp;
|
||||
} icmp_global = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock),
|
||||
};
|
||||
} icmp_global;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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)
|
||||
{
|
||||
u32 credit, delta, incr = 0, now = (u32)jiffies;
|
||||
bool rc = false;
|
||||
u32 delta, now, oldstamp;
|
||||
int incr, new, old;
|
||||
|
||||
/* Check if token bucket is empty and cannot be refilled
|
||||
* without taking the spinlock. The READ_ONCE() are paired
|
||||
* with the following WRITE_ONCE() in this same function.
|
||||
/* Note: many cpus could find this condition true.
|
||||
* Then later icmp_global_consume() could consume more credits,
|
||||
* this is an acceptable race.
|
||||
*/
|
||||
if (!READ_ONCE(icmp_global.credit)) {
|
||||
delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ);
|
||||
if (delta < HZ / 50)
|
||||
return false;
|
||||
}
|
||||
if (atomic_read(&icmp_global.credit) > 0)
|
||||
return true;
|
||||
|
||||
spin_lock(&icmp_global.lock);
|
||||
delta = min_t(u32, now - icmp_global.stamp, HZ);
|
||||
if (delta >= HZ / 50) {
|
||||
incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
|
||||
if (incr)
|
||||
WRITE_ONCE(icmp_global.stamp, now);
|
||||
now = jiffies;
|
||||
oldstamp = READ_ONCE(icmp_global.stamp);
|
||||
delta = min_t(u32, now - oldstamp, HZ);
|
||||
if (delta < HZ / 50)
|
||||
return false;
|
||||
|
||||
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,
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (type > NR_ICMP_TYPES)
|
||||
@@ -289,14 +291,17 @@ static bool icmpv4_mask_allow(struct net *net, int type, int code)
|
||||
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))
|
||||
return true;
|
||||
|
||||
if (icmp_global_allow())
|
||||
if (icmp_global_allow()) {
|
||||
*apply_ratelimit = true;
|
||||
return true;
|
||||
|
||||
}
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
|
||||
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,
|
||||
struct flowi4 *fl4, int type, int code)
|
||||
struct flowi4 *fl4, int type, int code,
|
||||
bool apply_ratelimit)
|
||||
{
|
||||
struct dst_entry *dst = &rt->dst;
|
||||
struct inet_peer *peer;
|
||||
bool rc = true;
|
||||
int vif;
|
||||
|
||||
if (icmpv4_mask_allow(net, type, code))
|
||||
goto out;
|
||||
if (!apply_ratelimit)
|
||||
return true;
|
||||
|
||||
/* No rate limit on 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)
|
||||
inet_putpeer(peer);
|
||||
out:
|
||||
if (!rc)
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
|
||||
else
|
||||
icmp_global_consume();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -397,6 +407,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
||||
struct ipcm_cookie ipc;
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
struct net *net = dev_net(rt->dst.dev);
|
||||
bool apply_ratelimit = false;
|
||||
struct flowi4 fl4;
|
||||
struct sock *sk;
|
||||
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))
|
||||
return;
|
||||
|
||||
/* Needed by both icmp_global_allow and icmp_xmit_lock */
|
||||
/* Needed by both icmpv4_global_allow and icmp_xmit_lock */
|
||||
local_bh_disable();
|
||||
|
||||
/* global icmp_msgs_per_sec */
|
||||
if (!icmpv4_global_allow(net, type, code))
|
||||
/* is global icmp_msgs_per_sec exhausted ? */
|
||||
if (!icmpv4_global_allow(net, type, code, &apply_ratelimit))
|
||||
goto out_bh_enable;
|
||||
|
||||
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);
|
||||
if (IS_ERR(rt))
|
||||
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);
|
||||
ip_rt_put(rt);
|
||||
out_unlock:
|
||||
@@ -589,6 +600,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
|
||||
int room;
|
||||
struct icmp_bxm icmp_param;
|
||||
struct rtable *rt = skb_rtable(skb_in);
|
||||
bool apply_ratelimit = false;
|
||||
struct ipcm_cookie ipc;
|
||||
struct flowi4 fl4;
|
||||
__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();
|
||||
|
||||
/* 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)
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* RFC says return as much as we can without exceeding 576 bytes. */
|
||||
|
||||
@@ -352,7 +352,7 @@ static void icmp_put(struct seq_file *seq)
|
||||
seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
|
||||
for (i = 0; icmpmibmap[i].name; i++)
|
||||
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++)
|
||||
seq_printf(seq, " Out%s", icmpmibmap[i].name);
|
||||
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++)
|
||||
seq_printf(seq, " %lu",
|
||||
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_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++)
|
||||
seq_printf(seq, " %lu",
|
||||
atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
|
||||
|
||||
@@ -175,14 +175,17 @@ static bool icmpv6_mask_allow(struct net *net, int type)
|
||||
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))
|
||||
return true;
|
||||
|
||||
if (icmp_global_allow())
|
||||
if (icmp_global_allow()) {
|
||||
*apply_ratelimit = true;
|
||||
return true;
|
||||
|
||||
}
|
||||
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -190,13 +193,13 @@ static bool icmpv6_global_allow(struct net *net, int type)
|
||||
* Check the ICMP output rate limit
|
||||
*/
|
||||
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 dst_entry *dst;
|
||||
bool res = false;
|
||||
|
||||
if (icmpv6_mask_allow(net, type))
|
||||
if (!apply_ratelimit)
|
||||
return true;
|
||||
|
||||
/*
|
||||
@@ -224,6 +227,11 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
|
||||
if (peer)
|
||||
inet_putpeer(peer);
|
||||
}
|
||||
if (!res)
|
||||
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
ICMP6_MIB_RATELIMITHOST);
|
||||
else
|
||||
icmp_global_consume();
|
||||
dst_release(dst);
|
||||
return res;
|
||||
}
|
||||
@@ -450,6 +458,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
struct net *net;
|
||||
struct ipv6_pinfo *np;
|
||||
const struct in6_addr *saddr = NULL;
|
||||
bool apply_ratelimit = false;
|
||||
struct dst_entry *dst;
|
||||
struct icmp6hdr tmp_hdr;
|
||||
struct flowi6 fl6;
|
||||
@@ -531,11 +540,12 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Needed by both icmp_global_allow and icmpv6_xmit_lock */
|
||||
/* Needed by both icmpv6_global_allow and icmpv6_xmit_lock */
|
||||
local_bh_disable();
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
if (!icmpv6_xrlim_allow(sk, type, &fl6))
|
||||
if (!icmpv6_xrlim_allow(sk, type, &fl6, apply_ratelimit))
|
||||
goto out;
|
||||
|
||||
tmp_hdr.icmp6_type = type;
|
||||
@@ -715,6 +725,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
struct ipv6_pinfo *np;
|
||||
const struct in6_addr *saddr = NULL;
|
||||
struct icmp6hdr *icmph = icmp6_hdr(skb);
|
||||
bool apply_ratelimit = false;
|
||||
struct icmp6hdr tmp_hdr;
|
||||
struct flowi6 fl6;
|
||||
struct icmpv6_msg msg;
|
||||
@@ -778,8 +789,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
goto out;
|
||||
|
||||
/* Check the ratelimit */
|
||||
if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) ||
|
||||
!icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6))
|
||||
if ((!(skb->dev->flags & IFF_LOOPBACK) &&
|
||||
!icmpv6_global_allow(net, ICMPV6_ECHO_REPLY, &apply_ratelimit)) ||
|
||||
!icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6, apply_ratelimit))
|
||||
goto out_dst_release;
|
||||
|
||||
idev = __in6_dev_get(skb->dev);
|
||||
|
||||
@@ -94,6 +94,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
|
||||
SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
|
||||
SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
|
||||
SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS),
|
||||
SNMP_MIB_ITEM("Icmp6OutRateLimitHost", ICMP6_MIB_RATELIMITHOST),
|
||||
SNMP_MIB_SENTINEL
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ static int __init bpf_lsm_init(void)
|
||||
|
||||
struct lsm_blob_sizes bpf_lsm_blob_sizes __lsm_ro_after_init = {
|
||||
.lbs_inode = sizeof(struct bpf_storage_blob),
|
||||
.lbs_task = sizeof(struct bpf_storage_blob),
|
||||
};
|
||||
|
||||
DEFINE_LSM(bpf) = {
|
||||
|
||||
Reference in New Issue
Block a user