Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Cross-merge networking fixes after downstream PR (net-7.1-rc2).

No conflicts, or adjacent changes.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-04-30 12:49:56 -07:00
358 changed files with 5243 additions and 3973 deletions

View File

@@ -220,7 +220,7 @@ cgroup v2 currently supports the following mount options.
memory_hugetlb_accounting
Count HugeTLB memory usage towards the cgroup's overall
memory usage for the memory controller (for the purpose of
statistics reporting and memory protetion). This is a new
statistics reporting and memory protection). This is a new
behavior that could regress existing setups, so it must be
explicitly opted in with this mount option.

View File

@@ -24,6 +24,7 @@ properties:
compatible:
items:
- enum:
- qcom,eliza-ipcc
- qcom,glymur-ipcc
- qcom,kaanapali-ipcc
- qcom,milos-ipcc

View File

@@ -57,7 +57,7 @@ Mount options unique to the isofs filesystem.
Recommended documents about ISO 9660 standard are located at:
- http://www.y-adagio.com/
- ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
- https://ecma-international.org/wp-content/uploads/ECMA-119_2nd_edition_december_1987.pdf
Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically
identical with ISO 9660.", so it is a valid and gratis substitute of the

View File

@@ -188,6 +188,7 @@ operations:
name: dev-set
doc: Set the configuration of a PSP device.
attribute-set: dev
flags: [admin-perm]
do:
request:
attributes:
@@ -207,6 +208,7 @@ operations:
name: key-rotate
doc: Rotate the device key.
attribute-set: dev
flags: [admin-perm]
do:
request:
attributes:

View File

@@ -18672,19 +18672,59 @@ F: net/xfrm/
F: tools/testing/selftests/net/ipsec.c
NETWORKING [IPv4/IPv6]
M: "David S. Miller" <davem@davemloft.net>
M: David Ahern <dsahern@kernel.org>
M: Ido Schimmel <idosch@nvidia.com>
L: netdev@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
F: arch/x86/net/*
F: include/linux/ip.h
F: include/linux/ipv6*
F: Documentation/netlink/specs/rt-addr.yaml
F: Documentation/netlink/specs/rt-neigh.yaml
F: Documentation/netlink/specs/rt-route.yaml
F: Documentation/netlink/specs/rt-rule.yaml
F: include/linux/inetdevice.h
F: include/linux/mroute*
F: include/net/addrconf.h
F: include/net/arp.h
F: include/net/fib*
F: include/net/if_inet6.h
F: include/net/inetpeer.h
F: include/net/ip*
F: include/net/lwtunnel.h
F: include/net/ndisc.h
F: include/net/netns/nexthop.h
F: include/net/nexthop.h
F: include/net/route.h
F: net/ipv4/
F: net/ipv6/
F: include/uapi/linux/fib_rules.h
F: include/uapi/linux/in_route.h
F: include/uapi/linux/mroute*
F: include/uapi/linux/nexthop.h
F: net/core/fib*
F: net/core/lwtunnel.c
F: net/ipv4/arp.c
F: net/ipv4/devinet.c
F: net/ipv4/fib*
F: net/ipv4/icmp.c
F: net/ipv4/igmp.c
F: net/ipv4/inet_fragment.c
F: net/ipv4/inetpeer.c
F: net/ipv4/ip*
F: net/ipv4/metrics.c
F: net/ipv4/netlink.c
F: net/ipv4/nexthop.c
F: net/ipv4/route.c
F: net/ipv6/addr*
F: net/ipv6/anycast.c
F: net/ipv6/exthdrs.c
F: net/ipv6/exthdrs_core.c
F: net/ipv6/fib*
F: net/ipv6/icmp.c
F: net/ipv6/ip*
F: net/ipv6/mcast*
F: net/ipv6/ndisc.c
F: net/ipv6/output_core.c
F: net/ipv6/reassembly.c
F: net/ipv6/route.c
F: tools/testing/selftests/net/fib*
F: tools/testing/selftests/net/forwarding/
NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK)
M: Paul Moore <paul@paul-moore.com>
@@ -18819,18 +18859,11 @@ F: Documentation/networking/net_failover.rst
F: drivers/net/net_failover.c
F: include/net/net_failover.h
NEXTHOP
M: David Ahern <dsahern@kernel.org>
L: netdev@vger.kernel.org
S: Maintained
F: include/net/netns/nexthop.h
F: include/net/nexthop.h
F: include/uapi/linux/nexthop.h
F: net/ipv4/nexthop.c
NFC SUBSYSTEM
L: netdev@vger.kernel.org
S: Orphan
M: David Heidelberg <david+nfc@ixit.cz>
L: oe-linux-nfc@lists.linux.dev
S: Maintained
T: git https://codeberg.org/linux-nfc/linux.git
F: Documentation/devicetree/bindings/net/nfc/
F: drivers/nfc/
F: include/net/nfc/
@@ -20774,6 +20807,7 @@ M: Dominik Brodowski <linux@dominikbrodowski.net>
S: Odd Fixes
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux.git
F: Documentation/pcmcia/
F: drivers/net/ethernet/8390/pcnet_cs.c
F: drivers/pcmcia/
F: include/pcmcia/
F: tools/pcmcia/

View File

@@ -50,6 +50,9 @@
#include <linux/mm.h>
#define MARKER(m) \
m, __after_##m = m - 1
enum __kvm_host_smccc_func {
/* Hypercalls that are unavailable once pKVM has finalised. */
/* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */
@@ -59,8 +62,10 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
__KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
__KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
__KVM_HOST_SMCCC_FUNC_MIN_PKVM = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
@@ -72,11 +77,20 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
__KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff,
__KVM_HOST_SMCCC_FUNC___tracing_load,
__KVM_HOST_SMCCC_FUNC___tracing_unload,
__KVM_HOST_SMCCC_FUNC___tracing_enable,
__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
__KVM_HOST_SMCCC_FUNC___tracing_reset,
__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
__KVM_HOST_SMCCC_FUNC___tracing_write_event,
__KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
__KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM = __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
/* Hypercalls that are available only when pKVM has finalised. */
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
@@ -100,14 +114,8 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_load,
__KVM_HOST_SMCCC_FUNC___pkvm_vcpu_put,
__KVM_HOST_SMCCC_FUNC___pkvm_tlb_flush_vmid,
__KVM_HOST_SMCCC_FUNC___tracing_load,
__KVM_HOST_SMCCC_FUNC___tracing_unload,
__KVM_HOST_SMCCC_FUNC___tracing_enable,
__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
__KVM_HOST_SMCCC_FUNC___tracing_reset,
__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
__KVM_HOST_SMCCC_FUNC___tracing_write_event,
MARKER(__KVM_HOST_SMCCC_FUNC_MAX)
};
#define DECLARE_KVM_VHE_SYM(sym) extern char sym[]

View File

@@ -450,9 +450,6 @@ struct kvm_vcpu_fault_info {
r = __VNCR_START__ + ((VNCR_ ## r) / 8), \
__after_##r = __MAX__(__before_##r - 1, r)
#define MARKER(m) \
m, __after_##m = m - 1
enum vcpu_sysreg {
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
MPIDR_EL1, /* MultiProcessor Affinity Register */
@@ -1548,7 +1545,7 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
#define kvm_vcpu_has_feature(k, f) __vcpu_has_feature(&(k)->arch, (f))
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
#define kvm_vcpu_initialized(v) vcpu_get_flag(vcpu, VCPU_INITIALIZED)
#define kvm_vcpu_initialized(v) vcpu_get_flag(v, VCPU_INITIALIZED)
int kvm_trng_call(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM

View File

@@ -824,6 +824,10 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF | HCR_VSE);
irq_lines |= (!irqchip_in_kernel(v->kvm) &&
(kvm_timer_should_notify_user(v) ||
kvm_pmu_should_notify_user(v)));
return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
&& !kvm_arm_vcpu_stopped(v) && !v->arch.pause);
}

View File

@@ -131,7 +131,6 @@ struct reg_feat_map_desc {
}
#define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP
#define FEAT_SPE_FnE ID_AA64DFR0_EL1, PMSVer, V1P2
#define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP
#define FEAT_TRC_SR ID_AA64DFR0_EL1, TraceVer, IMP
#define FEAT_PMUv3 ID_AA64DFR0_EL1, PMUVer, IMP
@@ -192,7 +191,7 @@ struct reg_feat_map_desc {
#define FEAT_SRMASK ID_AA64MMFR4_EL1, SRMASK, IMP
#define FEAT_PoPS ID_AA64MMFR4_EL1, PoPS, IMP
#define FEAT_PFAR ID_AA64PFR1_EL1, PFAR, IMP
#define FEAT_Debugv8p9 ID_AA64DFR0_EL1, PMUVer, V3P9
#define FEAT_Debugv8p9 ID_AA64DFR0_EL1, DebugVer, V8P9
#define FEAT_PMUv3_SS ID_AA64DFR0_EL1, PMSS, IMP
#define FEAT_SEBEP ID_AA64DFR0_EL1, SEBEP, IMP
#define FEAT_EBEP ID_AA64DFR1_EL1, EBEP, IMP
@@ -283,7 +282,7 @@ static bool feat_anerr(struct kvm *kvm)
static bool feat_sme_smps(struct kvm *kvm)
{
/*
* Revists this if KVM ever supports SME -- this really should
* Revisit this if KVM ever supports SME -- this really should
* look at the guest's view of SMIDR_EL1. Funnily enough, this
* is not captured in the JSON file, but only as a note in the
* ARM ARM.
@@ -295,17 +294,27 @@ static bool feat_sme_smps(struct kvm *kvm)
static bool feat_spe_fds(struct kvm *kvm)
{
/*
* Revists this if KVM ever supports SPE -- this really should
* Revisit this if KVM ever supports SPE -- this really should
* look at the guest's view of PMSIDR_EL1.
*/
return (kvm_has_feat(kvm, FEAT_SPEv1p4) &&
(read_sysreg_s(SYS_PMSIDR_EL1) & PMSIDR_EL1_FDS));
}
static bool feat_spe_fne(struct kvm *kvm)
{
/*
* Revisit this if KVM ever supports SPE -- this really should
* look at the guest's view of PMSIDR_EL1.
*/
return (kvm_has_feat(kvm, FEAT_SPEv1p2) &&
(read_sysreg_s(SYS_PMSIDR_EL1) & PMSIDR_EL1_FnE));
}
static bool feat_trbe_mpam(struct kvm *kvm)
{
/*
* Revists this if KVM ever supports both MPAM and TRBE --
* Revisit this if KVM ever supports both MPAM and TRBE --
* this really should look at the guest's view of TRBIDR_EL1.
*/
return (kvm_has_feat(kvm, FEAT_TRBE) &&
@@ -537,7 +546,7 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
HDFGRTR_EL2_PMBPTR_EL1 |
HDFGRTR_EL2_PMBLIMITR_EL1,
FEAT_SPE),
NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE),
NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, feat_spe_fne),
NEEDS_FEAT(HDFGRTR_EL2_nBRBDATA |
HDFGRTR_EL2_nBRBCTL |
HDFGRTR_EL2_nBRBIDR,
@@ -605,7 +614,7 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
HDFGWTR_EL2_PMBPTR_EL1 |
HDFGWTR_EL2_PMBLIMITR_EL1,
FEAT_SPE),
NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE),
NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, feat_spe_fne),
NEEDS_FEAT(HDFGWTR_EL2_nBRBDATA |
HDFGWTR_EL2_nBRBCTL,
FEAT_BRBE),

View File

@@ -709,6 +709,14 @@ static const hcall_t host_hcall[] = {
HANDLE_FUNC(__kvm_tlb_flush_vmid_range),
HANDLE_FUNC(__kvm_flush_cpu_context),
HANDLE_FUNC(__kvm_timer_set_cntvoff),
HANDLE_FUNC(__tracing_load),
HANDLE_FUNC(__tracing_unload),
HANDLE_FUNC(__tracing_enable),
HANDLE_FUNC(__tracing_swap_reader),
HANDLE_FUNC(__tracing_update_clock),
HANDLE_FUNC(__tracing_reset),
HANDLE_FUNC(__tracing_enable_event),
HANDLE_FUNC(__tracing_write_event),
HANDLE_FUNC(__vgic_v3_save_aprs),
HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
HANDLE_FUNC(__vgic_v5_save_apr),
@@ -735,22 +743,16 @@ static const hcall_t host_hcall[] = {
HANDLE_FUNC(__pkvm_vcpu_load),
HANDLE_FUNC(__pkvm_vcpu_put),
HANDLE_FUNC(__pkvm_tlb_flush_vmid),
HANDLE_FUNC(__tracing_load),
HANDLE_FUNC(__tracing_unload),
HANDLE_FUNC(__tracing_enable),
HANDLE_FUNC(__tracing_swap_reader),
HANDLE_FUNC(__tracing_update_clock),
HANDLE_FUNC(__tracing_reset),
HANDLE_FUNC(__tracing_enable_event),
HANDLE_FUNC(__tracing_write_event),
};
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(unsigned long, id, host_ctxt, 0);
unsigned long hcall_min = 0, hcall_max = -1;
unsigned long hcall_min = 0, hcall_max = __KVM_HOST_SMCCC_FUNC_MAX;
hcall_t hfn;
BUILD_BUG_ON(ARRAY_SIZE(host_hcall) != __KVM_HOST_SMCCC_FUNC_MAX);
/*
* If pKVM has been initialised then reject any calls to the
* early "privileged" hypercalls. Note that we cannot reject
@@ -763,16 +765,14 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
if (static_branch_unlikely(&kvm_protected_mode_initialized)) {
hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM;
} else {
hcall_max = __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM;
hcall_max = __KVM_HOST_SMCCC_FUNC_PKVM_ONLY;
}
id &= ~ARM_SMCCC_CALL_HINTS;
id -= KVM_HOST_SMCCC_ID(0);
if (unlikely(id < hcall_min || id > hcall_max ||
id >= ARRAY_SIZE(host_hcall))) {
if (unlikely(id < hcall_min || id >= hcall_max))
goto inval;
}
hfn = host_hcall[id];
if (unlikely(!hfn))
@@ -805,6 +805,10 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
}
func_id &= ~ARM_SMCCC_CALL_HINTS;
if (upper_32_bits(func_id)) {
cpu_reg(host_ctxt, 0) = SMCCC_RET_NOT_SUPPORTED;
goto exit_skip_instr;
}
handled = kvm_host_psci_handler(host_ctxt, func_id);
if (!handled)

View File

@@ -266,7 +266,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle,
if (hyp_vm->kvm.created_vcpus <= vcpu_idx)
goto unlock;
hyp_vcpu = hyp_vm->vcpus[vcpu_idx];
/* Pairs with smp_store_release() in register_hyp_vcpu(). */
hyp_vcpu = smp_load_acquire(&hyp_vm->vcpus[vcpu_idx]);
if (!hyp_vcpu)
goto unlock;
@@ -860,12 +861,30 @@ int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
* the page-aligned size of 'struct pkvm_hyp_vcpu'.
* Return 0 on success, negative error code on failure.
*/
static int register_hyp_vcpu(struct pkvm_hyp_vm *hyp_vm,
struct pkvm_hyp_vcpu *hyp_vcpu)
{
unsigned int idx = hyp_vcpu->vcpu.vcpu_idx;
if (idx >= hyp_vm->kvm.created_vcpus)
return -EINVAL;
if (hyp_vm->vcpus[idx])
return -EINVAL;
/*
* Ensure the hyp_vcpu is initialised before publishing it to
* the vCPU-load path via 'hyp_vm->vcpus[]'.
*/
smp_store_release(&hyp_vm->vcpus[idx], hyp_vcpu);
return 0;
}
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
unsigned long vcpu_hva)
{
struct pkvm_hyp_vcpu *hyp_vcpu;
struct pkvm_hyp_vm *hyp_vm;
unsigned int idx;
int ret;
hyp_vcpu = map_donated_memory(vcpu_hva, sizeof(*hyp_vcpu));
@@ -884,18 +903,11 @@ int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
if (ret)
goto unlock;
idx = hyp_vcpu->vcpu.vcpu_idx;
if (idx >= hyp_vm->kvm.created_vcpus) {
ret = -EINVAL;
goto unlock;
ret = register_hyp_vcpu(hyp_vm, hyp_vcpu);
if (ret) {
unpin_host_vcpu(host_vcpu);
unpin_host_sve_state(hyp_vcpu);
}
if (hyp_vm->vcpus[idx]) {
ret = -EINVAL;
goto unlock;
}
hyp_vm->vcpus[idx] = hyp_vcpu;
unlock:
hyp_spin_unlock(&vm_table_lock);

View File

@@ -312,10 +312,6 @@ void __noreturn __pkvm_init_finalise(void)
};
pkvm_pgtable.mm_ops = &pkvm_pgtable_mm_ops;
ret = fix_host_ownership();
if (ret)
goto out;
ret = fix_hyp_pgtable_refcnt();
if (ret)
goto out;
@@ -324,6 +320,10 @@ void __noreturn __pkvm_init_finalise(void)
if (ret)
goto out;
ret = fix_host_ownership();
if (ret)
goto out;
ret = hyp_ffa_init(ffa_proxy_pages);
if (ret)
goto out;

View File

@@ -91,7 +91,7 @@ static int vgic_mmio_uaccess_write_v2_misc(struct kvm_vcpu *vcpu,
* migration from old kernels to new kernels with legacy
* userspace.
*/
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val);
switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:

View File

@@ -194,7 +194,7 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
if ((reg ^ val) & ~GICD_IIDR_REVISION_MASK)
return -EINVAL;
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, reg);
reg = FIELD_GET(GICD_IIDR_REVISION_MASK, val);
switch (reg) {
case KVM_VGIC_IMP_REV_2:
case KVM_VGIC_IMP_REV_3:

View File

@@ -459,19 +459,11 @@ static void pata_parport_dev_release(struct device *dev)
kfree(pi);
}
static void pata_parport_bus_release(struct device *dev)
{
/* nothing to do here but required to avoid warning on device removal */
}
static const struct bus_type pata_parport_bus_type = {
.name = DRV_NAME,
};
static struct device pata_parport_bus = {
.init_name = DRV_NAME,
.release = pata_parport_bus_release,
};
static struct device *pata_parport_bus;
static const struct scsi_host_template pata_parport_sht = {
PATA_PARPORT_SHT("pata_parport")
@@ -518,7 +510,7 @@ static struct pi_adapter *pi_init_one(struct parport *parport,
}
/* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
pi->dev.parent = &pata_parport_bus;
pi->dev.parent = pata_parport_bus;
pi->dev.bus = &pata_parport_bus_type;
pi->dev.driver = &pr->driver;
pi->dev.release = pata_parport_dev_release;
@@ -780,8 +772,9 @@ static __init int pata_parport_init(void)
return error;
}
error = device_register(&pata_parport_bus);
if (error) {
pata_parport_bus = root_device_register(DRV_NAME);
if (IS_ERR(pata_parport_bus)) {
error = PTR_ERR(pata_parport_bus);
pr_err("failed to register pata_parport bus, error: %d\n", error);
goto out_unregister_bus;
}
@@ -811,7 +804,7 @@ static __init int pata_parport_init(void)
out_remove_new:
bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
out_unregister_dev:
device_unregister(&pata_parport_bus);
root_device_unregister(pata_parport_bus);
out_unregister_bus:
bus_unregister(&pata_parport_bus_type);
return error;
@@ -822,7 +815,7 @@ static __exit void pata_parport_exit(void)
parport_unregister_driver(&pata_parport_driver);
bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
device_unregister(&pata_parport_bus);
root_device_unregister(pata_parport_bus);
bus_unregister(&pata_parport_bus_type);
}

View File

@@ -927,11 +927,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin)
return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin);
}
/**
* __dpll_pin_change_ntf - notify that the pin has been changed
* @pin: registered pin pointer
*
* Context: caller must hold dpll_lock. Suitable for use inside pin
* callbacks which are already invoked under dpll_lock.
* Return: 0 if succeeds, error code otherwise.
*/
int __dpll_pin_change_ntf(struct dpll_pin *pin)
{
lockdep_assert_held(&dpll_lock);
dpll_pin_notify(pin, DPLL_PIN_CHANGED);
return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin);
}
EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf);
/**
* dpll_pin_change_ntf - notify that the pin has been changed

View File

@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll);
int dpll_pin_create_ntf(struct dpll_pin *pin);
int dpll_pin_delete_ntf(struct dpll_pin *pin);
int __dpll_pin_change_ntf(struct dpll_pin *pin);

View File

@@ -12,8 +12,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include "mailbox.h"
/*
* The maximum transmission size is 32 words or 128 bytes.
*/
@@ -405,7 +403,7 @@ static int cix_mbox_startup(struct mbox_chan *chan)
int index = cp->index, ret;
u32 val;
ret = request_irq(priv->irq, cix_mbox_isr, 0,
ret = request_irq(priv->irq, cix_mbox_isr, IRQF_NO_SUSPEND,
dev_name(priv->dev), chan);
if (ret) {
dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq);
@@ -415,7 +413,7 @@ static int cix_mbox_startup(struct mbox_chan *chan)
switch (cp->type) {
case CIX_MBOX_TYPE_DB:
/* Overwrite txdone_method for DB channel */
chan->txdone_method = TXDONE_BY_ACK;
chan->txdone_method = MBOX_TXDONE_BY_ACK;
fallthrough;
case CIX_MBOX_TYPE_REG:
if (priv->dir == CIX_MBOX_TX) {

View File

@@ -99,7 +99,6 @@ static int exynos_mbox_probe(struct platform_device *pdev)
struct mbox_controller *mbox;
struct mbox_chan *chans;
struct clk *pclk;
int i;
exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL);
if (!exynos_mbox)
@@ -129,9 +128,6 @@ static int exynos_mbox_probe(struct platform_device *pdev)
mbox->ops = &exynos_mbox_chan_ops;
mbox->of_xlate = exynos_mbox_of_xlate;
for (i = 0; i < EXYNOS_MBOX_CHAN_COUNT; i++)
chans[i].mbox = mbox;
exynos_mbox->mbox = mbox;
platform_set_drvdata(pdev, exynos_mbox);

View File

@@ -15,8 +15,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "mailbox.h"
#define MBOX_CHAN_MAX 32
#define MBOX_RX 0x0

View File

@@ -79,12 +79,12 @@ struct hi6220_mbox {
/* region for mailbox */
void __iomem *base;
unsigned int chan_num;
struct hi6220_mbox_chan *mchan;
void *irq_map_chan[MBOX_CHAN_MAX];
struct mbox_chan *chan;
struct mbox_controller controller;
unsigned int chan_num;
struct hi6220_mbox_chan mchan[] __counted_by(chan_num);
};
static void mbox_set_state(struct hi6220_mbox *mbox,
@@ -267,16 +267,12 @@ static int hi6220_mbox_probe(struct platform_device *pdev)
struct hi6220_mbox *mbox;
int i, err;
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
mbox = devm_kzalloc(dev, struct_size(mbox, mchan, MBOX_CHAN_MAX), GFP_KERNEL);
if (!mbox)
return -ENOMEM;
mbox->dev = dev;
mbox->chan_num = MBOX_CHAN_MAX;
mbox->mchan = devm_kcalloc(dev,
mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL);
if (!mbox->mchan)
return -ENOMEM;
mbox->dev = dev;
mbox->chan = devm_kcalloc(dev,
mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL);

View File

@@ -23,8 +23,6 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include "mailbox.h"
#define IMX_MU_CHANS 24
/* TX0/RX0/RXDB[0-3] */
#define IMX_MU_SCU_CHANS 6
@@ -734,7 +732,7 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
p_chan = &mbox->chans[chan];
if (type == IMX_MU_TYPE_TXDB_V2)
p_chan->txdone_method = TXDONE_BY_ACK;
p_chan->txdone_method = MBOX_TXDONE_BY_ACK;
return p_chan;
}

View File

@@ -21,8 +21,6 @@
#include <linux/property.h>
#include <linux/slab.h>
#include "mailbox.h"
#define STI_MBOX_INST_MAX 4 /* RAM saving: Max supported instances */
#define STI_MBOX_CHAN_MAX 20 /* RAM saving: Max supported channels */

View File

@@ -28,8 +28,6 @@
#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \
(MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
static bool mbox_data_ready;
struct mbox_test_device {
struct device *dev;
void __iomem *tx_mmio;
@@ -42,6 +40,7 @@ struct mbox_test_device {
spinlock_t lock;
struct mutex mutex;
wait_queue_head_t waitq;
bool data_ready;
struct fasync_struct *async_queue;
struct dentry *root_debugfs_dir;
};
@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
unsigned long flags;
spin_lock_irqsave(&tdev->lock, flags);
data_ready = mbox_data_ready;
data_ready = tdev->data_ready;
spin_unlock_irqrestore(&tdev->lock, flags);
return data_ready;
@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
*(touser + l) = '\0';
memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
mbox_data_ready = false;
tdev->data_ready = false;
spin_unlock_irqrestore(&tdev->lock, flags);
@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message)
message, MBOX_MAX_MSG_LEN);
memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
}
mbox_data_ready = true;
tdev->data_ready = true;
spin_unlock_irqrestore(&tdev->lock, flags);
wake_up_interruptible(&tdev->waitq);
@@ -336,7 +335,7 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name)
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
if (!client)
return ERR_PTR(-ENOMEM);
return NULL;
client->dev = &pdev->dev;
client->rx_callback = mbox_test_receive_message;
@@ -355,67 +354,80 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name)
return channel;
}
static void __iomem *mbox_test_ioremap(struct platform_device *pdev, unsigned int res_num)
{
struct resource *res;
void __iomem *mmio;
res = platform_get_resource(pdev, IORESOURCE_MEM, res_num);
if (!res)
return NULL;
mmio = devm_ioremap_resource(&pdev->dev, res);
if (PTR_ERR(mmio) == -EBUSY) {
dev_info(&pdev->dev, "trying workaround with plain ioremap\n");
return devm_ioremap(&pdev->dev, res->start, resource_size(res));
}
return IS_ERR(mmio) ? NULL : mmio;
}
static int mbox_test_probe(struct platform_device *pdev)
{
struct mbox_test_device *tdev;
struct resource *res;
resource_size_t size;
int ret;
tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
if (!tdev)
return -ENOMEM;
tdev->dev = &pdev->dev;
spin_lock_init(&tdev->lock);
mutex_init(&tdev->mutex);
init_waitqueue_head(&tdev->waitq);
platform_set_drvdata(pdev, tdev);
/* It's okay for MMIO to be NULL */
tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
/* if reserved area in SRAM, try just ioremap */
size = resource_size(res);
tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
} else if (IS_ERR(tdev->tx_mmio)) {
tdev->tx_mmio = NULL;
}
tdev->tx_mmio = mbox_test_ioremap(pdev, 0);
/* If specified, second reg entry is Rx MMIO */
tdev->rx_mmio = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
size = resource_size(res);
tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
} else if (IS_ERR(tdev->rx_mmio)) {
tdev->rx_mmio = mbox_test_ioremap(pdev, 1);
if (!tdev->rx_mmio)
tdev->rx_mmio = tdev->tx_mmio;
}
tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
if (IS_ERR_OR_NULL(tdev->tx_channel) && IS_ERR_OR_NULL(tdev->rx_channel))
if (!tdev->tx_channel && !tdev->rx_channel)
return -EPROBE_DEFER;
/* If Rx is not specified but has Rx MMIO, then Rx = Tx */
if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
tdev->rx_channel = tdev->tx_channel;
tdev->dev = &pdev->dev;
platform_set_drvdata(pdev, tdev);
spin_lock_init(&tdev->lock);
mutex_init(&tdev->mutex);
if (tdev->rx_channel) {
tdev->rx_buffer = devm_kzalloc(&pdev->dev,
MBOX_MAX_MSG_LEN, GFP_KERNEL);
if (!tdev->rx_buffer)
return -ENOMEM;
if (!tdev->rx_buffer) {
ret = -ENOMEM;
goto err_free_chans;
}
}
ret = mbox_test_add_debugfs(pdev, tdev);
if (ret)
return ret;
goto err_free_chans;
init_waitqueue_head(&tdev->waitq);
dev_info(&pdev->dev, "Successfully registered\n");
return 0;
err_free_chans:
if (tdev->tx_channel)
mbox_free_channel(tdev->tx_channel);
if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)
mbox_free_channel(tdev->rx_channel);
return ret;
}
static void mbox_test_remove(struct platform_device *pdev)
@@ -426,7 +438,7 @@ static void mbox_test_remove(struct platform_device *pdev)
if (tdev->tx_channel)
mbox_free_channel(tdev->tx_channel);
if (tdev->rx_channel)
if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)
mbox_free_channel(tdev->rx_channel);
}

View File

@@ -18,8 +18,6 @@
#include <linux/property.h>
#include <linux/spinlock.h>
#include "mailbox.h"
static LIST_HEAD(mbox_cons);
static DEFINE_MUTEX(con_mutex);
@@ -52,7 +50,7 @@ static void msg_submit(struct mbox_chan *chan)
int err = -EBUSY;
scoped_guard(spinlock_irqsave, &chan->lock) {
if (!chan->msg_count || chan->active_req)
if (!chan->msg_count || chan->active_req != MBOX_NO_MSG)
break;
count = chan->msg_count;
@@ -74,7 +72,7 @@ static void msg_submit(struct mbox_chan *chan)
}
}
if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
if (!err && (chan->txdone_method & MBOX_TXDONE_BY_POLL)) {
/* kick start the timer immediately to avoid delays */
scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock)
hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
@@ -87,13 +85,13 @@ static void tx_tick(struct mbox_chan *chan, int r)
scoped_guard(spinlock_irqsave, &chan->lock) {
mssg = chan->active_req;
chan->active_req = NULL;
chan->active_req = MBOX_NO_MSG;
}
/* Submit next message */
msg_submit(chan);
if (!mssg)
if (mssg == MBOX_NO_MSG)
return;
/* Notify the client */
@@ -114,7 +112,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
for (i = 0; i < mbox->num_chans; i++) {
struct mbox_chan *chan = &mbox->chans[i];
if (chan->active_req && chan->cl) {
if (chan->active_req != MBOX_NO_MSG && chan->cl) {
txdone = chan->mbox->ops->last_tx_done(chan);
if (txdone)
tx_tick(chan, 0);
@@ -164,7 +162,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data);
*/
void mbox_chan_txdone(struct mbox_chan *chan, int r)
{
if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) {
if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_IRQ))) {
dev_err(chan->mbox->dev,
"Controller can't run the TX ticker\n");
return;
@@ -185,7 +183,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone);
*/
void mbox_client_txdone(struct mbox_chan *chan, int r)
{
if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) {
if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_ACK))) {
dev_err(chan->mbox->dev, "Client can't run the TX ticker\n");
return;
}
@@ -218,6 +216,29 @@ bool mbox_client_peek_data(struct mbox_chan *chan)
}
EXPORT_SYMBOL_GPL(mbox_client_peek_data);
/**
* mbox_chan_tx_slots_available - Query the number of available TX queue slots.
* @chan: Mailbox channel to query.
*
* Clients may call this to check how many messages can be queued via
* mbox_send_message() before the channel's TX queue is full. This helps
* clients avoid the -ENOBUFS error without needing to increase
* MBOX_TX_QUEUE_LEN.
* This can be called from atomic context.
*
* Return: Number of available slots in the channel's TX queue.
*/
unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan)
{
unsigned int ret;
guard(spinlock_irqsave)(&chan->lock);
ret = MBOX_TX_QUEUE_LEN - chan->msg_count;
return ret;
}
EXPORT_SYMBOL_GPL(mbox_chan_tx_slots_available);
/**
* mbox_send_message - For client to submit a message to be
* sent to the remote.
@@ -246,7 +267,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
{
int t;
if (!chan || !chan->cl)
if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
return -EINVAL;
t = add_to_rbuf(chan, mssg);
@@ -319,12 +340,12 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
scoped_guard(spinlock_irqsave, &chan->lock) {
chan->msg_free = 0;
chan->msg_count = 0;
chan->active_req = NULL;
chan->active_req = MBOX_NO_MSG;
chan->cl = cl;
init_completion(&chan->tx_complete);
if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
chan->txdone_method = TXDONE_BY_ACK;
if (chan->txdone_method == MBOX_TXDONE_BY_POLL && cl->knows_txdone)
chan->txdone_method = MBOX_TXDONE_BY_ACK;
}
if (chan->mbox->ops->startup) {
@@ -341,7 +362,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
}
/**
* mbox_bind_client - Request a mailbox channel.
* mbox_bind_client - Bind client to a mailbox channel.
* @chan: The mailbox channel to bind the client to.
* @cl: Identity of the client requesting the channel.
*
@@ -477,9 +498,9 @@ void mbox_free_channel(struct mbox_chan *chan)
/* The queued TX requests are simply aborted, no callbacks are made */
scoped_guard(spinlock_irqsave, &chan->lock) {
chan->cl = NULL;
chan->active_req = NULL;
if (chan->txdone_method == TXDONE_BY_ACK)
chan->txdone_method = TXDONE_BY_POLL;
chan->active_req = MBOX_NO_MSG;
if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
chan->txdone_method = MBOX_TXDONE_BY_POLL;
}
module_put(chan->mbox->dev->driver->owner);
@@ -505,18 +526,17 @@ int mbox_controller_register(struct mbox_controller *mbox)
{
int i, txdone;
/* Sanity check */
if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans)
if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans)
return -EINVAL;
if (mbox->txdone_irq)
txdone = TXDONE_BY_IRQ;
txdone = MBOX_TXDONE_BY_IRQ;
else if (mbox->txdone_poll)
txdone = TXDONE_BY_POLL;
txdone = MBOX_TXDONE_BY_POLL;
else /* It has to be ACK then */
txdone = TXDONE_BY_ACK;
txdone = MBOX_TXDONE_BY_ACK;
if (txdone == TXDONE_BY_POLL) {
if (txdone == MBOX_TXDONE_BY_POLL) {
if (!mbox->ops->last_tx_done) {
dev_err(mbox->dev, "last_tx_done method is absent\n");
@@ -532,6 +552,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
chan->cl = NULL;
chan->mbox = mbox;
chan->active_req = MBOX_NO_MSG;
chan->txdone_method = txdone;
spin_lock_init(&chan->lock);
}

View File

@@ -1,12 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __MAILBOX_H
#define __MAILBOX_H
#include <linux/bits.h>
#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
#define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */
#endif /* __MAILBOX_H */

View File

@@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
if (curr_pa == end_pa - CMDQ_INST_SIZE ||
curr_pa == end_pa) {
/* set to this task directly */
writel(task->pa_base >> cmdq->pdata->shift,
thread->base + CMDQ_THR_CURR_ADDR);
gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata);
writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR);
} else {
cmdq_task_insert_into_thread(task);
smp_mb(); /* modify jump before enable thread */
}
writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift,
thread->base + CMDQ_THR_END_ADDR);
gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata);
writel(gce_addr, thread->base + CMDQ_THR_END_ADDR);
cmdq_thread_resume(thread);
}
list_move_tail(&task->list_entry, &thread->task_busy_list);
@@ -728,7 +728,7 @@ static int cmdq_probe(struct platform_device *pdev)
cmdq->mbox.ops = &cmdq_mbox_chan_ops;
cmdq->mbox.of_xlate = cmdq_xlate;
/* make use of TXDONE_BY_ACK */
/* make use of MBOX_TXDONE_BY_ACK */
cmdq->mbox.txdone_irq = false;
cmdq->mbox.txdone_poll = false;

View File

@@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *sp)
{
if (sp->args_count)
return NULL;
return ERR_PTR(-EINVAL);
return &mbox->chans[0];
}

View File

@@ -22,8 +22,6 @@
#include <linux/pm_runtime.h>
#include <linux/mailbox_controller.h>
#include "mailbox.h"
#define MAILBOX_REVISION 0x000
#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
@@ -240,7 +238,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
}
if (mbox->send_no_irq)
mbox->chan->txdone_method = TXDONE_BY_ACK;
mbox->chan->txdone_method = MBOX_TXDONE_BY_ACK;
omap_mbox_enable_irq(mbox, IRQ_RX);

View File

@@ -59,8 +59,6 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <acpi/pcc.h>
#include "mailbox.h"
#define MBOX_IRQ_NAME "pcc-mbox"
/**

View File

@@ -46,7 +46,7 @@ struct rockchip_mbox {
/* The maximum size of buf for each channel */
u32 buf_size;
struct rockchip_mbox_chan *chans;
struct rockchip_mbox_chan chans[];
};
static int rockchip_mbox_send_data(struct mbox_chan *chan, void *data)
@@ -173,15 +173,10 @@ static int rockchip_mbox_probe(struct platform_device *pdev)
drv_data = (const struct rockchip_mbox_data *) device_get_match_data(&pdev->dev);
mb = devm_kzalloc(&pdev->dev, sizeof(*mb), GFP_KERNEL);
mb = devm_kzalloc(&pdev->dev, struct_size(mb, chans, drv_data->num_chans), GFP_KERNEL);
if (!mb)
return -ENOMEM;
mb->chans = devm_kcalloc(&pdev->dev, drv_data->num_chans,
sizeof(*mb->chans), GFP_KERNEL);
if (!mb->chans)
return -ENOMEM;
mb->mbox.chans = devm_kcalloc(&pdev->dev, drv_data->num_chans,
sizeof(*mb->mbox.chans), GFP_KERNEL);
if (!mb->mbox.chans)

View File

@@ -16,8 +16,6 @@
#include <dt-bindings/mailbox/tegra186-hsp.h>
#include "mailbox.h"
#define HSP_INT_IE(x) (0x100 + ((x) * 4))
#define HSP_INT_IV 0x300
#define HSP_INT_IR 0x304
@@ -497,7 +495,7 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan,
mbox_chan_txdone(chan, 0);
/* Wait until channel is empty */
if (chan->active_req != NULL)
if (chan->active_req != MBOX_NO_MSG)
continue;
return 0;
@@ -516,7 +514,7 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan)
struct tegra_hsp *hsp = mb->channel.hsp;
unsigned long flags;
chan->txdone_method = TXDONE_BY_IRQ;
chan->txdone_method = MBOX_TXDONE_BY_IRQ;
/*
* Shared mailboxes start out as consumers by default. FULL and EMPTY

View File

@@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s,
if (le32_to_cpu(n->header.nr_entries) == 1) {
struct dm_block *child;
int is_shared;
dm_block_t b = value64(n, 0);
r = dm_tm_block_is_shared(info->tm, b, &is_shared);
if (r)
return r;
r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child);
if (r)
return r;
if (is_shared)
inc_children(info->tm, dm_block_data(child), vt);
memcpy(n, dm_block_data(child),
dm_bm_block_size(dm_tm_get_bm(info->tm)));

View File

@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,
struct in6_addr saddr;
struct socket *sock = rcu_dereference(bareudp->sock);
if (!sock)
return -ESHUTDOWN;
dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock,
0, &saddr, &info->key,
sport, bareudp->port, info->key.tos,

View File

@@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port)
static void ad_mux_machine(struct port *port, bool *update_slave_arr)
{
struct bonding *bond = __get_bond_by_port(port);
struct aggregator *aggregator;
mux_states_t last_state;
/* keep current State Machine state to compare later if it was
@@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
*/
last_state = port->sm_mux_state;
aggregator = rcu_dereference(port->aggregator);
if (port->sm_vars & AD_PORT_BEGIN) {
port->sm_mux_state = AD_MUX_DETACHED;
} else {
@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* cycle to update ready variable, we check
* READY_N and update READY here
*/
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
port->sm_mux_state = AD_MUX_DETACHED;
break;
}
@@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* update ready variable, we check READY_N and update
* READY here
*/
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
/* if the wait_while_timer expired, and the port is
* in READY state, move to ATTACHED state
@@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
if ((port->sm_vars & AD_PORT_SELECTED) &&
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
!__check_agg_selection_timer(port)) {
if (port->aggregator->is_active) {
if (aggregator->is_active) {
int state = AD_MUX_COLLECTING_DISTRIBUTING;
if (!bond->params.coupled_control)
@@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* cycle to update ready variable, we check
* READY_N and update READY here
*/
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
port->sm_mux_state = AD_MUX_DETACHED;
} else if (port->aggregator->is_active) {
} else if (aggregator->is_active) {
port->actor_oper_port_state |=
LACP_STATE_SYNCHRONIZATION;
}
@@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* sure that a collecting distributing
* port in an active aggregator is enabled
*/
if (port->aggregator->is_active &&
if (aggregator->is_active &&
!__port_is_collecting_distributing(port)) {
__enable_port(port);
*update_slave_arr = true;
@@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
*/
struct slave *slave = port->slave;
if (port->aggregator->is_active &&
if (aggregator->is_active &&
bond_is_slave_rx_disabled(slave)) {
ad_enable_collecting(port);
*update_slave_arr = true;
@@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
* sure that a collecting distributing
* port in an active aggregator is enabled
*/
if (port->aggregator &&
port->aggregator->is_active &&
if (aggregator &&
aggregator->is_active &&
!__port_is_collecting_distributing(port)) {
__enable_port(port);
*update_slave_arr = true;
@@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
break;
case AD_MUX_ATTACHED:
if (port->aggregator->is_active)
if (aggregator->is_active)
port->actor_oper_port_state |=
LACP_STATE_SYNCHRONIZATION;
else
@@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
bond = __get_bond_by_port(port);
/* if the port is connected to other aggregator, detach it */
if (port->aggregator) {
temp_aggregator = rcu_dereference(port->aggregator);
if (temp_aggregator) {
/* detach the port from its former aggregator */
temp_aggregator = port->aggregator;
for (curr_port = temp_aggregator->lag_ports; curr_port;
last_port = curr_port,
curr_port = curr_port->next_port_in_aggregator) {
@@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
/* clear the port's relations to this
* aggregator
*/
port->aggregator = NULL;
RCU_INIT_POINTER(port->aggregator, NULL);
port->next_port_in_aggregator = NULL;
port->actor_port_aggregator_identifier = 0;
@@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
port->slave->bond->dev->name,
port->slave->dev->name,
port->actor_port_number,
port->aggregator->aggregator_identifier);
temp_aggregator->aggregator_identifier);
}
}
/* search on all aggregators for a suitable aggregator for this port */
@@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
)
) {
/* attach to the founded aggregator */
port->aggregator = aggregator;
rcu_assign_pointer(port->aggregator, aggregator);
port->actor_port_aggregator_identifier =
port->aggregator->aggregator_identifier;
aggregator->aggregator_identifier;
port->next_port_in_aggregator = aggregator->lag_ports;
port->aggregator->num_of_ports++;
aggregator->num_of_ports++;
aggregator->lag_ports = port;
slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
aggregator->aggregator_identifier);
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
@@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
if (!found) {
if (free_aggregator) {
/* assign port a new aggregator */
port->aggregator = free_aggregator;
port->actor_port_aggregator_identifier =
port->aggregator->aggregator_identifier;
free_aggregator->aggregator_identifier;
/* update the new aggregator's parameters
* if port was responsed from the end-user
*/
if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
/* if port is full duplex */
port->aggregator->is_individual = false;
free_aggregator->is_individual = false;
else
port->aggregator->is_individual = true;
free_aggregator->is_individual = true;
port->aggregator->actor_admin_aggregator_key =
free_aggregator->actor_admin_aggregator_key =
port->actor_admin_port_key;
port->aggregator->actor_oper_aggregator_key =
free_aggregator->actor_oper_aggregator_key =
port->actor_oper_port_key;
port->aggregator->partner_system =
free_aggregator->partner_system =
port->partner_oper.system;
port->aggregator->partner_system_priority =
free_aggregator->partner_system_priority =
port->partner_oper.system_priority;
port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
port->aggregator->receive_state = 1;
port->aggregator->transmit_state = 1;
port->aggregator->lag_ports = port;
port->aggregator->num_of_ports++;
free_aggregator->partner_oper_aggregator_key = port->partner_oper.key;
free_aggregator->receive_state = 1;
free_aggregator->transmit_state = 1;
free_aggregator->lag_ports = port;
free_aggregator->num_of_ports++;
rcu_assign_pointer(port->aggregator, free_aggregator);
/* mark this port as selected */
port->sm_vars |= AD_PORT_SELECTED;
slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
free_aggregator->aggregator_identifier);
} else {
slave_err(bond->dev, port->slave->dev,
"Port %d did not find a suitable aggregator\n",
@@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
* in all aggregator's ports, else set ready=FALSE in all
* aggregator's ports
*/
__set_agg_ports_ready(port->aggregator,
__agg_ports_are_ready(port->aggregator));
aggregator = rcu_dereference(port->aggregator);
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
aggregator = __get_first_agg(port);
ad_agg_selection_logic(aggregator, update_slave_arr);
ad_agg_selection_logic(__get_first_agg(port), update_slave_arr);
if (!port->aggregator->is_active)
if (!aggregator->is_active)
port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
}
@@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond
*/
static void ad_enable_collecting(struct port *port)
{
if (port->aggregator->is_active) {
struct aggregator *aggregator = rcu_dereference(port->aggregator);
if (aggregator->is_active) {
struct slave *slave = port->slave;
slave_dbg(slave->bond->dev, slave->dev,
"Enabling collecting on port %d (LAG %d)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
aggregator->aggregator_identifier);
__enable_collecting_port(port);
}
}
@@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port)
*/
static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
{
if (port->aggregator && __agg_has_partner(port->aggregator)) {
struct aggregator *aggregator = rcu_dereference(port->aggregator);
if (aggregator && __agg_has_partner(aggregator)) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Disabling distributing on port %d (LAG %d)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
aggregator->aggregator_identifier);
__disable_distributing_port(port);
/* Slave array needs an update */
*update_slave_arr = true;
@@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
static void ad_enable_collecting_distributing(struct port *port,
bool *update_slave_arr)
{
if (port->aggregator->is_active) {
struct aggregator *aggregator = rcu_dereference(port->aggregator);
if (aggregator->is_active) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Enabling port %d (LAG %d)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
aggregator->aggregator_identifier);
__enable_port(port);
/* Slave array needs update */
*update_slave_arr = true;
@@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port,
static void ad_disable_collecting_distributing(struct port *port,
bool *update_slave_arr)
{
if (port->aggregator && __agg_has_partner(port->aggregator)) {
struct aggregator *aggregator = rcu_dereference(port->aggregator);
if (aggregator && __agg_has_partner(aggregator)) {
slave_dbg(port->slave->bond->dev, port->slave->dev,
"Disabling port %d (LAG %d)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
aggregator->aggregator_identifier);
__disable_port(port);
/* Slave array needs an update */
*update_slave_arr = true;
@@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
*/
for (temp_port = aggregator->lag_ports; temp_port;
temp_port = temp_port->next_port_in_aggregator) {
temp_port->aggregator = new_aggregator;
rcu_assign_pointer(temp_port->aggregator, new_aggregator);
temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
}
@@ -2848,15 +2858,16 @@ int bond_3ad_set_carrier(struct bonding *bond)
int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct ad_info *ad_info)
{
struct aggregator *aggregator = NULL;
struct aggregator *aggregator = NULL, *tmp;
struct list_head *iter;
struct slave *slave;
struct port *port;
bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave)->port);
if (port->aggregator && port->aggregator->is_active) {
aggregator = port->aggregator;
tmp = rcu_dereference(port->aggregator);
if (tmp && tmp->is_active) {
aggregator = tmp;
break;
}
}

View File

@@ -1433,7 +1433,7 @@ static void bond_poll_controller(struct net_device *bond_dev)
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct aggregator *agg =
SLAVE_AD_INFO(slave)->port.aggregator;
rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (agg &&
agg->aggregator_identifier != ad_info.aggregator_id)
@@ -5179,15 +5179,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
spin_unlock_bh(&bond->mode_lock);
agg_id = ad_info.aggregator_id;
}
rcu_read_lock();
bond_for_each_slave(bond, slave, iter) {
if (skipslave == slave)
continue;
all_slaves->arr[all_slaves->count++] = slave;
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct aggregator *agg;
const struct aggregator *agg;
agg = SLAVE_AD_INFO(slave)->port.aggregator;
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (!agg || agg->aggregator_identifier != agg_id)
continue;
}
@@ -5199,6 +5200,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
usable_slaves->arr[usable_slaves->count++] = slave;
}
rcu_read_unlock();
bond_set_slave_arr(bond, usable_slaves, all_slaves);
return ret;

View File

@@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb,
const struct port *ad_port;
ad_port = &SLAVE_AD_INFO(slave)->port;
agg = SLAVE_AD_INFO(slave)->port.aggregator;
rcu_read_lock();
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (agg) {
if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
agg->aggregator_identifier))
goto nla_put_failure;
goto nla_put_failure_rcu;
if (nla_put_u8(skb,
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
ad_port->actor_oper_port_state))
goto nla_put_failure;
goto nla_put_failure_rcu;
if (nla_put_u16(skb,
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
ad_port->partner_oper.port_state))
goto nla_put_failure;
goto nla_put_failure_rcu;
if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE,
ad_port->sm_churn_actor_state))
goto nla_put_failure;
goto nla_put_failure_rcu;
if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE,
ad_port->sm_churn_partner_state))
goto nla_put_failure;
goto nla_put_failure_rcu;
}
rcu_read_unlock();
if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
SLAVE_AD_INFO(slave)->port_priority))
@@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb,
return 0;
nla_put_failure_rcu:
rcu_read_unlock();
nla_put_failure:
return -EMSGSIZE;
}

View File

@@ -188,6 +188,7 @@ static void bond_info_show_master(struct seq_file *seq)
}
}
/* Note: runs under rcu_read_lock() */
static void bond_info_show_slave(struct seq_file *seq,
const struct slave *slave)
{
@@ -214,7 +215,7 @@ static void bond_info_show_slave(struct seq_file *seq,
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
const struct port *port = &SLAVE_AD_INFO(slave)->port;
const struct aggregator *agg = port->aggregator;
const struct aggregator *agg = rcu_dereference(port->aggregator);
if (agg) {
seq_printf(seq, "Aggregator ID: %d\n",

View File

@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
const struct aggregator *agg;
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
agg = SLAVE_AD_INFO(slave)->port.aggregator;
if (agg)
return sysfs_emit(buf, "%d\n",
agg->aggregator_identifier);
rcu_read_lock();
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
if (agg) {
ssize_t res = sysfs_emit(buf, "%d\n",
agg->aggregator_identifier);
rcu_read_unlock();
return res;
}
rcu_read_unlock();
}
return sysfs_emit(buf, "N/A\n");
@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
ad_port = &SLAVE_AD_INFO(slave)->port;
if (ad_port->aggregator)
if (rcu_access_pointer(ad_port->aggregator))
return sysfs_emit(buf, "%u\n",
ad_port->actor_oper_port_state);
}
@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
ad_port = &SLAVE_AD_INFO(slave)->port;
if (ad_port->aggregator)
if (rcu_access_pointer(ad_port->aggregator))
return sysfs_emit(buf, "%u\n",
ad_port->partner_oper.port_state);
}

View File

@@ -847,13 +847,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
{
struct airoha_qdma *qdma = q->qdma;
struct airoha_eth *eth = qdma->eth;
int i;
int i, qid = q - &qdma->q_tx[0];
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
struct airoha_gdm_port *port = eth->ports[i];
int j;
if (port && port->qdma == qdma)
netif_tx_wake_all_queues(port->dev);
if (!port)
continue;
if (port->qdma != qdma)
continue;
for (j = 0; j < port->dev->num_tx_queues; j++) {
if (airoha_qdma_get_txq(qdma, j) != qid)
continue;
netif_wake_subqueue(port->dev, j);
}
}
q->txq_stopped = false;
}
@@ -929,10 +940,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
q->queued--;
if (skb) {
u16 queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq;
txq = netdev_get_tx_queue(skb->dev, queue);
txq = skb_get_tx_queue(skb->dev, skb);
netdev_tx_completed_queue(txq, 1, skb->len);
dev_kfree_skb_any(skb);
}
@@ -1737,14 +1747,11 @@ static int airoha_dev_stop(struct net_device *dev)
{
struct airoha_gdm_port *port = netdev_priv(dev);
struct airoha_qdma *qdma = port->qdma;
int i, err;
int i;
netif_tx_disable(dev);
err = airoha_set_vip_for_gdm_port(port, false);
if (err)
return err;
for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++)
airoha_set_vip_for_gdm_port(port, false);
for (i = 0; i < dev->num_tx_queues; i++)
netdev_tx_reset_subqueue(dev, i);
airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id),
@@ -1997,12 +2004,12 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
struct airoha_queue *q;
LIST_HEAD(tx_list);
int i = 0, qid;
void *data;
int i, qid;
u16 index;
u8 fport;
qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx);
qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
tag = airoha_get_dsa_tag(skb, dev);
msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
@@ -2039,7 +2046,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
spin_lock_bh(&q->lock);
txq = netdev_get_tx_queue(dev, qid);
txq = skb_get_tx_queue(dev, skb);
nr_frags = 1 + skb_shinfo(skb)->nr_frags;
if (q->queued + nr_frags >= q->ndesc) {
@@ -2057,7 +2064,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
list);
index = e - q->entry;
for (i = 0; i < nr_frags; i++) {
while (true) {
struct airoha_qdma_desc *desc = &q->desc[index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr_t addr;
@@ -2069,7 +2076,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
goto error_unmap;
list_move_tail(&e->list, &tx_list);
e->skb = i ? NULL : skb;
e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
e->dma_len = len;
@@ -2088,6 +2095,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff));
if (++i == nr_frags)
break;
data = skb_frag_address(frag);
len = skb_frag_size(frag);
}
@@ -2095,17 +2105,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
skb_tx_timestamp(skb);
netdev_tx_sent_queue(txq, skb->len);
if (q->ndesc - q->queued < q->free_thr) {
netif_tx_stop_queue(txq);
q->txq_stopped = true;
}
if (netif_xmit_stopped(txq) || !netdev_xmit_more())
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
if (q->ndesc - q->queued < q->free_thr) {
netif_tx_stop_queue(txq);
q->txq_stopped = true;
}
spin_unlock_bh(&q->lock);
return NETDEV_TX_OK;

View File

@@ -631,6 +631,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);
#define airoha_qdma_clear(qdma, offset, val) \
airoha_rmw((qdma)->regs, (offset), (val), 0)
static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid)
{
return qid % ARRAY_SIZE(qdma->q_tx);
}
static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port)
{
/* GDM1 port on EN7581 SoC is connected to the lan dsa switch.

View File

@@ -1756,6 +1756,27 @@ static int ibmveth_set_mac_addr(struct net_device *dev, void *p)
return 0;
}
static netdev_features_t ibmveth_features_check(struct sk_buff *skb,
struct net_device *dev,
netdev_features_t features)
{
/* Some physical adapters do not support segmentation offload with
* MSS < 224. Disable GSO for such packets to avoid adapter freeze.
* Note: Single-segment packets (gso_segs == 1) don't need this check
* as they bypass the LSO path and are transmitted without segmentation.
*/
if (skb_is_gso(skb)) {
if (skb_shinfo(skb)->gso_size < IBMVETH_MIN_LSO_MSS) {
netdev_warn_once(dev,
"MSS %u too small for LSO, disabling GSO\n",
skb_shinfo(skb)->gso_size);
features &= ~NETIF_F_GSO_MASK;
}
}
return vlan_features_check(skb, features);
}
static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_open = ibmveth_open,
.ndo_stop = ibmveth_close,
@@ -1767,6 +1788,7 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_set_features = ibmveth_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ibmveth_set_mac_addr,
.ndo_features_check = ibmveth_features_check,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ibmveth_poll_controller,
#endif

View File

@@ -37,6 +37,7 @@
#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL
#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL
#define IBMVETH_MIN_LSO_MSS 224 /* Minimum MSS for LSO */
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)

View File

@@ -158,11 +158,10 @@ struct iavf_vlan {
enum iavf_vlan_state_t {
IAVF_VLAN_INVALID,
IAVF_VLAN_ADD, /* filter needs to be added */
IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */
IAVF_VLAN_ACTIVE, /* filter is accepted by PF */
IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */
IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */
IAVF_VLAN_REMOVE, /* filter needs to be removed from list */
IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
};
struct iavf_vlan_filter {

View File

@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
/* Re-add the filter since we cannot tell whether the
* pending delete has already been processed by the PF.
* A duplicate add is harmless.
*/
/* DEL not yet sent to PF, cancel it */
f->state = IAVF_VLAN_ACTIVE;
} else if (f->state == IAVF_VLAN_REMOVING) {
/* DEL already sent to PF, re-add after completion */
f->state = IAVF_VLAN_ADD;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_ADD_VLAN_FILTER);
@@ -791,37 +791,19 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
} else {
} else if (f->state != IAVF_VLAN_REMOVING) {
f->state = IAVF_VLAN_REMOVE;
iavf_schedule_aq_request(adapter,
IAVF_FLAG_AQ_DEL_VLAN_FILTER);
}
/* If REMOVING, DEL is already sent to PF; completion
* handler will free the filter when PF confirms.
*/
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
/**
* iavf_restore_filters
* @adapter: board private structure
*
* Restore existing non MAC filters when VF netdev comes back up
**/
static void iavf_restore_filters(struct iavf_adapter *adapter)
{
struct iavf_vlan_filter *f;
/* re-add all VLAN filters */
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_INACTIVE)
f->state = IAVF_VLAN_ADD;
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
}
/**
* iavf_get_num_vlans_added - get number of VLANs added
@@ -1246,13 +1228,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
}
/**
* iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF
* yet and mark other to be removed.
* iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark
* others to be removed.
* @adapter: board private structure
**/
static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
static void iavf_clear_mac_filters(struct iavf_adapter *adapter)
{
struct iavf_vlan_filter *vlf, *vlftmp;
struct iavf_mac_filter *f, *ftmp;
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -1271,11 +1252,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter)
}
}
/* disable all VLAN filters */
list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list,
list)
vlf->state = IAVF_VLAN_DISABLE;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
@@ -1371,7 +1347,7 @@ void iavf_down(struct iavf_adapter *adapter)
iavf_napi_disable_all(adapter);
iavf_irq_disable(adapter);
iavf_clear_mac_vlan_filters(adapter);
iavf_clear_mac_filters(adapter);
iavf_clear_cloud_filters(adapter);
iavf_clear_fdir_filters(adapter);
iavf_clear_adv_rss_conf(adapter);
@@ -1388,8 +1364,6 @@ void iavf_down(struct iavf_adapter *adapter)
*/
if (!list_empty(&adapter->mac_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
if (!list_empty(&adapter->vlan_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER;
if (!list_empty(&adapter->cloud_filter_list))
adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER;
if (!list_empty(&adapter->fdir_list_head))
@@ -4494,8 +4468,6 @@ static int iavf_open(struct net_device *netdev)
iavf_add_filter(adapter, adapter->hw.mac.addr);
spin_unlock_bh(&adapter->mac_vlan_list_lock);
/* Restore filters that were removed with IFF_DOWN */
iavf_restore_filters(adapter);
iavf_restore_fdir_filters(adapter);
iavf_configure(adapter);

View File

@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_IS_NEW) {
if (f->state == IAVF_VLAN_ADDING) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
@@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
if (f->state == IAVF_VLAN_ADD) {
vvfl->vlan_id[i] = f->vlan.vid;
i++;
f->state = IAVF_VLAN_IS_NEW;
f->state = IAVF_VLAN_ADDING;
if (i == count)
break;
}
@@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
vlan->tpid = f->vlan.tpid;
i++;
f->state = IAVF_VLAN_IS_NEW;
f->state = IAVF_VLAN_ADDING;
}
}
@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
/* since VLAN capabilities are not allowed, we dont want to send
* a VLAN delete request because it will most likely fail and
* create unnecessary errors/noise, so just free the VLAN
* filters marked for removal to enable bailing out before
* sending a virtchnl message
*/
if (f->state == IAVF_VLAN_REMOVE &&
!VLAN_FILTERING_ALLOWED(adapter)) {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
} else if (f->state == IAVF_VLAN_DISABLE &&
!VLAN_FILTERING_ALLOWED(adapter)) {
f->state = IAVF_VLAN_INACTIVE;
} else if (f->state == IAVF_VLAN_REMOVE ||
f->state == IAVF_VLAN_DISABLE) {
} else if (f->state == IAVF_VLAN_REMOVE) {
count++;
}
}
@@ -958,18 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_DISABLE) {
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_REMOVE) {
vvfl->vlan_id[i] = f->vlan.vid;
f->state = IAVF_VLAN_INACTIVE;
i++;
if (i == count)
break;
} else if (f->state == IAVF_VLAN_REMOVE) {
vvfl->vlan_id[i] = f->vlan.vid;
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -1006,9 +988,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
vvfl_v2->num_elements = count;
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_DISABLE ||
f->state == IAVF_VLAN_REMOVE) {
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_REMOVE) {
struct virtchnl_vlan_supported_caps *filtering_support =
&adapter->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan;
@@ -1022,13 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
vlan->tci = f->vlan.vid;
vlan->tpid = f->vlan.tpid;
if (f->state == IAVF_VLAN_DISABLE) {
f->state = IAVF_VLAN_INACTIVE;
} else {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
}
f->state = IAVF_VLAN_REMOVING;
i++;
if (i == count)
break;
@@ -2391,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_DEL_VLAN:
dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
iavf_stat_str(&adapter->hw, v_retval));
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
iavf_stat_str(&adapter->hw, v_retval));
@@ -2905,17 +2876,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
spin_unlock_bh(&adapter->adv_rss_lock);
}
break;
case VIRTCHNL_OP_ADD_VLAN:
case VIRTCHNL_OP_ADD_VLAN_V2: {
struct iavf_vlan_filter *f;
if (v_retval)
break;
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->state == IAVF_VLAN_IS_NEW)
if (f->state == IAVF_VLAN_ADDING)
f->state = IAVF_VLAN_ACTIVE;
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
break;
case VIRTCHNL_OP_DEL_VLAN:
case VIRTCHNL_OP_DEL_VLAN_V2: {
struct iavf_vlan_filter *f, *ftmp;
spin_lock_bh(&adapter->mac_vlan_list_lock);
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list,
list) {
if (f->state == IAVF_VLAN_REMOVING) {
if (v_retval) {
/* PF rejected DEL, keep filter */
f->state = IAVF_VLAN_ACTIVE;
} else {
list_del(&f->list);
kfree(f);
adapter->num_vlan_filters--;
}
}
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
}
break;
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
/* PF enabled vlan strip on this VF.
* Update netdev->features if needed to be in sync with ethtool.

View File

@@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
return err;
}
ice_init_dev_hw(pf);
/* load MSI-X values */
ice_set_min_max_msix(pf);

View File

@@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_fltr_mgmt_struct;
ice_init_dev_hw(hw->back);
mutex_init(&hw->tnl_lock);
ice_init_chk_recipe_reuse_support(hw);

View File

@@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv,
extack, ICE_DPLL_PIN_TYPE_INPUT);
}
/**
* ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change
* @d: pointer to dplls struct
* @changed: the SW pin that was explicitly changed (already notified by dpll core)
*
* SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and
* SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO
* expander, the paired pin's state may also change. Send a change
* notification for the peer pin so userspace consumers monitoring the
* peer via dpll netlink learn about the update.
*
* Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is
* released. Uses __dpll_pin_change_ntf() because dpll_lock is
* still held by the dpll netlink layer.
*/
static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d,
struct ice_dpll_pin *changed)
{
struct ice_dpll_pin *peer;
peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ?
&d->ufl[changed->idx] : &d->sma[changed->idx];
if (peer->pin)
__dpll_pin_change_ntf(peer->pin);
}
/**
* ice_dpll_sma_direction_set - set direction of SMA pin
* @p: pointer to a pin
@@ -1171,6 +1197,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
enum dpll_pin_direction direction,
struct netlink_ext_ack *extack)
{
struct ice_dplls *d = &p->pf->dplls;
struct ice_dpll_pin *peer;
u8 data;
int ret;
@@ -1189,8 +1217,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
case ICE_DPLL_PIN_SW_2_IDX:
if (direction == DPLL_PIN_DIRECTION_INPUT) {
data &= ~ICE_SMA2_DIR_EN;
data |= ICE_SMA2_UFL2_RX_DIS;
} else {
data &= ~ICE_SMA2_TX_EN;
data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS);
data |= ICE_SMA2_DIR_EN;
}
break;
@@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p,
ret = ice_dpll_pin_state_update(p->pf, p,
ICE_DPLL_PIN_TYPE_SOFTWARE,
extack);
if (ret)
return ret;
/* When a direction change activates the paired U.FL pin, enable
* its backing CGU pin so the pin reports as connected. Without
* this the U.FL routing is correct but the CGU pin stays disabled
* and userspace sees the pin as disconnected. Do not disable the
* backing pin when U.FL becomes inactive because the SMA pin may
* still be using it.
*/
peer = &d->ufl[p->idx];
if (peer->active) {
struct ice_dpll_pin *target;
enum ice_dpll_pin_type type;
if (peer->output) {
target = peer->output;
type = ICE_DPLL_PIN_TYPE_OUTPUT;
} else {
target = peer->input;
type = ICE_DPLL_PIN_TYPE_INPUT;
}
ret = ice_dpll_pin_enable(&p->pf->hw, target,
d->eec.dpll_idx, type, extack);
if (!ret)
ret = ice_dpll_pin_state_update(p->pf, target,
type, extack);
}
return ret;
}
@@ -1253,6 +1310,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA1_MASK;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
/* Skip if U.FL1 is not active, setting TX_EN
* while DIR_EN is set would also deactivate
* the paired SMA1 output.
*/
if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) {
ret = 0;
goto unlock;
}
data |= ICE_SMA1_TX_EN;
enable = false;
} else {
@@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
data &= ~ICE_SMA2_UFL2_RX_DIS;
enable = true;
} else if (state == DPLL_PIN_STATE_DISCONNECTED) {
/* Skip if U.FL2 is not active, setting
* UFL2_RX_DIS could also disable the paired
* SMA2 input.
*/
if (!(data & ICE_SMA2_DIR_EN) ||
(data & ICE_SMA2_UFL2_RX_DIS)) {
ret = 0;
goto unlock;
}
data |= ICE_SMA2_UFL2_RX_DIS;
enable = false;
} else {
@@ -1296,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
if (!ret)
ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1414,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
unlock:
mutex_unlock(&pf->dplls.lock);
if (!ret)
ice_dpll_sw_pin_notify_peer(&pf->dplls, sma);
return ret;
}
@@ -1609,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv,
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_sma_direction_set(p, direction, extack);
mutex_unlock(&pf->dplls.lock);
if (!ret)
ice_dpll_sw_pin_notify_peer(&pf->dplls, p);
return ret;
}
@@ -1915,7 +1995,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv,
d->active_input == p->input->pin))
*phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
else if (d->phase_offset_monitor_period)
*phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR;
*phase_offset = (p->input &&
p->direction == DPLL_PIN_DIRECTION_INPUT ?
p->input->phase_offset :
p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR;
else
*phase_offset = 0;
mutex_unlock(&pf->dplls.lock);
@@ -2609,6 +2692,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
return pci_get_dsn(pf->pdev);
}
/**
* ice_dpll_pin_ntf - notify pin change including any SW pin wrappers
* @dplls: pointer to dplls struct
* @pin: the dpll_pin that changed
*
* Send a change notification for @pin and for any registered SMA/U.FL pin
* whose backing CGU input matches @pin.
*/
static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin)
{
dpll_pin_change_ntf(pin);
for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) {
if (dplls->sma[i].pin && dplls->sma[i].input &&
dplls->sma[i].input->pin == pin)
dpll_pin_change_ntf(dplls->sma[i].pin);
if (dplls->ufl[i].pin && dplls->ufl[i].input &&
dplls->ufl[i].input->pin == pin)
dpll_pin_change_ntf(dplls->ufl[i].pin);
}
}
/**
* ice_dpll_notify_changes - notify dpll subsystem about changes
* @d: pointer do dpll
@@ -2617,6 +2721,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf)
*/
static void ice_dpll_notify_changes(struct ice_dpll *d)
{
struct ice_dplls *dplls = &d->pf->dplls;
bool pin_notified = false;
if (d->prev_dpll_state != d->dpll_state) {
@@ -2625,17 +2730,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d)
}
if (d->prev_input != d->active_input) {
if (d->prev_input)
dpll_pin_change_ntf(d->prev_input);
ice_dpll_pin_ntf(dplls, d->prev_input);
d->prev_input = d->active_input;
if (d->active_input) {
dpll_pin_change_ntf(d->active_input);
ice_dpll_pin_ntf(dplls, d->active_input);
pin_notified = true;
}
}
if (d->prev_phase_offset != d->phase_offset) {
d->prev_phase_offset = d->phase_offset;
if (!pin_notified && d->active_input)
dpll_pin_change_ntf(d->active_input);
ice_dpll_pin_ntf(dplls, d->active_input);
}
}
@@ -2664,6 +2769,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
/**
* ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes
* @dplls: pointer to dplls struct
* @pins: array of ice_dpll_pin pointers registered within dpll subsystem
* @pin_num: number of pins
* @phase_offset_ntf_mask: bitmask of pin indexes to notify
@@ -2673,15 +2779,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf)
*
* Context: Must be called while pf->dplls.lock is released.
*/
static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins,
static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls,
struct ice_dpll_pin *pins,
u8 pin_num,
u32 phase_offset_ntf_mask)
{
int i = 0;
for (i = 0; i < pin_num; i++)
if (phase_offset_ntf_mask & (1 << i))
dpll_pin_change_ntf(pins[i].pin);
for (int i = 0; i < pin_num; i++)
if (phase_offset_ntf_mask & BIT(i))
ice_dpll_pin_ntf(dplls, pins[i].pin);
}
/**
@@ -2857,7 +2962,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
ice_dpll_notify_changes(de);
ice_dpll_notify_changes(dp);
if (phase_offset_ntf)
ice_dpll_pins_notify_mask(d->inputs, d->num_inputs,
ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs,
phase_offset_ntf);
resched:
@@ -4014,6 +4119,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
struct ice_dpll_pin *pin;
u32 phase_adj_max, caps;
int i, ret;
u8 data;
if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP)
input_idx_offset = ICE_E810_RCLK_PINS_NUM;
@@ -4073,6 +4179,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf)
}
ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max);
}
/* Initialize the SMA control register to a known-good default state.
* Without this write the PCA9575 GPIO expander retains its power-on
* default (all outputs high) which makes all SW pins appear inactive.
* Set SMA1 and SMA2 as active inputs, disable U.FL1 output and
* U.FL2 input.
*/
ret = ice_read_sma_ctrl(&pf->hw, &data);
if (ret)
return ret;
data &= ~ICE_ALL_SMA_MASK;
data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS;
ret = ice_write_sma_ctrl(&pf->hw, data);
if (ret)
return ret;
ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE,
NULL);
if (ret)

View File

@@ -5245,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
return err;
}
ice_init_dev_hw(pf);
adapter = ice_adapter_get(pdev);
if (IS_ERR(adapter)) {
err = PTR_ERR(adapter);

View File

@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_vf_ctrl_invalidate_vsi(vf);
ice_vf_pre_vsi_rebuild(vf);
ice_vf_rebuild_vsi(vf);
if (ice_vf_rebuild_vsi(vf)) {
dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n",
vf->vf_id);
mutex_unlock(&vf->cfg_lock);
continue;
}
ice_vf_post_vsi_rebuild(vf);
ice_eswitch_attach_vf(pf, vf);

View File

@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx,
if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) {
netif_err(efx, drv, efx->net_dev,
"mcdi MC_CMD_GET_VERSION failed\n");
return rc;
return rc ?: -EIO;
}
/* Handle previous output */

View File

@@ -5549,9 +5549,12 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
break;
/* Prefetch the next RX descriptor */
rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
priv->dma_conf.dma_rx_size);
next_entry = rx_q->cur_rx;
next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
priv->dma_conf.dma_rx_size);
if (unlikely(next_entry == rx_q->dirty_rx))
break;
rx_q->cur_rx = next_entry;
np = stmmac_get_rx_desc(priv, rx_q, next_entry);
@@ -5686,7 +5689,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
dma_dir = page_pool_get_dma_dir(rx_q->page_pool);
bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE;
limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit);
if (netif_msg_rx_status(priv)) {
void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0);
@@ -5733,9 +5735,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
if (unlikely(status & dma_own))
break;
rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
priv->dma_conf.dma_rx_size);
next_entry = rx_q->cur_rx;
next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx,
priv->dma_conf.dma_rx_size);
if (unlikely(next_entry == rx_q->dirty_rx))
break;
rx_q->cur_rx = next_entry;
np = stmmac_get_rx_desc(priv, rx_q, next_entry);

View File

@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
u8 *pecp;
int rc;
fs = mctp_i2c_get_tx_flow_state(midev, skb);
hdr = (void *)skb_mac_header(skb);
/* Sanity check that packet contents matches skb length,
* and can't exceed MCTP_I2C_BUFSZ
@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
return;
}
fs = mctp_i2c_get_tx_flow_state(midev, skb);
if (skb_tailroom(skb) >= 1) {
/* Linear case with space, we can just append the PEC */
skb_put(skb, 1);

View File

@@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item,
unregister_netcons_consoles();
}
ret = strnlen(buf, count);
ret = count;
/* Deferred cleanup */
netconsole_process_cleanups();
out_unlock:
@@ -781,7 +781,7 @@ static ssize_t release_store(struct config_item *item, const char *buf,
nt->release = release;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->extended = extended;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,
size_t count)
{
struct netconsole_target *nt = to_target(item);
size_t len = count;
/* Account for a trailing newline appended by tools like echo */
if (len && buf[len - 1] == '\n')
len--;
if (len >= IFNAMSIZ)
return -ENAMETOOLONG;
dynamic_netconsole_mutex_lock();
if (nt->state == STATE_ENABLED) {
@@ -830,7 +837,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,
trim_newline(nt->np.dev_name, IFNAMSIZ);
dynamic_netconsole_mutex_unlock();
return strnlen(buf, count);
return count;
}
static ssize_t local_port_store(struct config_item *item, const char *buf,
@@ -849,7 +856,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,
ret = kstrtou16(buf, 10, &nt->np.local_port);
if (ret < 0)
goto out_unlock;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -871,7 +878,7 @@ static ssize_t remote_port_store(struct config_item *item,
ret = kstrtou16(buf, 10, &nt->np.remote_port);
if (ret < 0)
goto out_unlock;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -896,7 +903,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->np.ipv6 = !!ipv6;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -921,7 +928,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
nt->np.ipv6 = !!ipv6;
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -957,7 +964,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,
goto out_unlock;
memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
ret = strnlen(buf, count);
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
return ret;
@@ -1072,26 +1079,30 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
size_t count)
{
struct userdatum *udm = to_userdatum(item);
char old_value[MAX_EXTRADATA_VALUE_LEN];
struct netconsole_target *nt;
struct userdata *ud;
ssize_t ret;
if (count > MAX_EXTRADATA_VALUE_LEN)
if (count >= MAX_EXTRADATA_VALUE_LEN)
return -EMSGSIZE;
mutex_lock(&netconsole_subsys.su_mutex);
dynamic_netconsole_mutex_lock();
ret = strscpy(udm->value, buf, sizeof(udm->value));
if (ret < 0)
goto out_unlock;
/* Snapshot for rollback if update_userdata() fails below */
strscpy(old_value, udm->value, sizeof(old_value));
/* count is bounded above, so strscpy() cannot truncate here */
strscpy(udm->value, buf, sizeof(udm->value));
trim_newline(udm->value, sizeof(udm->value));
ud = to_userdata(item->ci_parent);
nt = userdata_to_target(ud);
ret = update_userdata(nt);
if (ret < 0)
if (ret < 0) {
/* Restore the previous value so it matches the live payload */
strscpy(udm->value, old_value, sizeof(udm->value));
goto out_unlock;
}
ret = count;
out_unlock:
dynamic_netconsole_mutex_unlock();
@@ -1133,7 +1144,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_MSGID);
unlock_ok:
ret = strnlen(buf, count);
ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1162,7 +1173,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_RELEASE);
unlock_ok:
ret = strnlen(buf, count);
ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1191,7 +1202,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_TASKNAME);
unlock_ok:
ret = strnlen(buf, count);
ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;
@@ -1225,7 +1236,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item,
disable_sysdata_feature(nt, SYSDATA_CPU_NR);
unlock_ok:
ret = strnlen(buf, count);
ret = count;
dynamic_netconsole_mutex_unlock();
mutex_unlock(&netconsole_subsys.su_mutex);
return ret;

View File

@@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void)
skb->protocol = htons(ETH_P_IP);
skb_set_network_header(skb, skb->len);
iph = skb_put(skb, sizeof(struct iphdr));
iph = skb_put_zero(skb, sizeof(struct iphdr));
iph->protocol = IPPROTO_UDP;
iph->saddr = in_aton("192.0.2.1");
iph->daddr = in_aton("198.51.100.1");

View File

@@ -31,6 +31,7 @@
#define DP83869_RGMIICTL 0x0032
#define DP83869_STRAP_STS1 0x006e
#define DP83869_RGMIIDCTL 0x0086
#define DP83869_ANA_PLL_PROG_PI 0x00c6
#define DP83869_RXFCFG 0x0134
#define DP83869_RXFPMD1 0x0136
#define DP83869_RXFPMD2 0x0137
@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev)
dp83869_config_port_mirroring(phydev);
/* Clock output selection if muxing property is set */
if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK)
if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) {
/*
* Table 7-121 in datasheet says we have to set register 0xc6
* to value 0x10 before CLK_O_SEL can be modified.
*/
ret = phy_write_mmd(phydev, DP83869_DEVADDR,
DP83869_ANA_PLL_PROG_PI, 0x10);
if (ret)
return ret;
ret = phy_modify_mmd(phydev,
DP83869_DEVADDR, DP83869_IO_MUX_CFG,
DP83869_IO_MUX_CFG_CLK_O_SEL_MASK,
dp83869->clk_output_sel <<
DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT);
}
if (phy_interface_is_rgmii(phydev)) {
ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,

View File

@@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
unsigned int skb_len;
int count, res;
/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -694,6 +695,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
skb_len = skb->len;
netif_stop_queue(netdev);
dev->tx_skb = skb;
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -707,9 +710,16 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
/*
* The URB was not submitted, so write_bulk_callback() will
* never run to free dev->tx_skb. Drop the skb here and
* clear tx_skb to avoid leaving a stale pointer.
*/
dev->tx_skb = NULL;
dev_kfree_skb_any(skb);
} else {
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += skb->len;
netdev->stats.tx_bytes += skb_len;
netif_trans_update(netdev);
}

View File

@@ -1034,6 +1034,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
err:
port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
synchronize_net();
return ret;
}
@@ -1053,10 +1054,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev,
}
/* inverse of do_vrf_add_slave */
static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev,
bool needs_sync)
{
netdev_upper_dev_unlink(port_dev, dev);
port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE;
/* Make sure that concurrent RCU readers that identified the device
* as a VRF port see a VRF master or no master at all.
*/
if (needs_sync)
synchronize_net();
cycle_netdev(port_dev, NULL);
@@ -1065,7 +1072,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev)
{
return do_vrf_del_slave(dev, port_dev);
return do_vrf_del_slave(dev, port_dev, true);
}
static void vrf_dev_uninit(struct net_device *dev)
@@ -1619,7 +1626,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head)
struct list_head *iter;
netdev_for_each_lower_dev(dev, port_dev, iter)
vrf_del_slave(dev, port_dev);
do_vrf_del_slave(dev, port_dev, false);
vrf_map_unregister_dev(dev);
@@ -1751,7 +1758,7 @@ static int vrf_device_event(struct notifier_block *unused,
goto out;
vrf_dev = netdev_master_upper_dev_get(dev);
vrf_del_slave(vrf_dev, dev);
do_vrf_del_slave(vrf_dev, dev, false);
}
out:
return NOTIFY_DONE;

View File

@@ -317,6 +317,7 @@
#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))
#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))
#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6)
#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1
#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)
#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)
if (ret)
return ret;
if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK)
if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL)
*is_rf_field = true;
else
*is_rf_field = false;

View File

@@ -1620,6 +1620,12 @@ static void privcmd_close(struct vm_area_struct *vma)
kvfree(pages);
}
static int privcmd_may_split(struct vm_area_struct *area, unsigned long addr)
{
/* Forbid splitting, avoids double free via privcmd_close(). */
return -EINVAL;
}
static vm_fault_t privcmd_fault(struct vm_fault *vmf)
{
printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
@@ -1631,6 +1637,7 @@ static vm_fault_t privcmd_fault(struct vm_fault *vmf)
static const struct vm_operations_struct privcmd_vm_ops = {
.close = privcmd_close,
.may_split = privcmd_may_split,
.fault = privcmd_fault
};

View File

@@ -366,6 +366,8 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer)
ret = sprintf(buffer, "<denied>");
return ret;
}
if (ret > PAGE_SIZE)
return -ENOSPC;
buildid = kmalloc(sizeof(*buildid) + ret, GFP_KERNEL);
if (!buildid)
@@ -373,8 +375,10 @@ static ssize_t buildid_show(struct hyp_sysfs_attr *attr, char *buffer)
buildid->len = ret;
ret = HYPERVISOR_xen_version(XENVER_build_id, buildid);
if (ret > 0)
ret = sprintf(buffer, "%s", buildid->buf);
if (ret > 0) {
/* Build id is binary, not a string. */
memcpy(buffer, buildid->buf, ret);
}
kfree(buildid);
return ret;

View File

@@ -4641,7 +4641,8 @@ int try_release_extent_buffer(struct folio *folio)
* to read the block we will not block on anything.
*/
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level)
u64 bytenr, u64 owner_root, u64 gen, int level,
const struct btrfs_key *first_key)
{
struct btrfs_tree_parent_check check = {
.level = level,
@@ -4650,6 +4651,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb;
int ret;
if (first_key) {
memcpy(&check.first_key, first_key, sizeof(struct btrfs_key));
check.has_first_key = true;
}
eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
if (IS_ERR(eb))
return;
@@ -4677,9 +4683,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
*/
void btrfs_readahead_node_child(struct extent_buffer *node, int slot)
{
struct btrfs_key node_key;
btrfs_node_key_to_cpu(node, &node_key, slot);
btrfs_readahead_tree_block(node->fs_info,
btrfs_node_blockptr(node, slot),
btrfs_header_owner(node),
btrfs_node_ptr_generation(node, slot),
btrfs_header_level(node) - 1);
btrfs_header_level(node) - 1,
&node_key);
}

View File

@@ -287,7 +287,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
}
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 owner_root, u64 gen, int level);
u64 bytenr, u64 owner_root, u64 gen, int level,
const struct btrfs_key *first_key);
void btrfs_readahead_node_child(struct extent_buffer *node, int slot);
/* Note: this can be used in for loops without caching the value in a variable. */

View File

@@ -259,7 +259,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
ASSERT(0);
btrfs_err(fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
goto out;
}
}
@@ -405,7 +409,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
nr++;
} else {
ASSERT(0);
btrfs_err(fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
goto out;
}
}
@@ -1518,7 +1526,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
ASSERT(0);
btrfs_err(trans->fs_info, "unexpected free space tree key type %u",
found_key.type);
ret = -EUCLEAN;
btrfs_abort_transaction(trans, ret);
return ret;
}
}

View File

@@ -1153,7 +1153,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,
NULL, &cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW |
EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
PAGE_UNLOCK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
if (async_extent->cb)
@@ -4959,6 +4959,8 @@ static int btrfs_rmdir(struct inode *vfs_dir, struct dentry *dentry)
if (ret)
goto out;
btrfs_record_unlink_dir(trans, dir, inode, false);
/* now the directory is empty */
ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name);
if (!ret)

View File

@@ -5102,7 +5102,6 @@ static int btrfs_ioctl_subvol_sync(struct btrfs_fs_info *fs_info, void __user *a
return 0;
}
#ifdef CONFIG_BTRFS_EXPERIMENTAL
static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg)
{
int ret = 0;
@@ -5134,10 +5133,12 @@ static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg
case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH:
btrfs_force_shutdown(fs_info);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#endif
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
@@ -5294,10 +5295,8 @@ long btrfs_ioctl(struct file *file, unsigned int
#endif
case BTRFS_IOC_SUBVOL_SYNC_WAIT:
return btrfs_ioctl_subvol_sync(fs_info, argp);
#ifdef CONFIG_BTRFS_EXPERIMENTAL
case BTRFS_IOC_SHUTDOWN:
return btrfs_ioctl_shutdown(fs_info, arg);
#endif
}
return -ENOTTY;

View File

@@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans,
for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) {
struct btrfs_raid_stride *stride = &extent->strides[i];
u64 devid;
u64 phys;
devid = btrfs_raid_stride_devid(leaf, stride);
btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid);
phys = btrfs_raid_stride_physical(leaf, stride) + frontpad;
btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys);
}
@@ -95,14 +98,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
while (1) {
key.objectid = start;
key.type = BTRFS_RAID_STRIPE_KEY;
key.offset = 0;
key.offset = (u64)-1;
ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1);
if (ret < 0)
break;
if (path->slots[0] == btrfs_header_nritems(path->nodes[0]))
path->slots[0]--;
/*
* Search with offset=(u64)-1 ensures we land on the correct
* leaf even when the target entry is the first item on a leaf.
* Since no real entry has offset=(u64)-1, ret is always 1 and
* slot points past the last entry with objectid==start (or
* past the end of the leaf if that entry is the last item).
* Back up one slot to find the actual entry.
*/
if (path->slots[0] == 0) {
/* No entry with objectid <= start exists. */
ret = 0;
break;
}
path->slots[0]--;
leaf = path->nodes[0];
slot = path->slots[0];
@@ -123,7 +138,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
*/
if (found_start > start) {
if (slot == 0) {
ret = btrfs_previous_item(stripe_root, path, start,
ret = btrfs_previous_item(stripe_root, path, 0,
BTRFS_RAID_STRIPE_KEY);
if (ret) {
if (ret > 0)
@@ -139,7 +154,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
btrfs_item_key_to_cpu(leaf, &key, slot);
found_start = key.objectid;
found_end = found_start + key.offset;
ASSERT(found_start <= start);
if (found_start > start || found_end <= start) {
ret = -ENOENT;
break;
}
}
if (key.type != BTRFS_RAID_STRIPE_KEY)
@@ -176,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "right" item. */
ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey);
if (ret == -EAGAIN) {
btrfs_release_path(path);
continue;
}
if (ret)
break;
/*
* btrfs_duplicate_item() may have triggered a leaf
* split via setup_leaf_for_split(), so we must refresh
* our leaf pointer from the path.
*/
leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, path->slots[0]);
extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_stripe_extent);
@@ -195,8 +223,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "left" item. */
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
btrfs_partially_delete_raid_extent(trans, path, &key,
diff_start, 0);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
diff_start, 0);
break;
}
@@ -212,8 +241,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_start < start) {
u64 diff_start = start - found_start;
btrfs_partially_delete_raid_extent(trans, path, &key,
diff_start, 0);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
diff_start, 0);
if (ret)
break;
start += (key.offset - diff_start);
length -= (key.offset - diff_start);
@@ -236,9 +268,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_end > end) {
u64 diff_end = found_end - end;
btrfs_partially_delete_raid_extent(trans, path, &key,
key.offset - length,
length);
ret = btrfs_partially_delete_raid_extent(trans, path,
&key,
key.offset - length,
length);
ASSERT(key.offset - diff_end == length);
break;
}

View File

@@ -2607,7 +2607,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
if (!block->key_ready)
btrfs_readahead_tree_block(fs_info, block->bytenr,
block->owner, 0,
block->level);
block->level, NULL);
}
/* Get first keys */
@@ -3876,7 +3876,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs
ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch);
btrfs_release_path(path);
if (num_entries <= max_items)
if (ret || num_entries <= max_items)
break;
num_entries -= max_items;
@@ -4174,6 +4174,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,
return ret;
}
if (ins.offset < length) {
spin_lock(&sinfo->lock);
btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - length);
spin_unlock(&sinfo->lock);
}
dest_addr = ins.objectid;
dest_length = ins.offset;
@@ -5000,6 +5006,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
return ret;
}
if (ins.offset < remap_length) {
spin_lock(&sinfo->lock);
btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - remap_length);
spin_unlock(&sinfo->lock);
}
made_reservation = true;
new_addr = ins.objectid;
@@ -5023,21 +5035,27 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
if (bg_needs_free_space) {
ret = btrfs_add_block_group_free_space(trans, dest_bg);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
}
ret = copy_remapped_data(fs_info, start, new_addr, length);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
ret = btrfs_remove_from_free_space_tree(trans, new_addr, length);
if (ret)
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
}
ret = add_remap_entry(trans, path, src_bg, start, new_addr, length);
if (ret) {
btrfs_add_to_free_space_tree(trans, new_addr, length);
btrfs_abort_transaction(trans, ret);
goto fail;
}

View File

@@ -24,7 +24,7 @@ isofs_export_iget(struct super_block *sb,
{
struct inode *inode;
if (block == 0)
if (block == 0 || block >= ISOFS_SB(sb)->s_nzones)
return ERR_PTR(-ESTALE);
inode = isofs_iget(sb, block, offset);
if (IS_ERR(inode))

View File

@@ -10,20 +10,13 @@
#include <linux/gfp.h>
#include "isofs.h"
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use isofs_match. No big problem. Match also makes
* some sanity tests.
*/
static int
isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
{
struct qstr qstr;
qstr.name = compare;
qstr.len = dlen;
if (likely(!dentry->d_op))
return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name,
&QSTR_LEN(compare, dlen));
}
/*

View File

@@ -101,6 +101,15 @@ static int rock_continue(struct rock_state *rs)
goto out;
}
if ((unsigned)rs->cont_extent >= ISOFS_SB(rs->inode->i_sb)->s_nzones) {
printk(KERN_NOTICE "rock: corrupted directory entry. "
"extent=%u out of volume (nzones=%lu)\n",
(unsigned)rs->cont_extent,
ISOFS_SB(rs->inode->i_sb)->s_nzones);
ret = -EIO;
goto out;
}
if (rs->cont_extent) {
struct buffer_head *bh;

View File

@@ -457,7 +457,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
/*
* Unlike file_handle, type and len of struct fanotify_fh are u8.
* Traditionally, filesystem return handle_type < 0xff, but there
* is no enforecement for that in vfs.
* is no enforcement for that in vfs.
*/
BUILD_BUG_ON(MAX_HANDLE_SZ > 0xff || FILEID_INVALID > 0xff);
if (type <= 0 || type >= FILEID_INVALID || fh_len != dwords << 2)

View File

@@ -388,7 +388,7 @@ static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector
return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
}
static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
{
struct hlist_node *node = NULL;

View File

@@ -238,7 +238,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,
return inode;
}
static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
/*
* Calculate mask of events for a list of marks.
*
* Return true if any of the attached marks want to hold an inode reference.
*/
static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
{
u32 new_mask = 0;
bool want_iref = false;
@@ -262,6 +267,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
*/
WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask);
return want_iref;
}
/*
* Calculate mask of events for a list of marks after attach/modify mark
* and get an inode reference for the connector if needed.
*
* A concurrent add of evictable mark and detach of non-evictable mark can
* lead to __fsnotify_recalc_mask() returning false want_iref, but in this
* case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called
* from fsnotify_put_mark().
*/
static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn)
{
bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF;
bool want_iref = __fsnotify_recalc_mask(conn) || has_iref;
(void) fsnotify_update_iref(conn, want_iref);
}
/*
* Calculate mask of events for a list of marks after detach mark
* and return the inode object if its reference is no longer needed.
*/
static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn)
{
bool want_iref = __fsnotify_recalc_mask(conn);
return fsnotify_update_iref(conn, want_iref);
}
@@ -298,7 +331,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
spin_lock(&conn->lock);
update_children = !fsnotify_conn_watches_children(conn);
__fsnotify_recalc_mask(conn);
fsnotify_recalc_mask_set_iref(conn);
update_children &= fsnotify_conn_watches_children(conn);
spin_unlock(&conn->lock);
/*
@@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
/* Update watched objects after detaching mark */
if (sb)
fsnotify_update_sb_watchers(sb, conn);
objp = __fsnotify_recalc_mask(conn);
objp = fsnotify_recalc_mask_clear_iref(conn);
type = conn->type;
}
WRITE_ONCE(mark->connector, NULL);
@@ -457,9 +490,6 @@ EXPORT_SYMBOL_GPL(fsnotify_put_mark);
*/
static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
{
if (!mark)
return true;
if (refcount_inc_not_zero(&mark->refcnt)) {
spin_lock(&mark->lock);
if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) {
@@ -500,15 +530,22 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
int type;
fsnotify_foreach_iter_type(type) {
struct fsnotify_mark *mark = iter_info->marks[type];
/* This can fail if mark is being removed */
if (!fsnotify_get_mark_safe(iter_info->marks[type])) {
__release(&fsnotify_mark_srcu);
goto fail;
while (mark && !fsnotify_get_mark_safe(mark)) {
if (mark->group == iter_info->current_group) {
__release(&fsnotify_mark_srcu);
goto fail;
}
/* This is a mark in an unrelated group, skip */
mark = fsnotify_next_mark(mark);
iter_info->marks[type] = mark;
}
}
/*
* Now that both marks are pinned by refcount in the inode / vfsmount
* Now that all marks are pinned by refcount in the inode / vfsmount / etc
* lists, we can drop SRCU lock, and safely resume the list iteration
* once userspace returns.
*/

View File

@@ -230,8 +230,12 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
}
/* Verify the descriptor CRC */
if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize) {
udf_err(sb, "block %u: CRC length %u exceeds block size\n",
block, le16_to_cpu(tag_p->descCRCLength));
goto error_out;
}
if (le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
bh->b_data + sizeof(struct tag),
le16_to_cpu(tag_p->descCRCLength)))
return bh;

View File

@@ -292,6 +292,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin,
int dpll_device_change_ntf(struct dpll_device *dpll);
int __dpll_pin_change_ntf(struct dpll_pin *pin);
int dpll_pin_change_ntf(struct dpll_pin *pin);
int register_dpll_notifier(struct notifier_block *nb);

View File

@@ -915,6 +915,7 @@ extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
unsigned int obj_type);
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark);
extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info);
extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info);

View File

@@ -45,6 +45,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg);
int mbox_flush(struct mbox_chan *chan, unsigned long timeout);
void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
unsigned int mbox_chan_tx_slots_available(struct mbox_chan *chan); /* atomic */
void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
#endif /* __MAILBOX_CLIENT_H */

View File

@@ -3,6 +3,7 @@
#ifndef __MAILBOX_CONTROLLER_H
#define __MAILBOX_CONTROLLER_H
#include <linux/bits.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
@@ -11,6 +12,13 @@
struct mbox_chan;
/* Sentinel value distinguishing "no active request" from "NULL message data" */
#define MBOX_NO_MSG ((void *)-1)
#define MBOX_TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
#define MBOX_TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
#define MBOX_TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */
/**
* struct mbox_chan_ops - methods to control mailbox channels
* @send_data: The API asks the MBOX controller driver, in atomic
@@ -54,10 +62,10 @@ struct mbox_chan_ops {
/**
* struct mbox_controller - Controller of a class of communication channels
* @dev: Device backing this controller
* @ops: Operators that work on each communication chan
* @chans: Array of channels
* @num_chans: Number of channels in the 'chans' array.
* @dev: Device backing this controller. Required.
* @ops: Operators that work on each communication chan. Required.
* @chans: Array of channels. Required.
* @num_chans: Number of channels in the 'chans' array. Required.
* @txdone_irq: Indicates if the controller can report to API when
* the last transmitted data was read by the remote.
* Eg, if it has some TX ACK irq.
@@ -70,6 +78,7 @@ struct mbox_chan_ops {
* @of_xlate: Controller driver specific mapping of channel via DT
* @poll_hrt: API private. hrtimer used to poll for TXDONE on all
* channels.
* @poll_hrt_lock: API private. Lock protecting access to poll_hrt.
* @node: API private. To hook into list of controllers.
*/
struct mbox_controller {

View File

@@ -226,6 +226,7 @@ struct mr_table_ops {
/**
* struct mr_table - a multicast routing table
* @work: used for table destruction
* @list: entry within a list of multicast routing tables
* @net: net where this table belongs
* @ops: protocol specific operations
@@ -243,6 +244,7 @@ struct mr_table_ops {
* @mroute_reg_vif_num: PIM-device vif index
*/
struct mr_table {
struct rcu_work work;
struct list_head list;
possible_net_t net;
struct mr_table_ops ops;
@@ -274,6 +276,7 @@ void vif_device_init(struct vif_device *v,
unsigned short flags,
unsigned short get_iflink_mask);
void mr_table_free(struct mr_table *mrt);
struct mr_table *
mr_table_alloc(struct net *net, u32 id,
struct mr_table_ops *ops,

View File

@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old,
old->prev = LIST_POISON2;
}
static inline void __list_splice_rcu(struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
last->next = next;
first->prev = prev;
next->prev = last;
rcu_assign_pointer(list_next_rcu(prev), first);
}
/**
* list_splice_rcu - splice a non-RCU list into an RCU-protected list,
* designed for stacks.
* @list: the non RCU-protected list to splice
* @head: the place in the existing RCU-protected list to splice
*
* The list pointed to by @head can be RCU-read traversed concurrently with
* this function.
*/
static inline void list_splice_rcu(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice_rcu(list, head, head->next);
}
/**
* __list_splice_init_rcu - join an RCU-protected list into an existing list.
* @list: the RCU-protected list to splice

View File

@@ -12,6 +12,7 @@
#include <linux/alloc_tag.h>
#include <linux/atomic.h>
#include <linux/compiler.h>
#include <linux/irq_work_types.h>
#include <linux/mutex.h>
#include <linux/workqueue_types.h>
@@ -49,6 +50,7 @@ typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *arg,
* @head_offset: Offset of rhash_head in struct to be hashed
* @max_size: Maximum size while expanding
* @min_size: Minimum size while shrinking
* @insecure_elasticity: Set to true to disable chain length checks
* @automatic_shrinking: Enable automatic shrinking of tables
* @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash)
* @obj_hashfn: Function to hash object
@@ -61,6 +63,7 @@ struct rhashtable_params {
u16 head_offset;
unsigned int max_size;
u16 min_size;
bool insecure_elasticity;
bool automatic_shrinking;
rht_hashfn_t hashfn;
rht_obj_hashfn_t obj_hashfn;
@@ -75,6 +78,7 @@ struct rhashtable_params {
* @p: Configuration parameters
* @rhlist: True if this is an rhltable
* @run_work: Deferred worker to expand/shrink asynchronously
* @run_irq_work: Bounces the @run_work kick through hard IRQ context.
* @mutex: Mutex to protect current/future table swapping
* @lock: Spin lock to protect walker list
* @nelems: Number of elements in table
@@ -86,6 +90,7 @@ struct rhashtable {
struct rhashtable_params p;
bool rhlist;
struct work_struct run_work;
struct irq_work run_irq_work;
struct mutex mutex;
spinlock_t lock;
atomic_t nelems;

View File

@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/irq_work.h>
#include <linux/jhash.h>
#include <linux/list_nulls.h>
#include <linux/workqueue.h>
@@ -821,14 +822,15 @@ static __always_inline void *__rhashtable_insert_fast(
goto out;
}
if (elasticity <= 0)
if (elasticity <= 0 && !params.insecure_elasticity)
goto slow_path;
data = ERR_PTR(-E2BIG);
if (unlikely(rht_grow_above_max(ht, tbl)))
goto out_unlock;
if (unlikely(rht_grow_above_100(ht, tbl)))
if (unlikely(rht_grow_above_100(ht, tbl)) &&
!params.insecure_elasticity)
goto slow_path;
/* Inserting at head of list makes unlocking free. */
@@ -846,7 +848,7 @@ static __always_inline void *__rhashtable_insert_fast(
rht_assign_unlock(tbl, bkt, obj, flags);
if (rht_grow_above_75(ht, tbl))
schedule_work(&ht->run_work);
irq_work_queue(&ht->run_irq_work);
data = NULL;
out:

View File

@@ -202,7 +202,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
#define TP_CONDITION(args...) args
/*
* Individual subsystem my have a separate configuration to
* Individual subsystem may have a separate configuration to
* enable their tracepoints. By default, this file will create
* the tracepoints if CONFIG_TRACEPOINTS is defined. If a subsystem
* wants to be able to disable its tracepoints from being created

View File

@@ -243,7 +243,7 @@ typedef struct port {
churn_state_t sm_churn_actor_state;
churn_state_t sm_churn_partner_state;
struct slave *slave; /* pointer to the bond slave that this port belongs to */
struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */
struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
u32 transaction_id; /* continuous number for identification of Marker PDU's; */
struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */

View File

@@ -1204,12 +1204,15 @@ struct nft_stats {
struct u64_stats_sync syncp;
};
#define NFT_HOOK_REMOVE (1 << 0)
struct nft_hook {
struct list_head list;
struct list_head ops_list;
struct rcu_head rcu;
char ifname[IFNAMSIZ];
u8 ifnamelen;
u8 flags;
};
struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook,
@@ -1664,6 +1667,16 @@ struct nft_trans {
u8 put_net:1;
};
/**
* struct nft_trans_hook - nf_tables hook update in transaction
* @list: used internally
* @hook: struct nft_hook with the device hook
*/
struct nft_trans_hook {
struct list_head list;
struct nft_hook *hook;
};
/**
* struct nft_trans_binding - nf_tables object with binding support in transaction
* @nft_trans: base structure, MUST be first member

View File

@@ -127,6 +127,21 @@ static inline unsigned int net_iov_idx(const struct net_iov *niov)
return niov - net_iov_owner(niov)->niovs;
}
/* Initialize a niov: stamp the owning area, the memory provider type,
* and the page_type "no type" sentinel expected by the page-type API
* (see PAGE_TYPE_OPS in <linux/page-flags.h>) so that
* page_pool_set_pp_info() can later call __SetPageNetpp() on a niov
* cast to struct page.
*/
static inline void net_iov_init(struct net_iov *niov,
struct net_iov_area *owner,
enum net_iov_type type)
{
niov->owner = owner;
niov->type = type;
niov->page_type = UINT_MAX;
}
/* netmem */
/**

View File

@@ -495,10 +495,9 @@ static int io_zcrx_create_area(struct io_zcrx_ifq *ifq,
for (i = 0; i < nr_iovs; i++) {
struct net_iov *niov = &area->nia.niovs[i];
niov->owner = &area->nia;
net_iov_init(niov, &area->nia, NET_IOV_IOURING);
area->freelist[i] = i;
atomic_set(&area->user_refs[i], 0);
niov->type = NET_IOV_IOURING;
}
if (ifq->dev) {

View File

@@ -3934,33 +3934,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, enum psi_res res)
{
struct cgroup_file_ctx *ctx = of->priv;
struct cgroup_file_ctx *ctx;
struct psi_trigger *new;
struct cgroup *cgrp;
struct psi_group *psi;
ssize_t ret = 0;
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;
cgroup_get(cgrp);
cgroup_kn_unlock(of->kn);
ctx = of->priv;
if (!ctx) {
ret = -ENODEV;
goto out_unlock;
}
/* Allow only one trigger per file descriptor */
if (ctx->psi.trigger) {
cgroup_put(cgrp);
return -EBUSY;
ret = -EBUSY;
goto out_unlock;
}
psi = cgroup_psi(cgrp);
new = psi_trigger_create(psi, buf, res, of->file, of);
if (IS_ERR(new)) {
cgroup_put(cgrp);
return PTR_ERR(new);
ret = PTR_ERR(new);
goto out_unlock;
}
smp_store_release(&ctx->psi.trigger, new);
cgroup_put(cgrp);
out_unlock:
cgroup_kn_unlock(of->kn);
if (ret)
return ret;
return nbytes;
}
@@ -5716,16 +5724,6 @@ static void offline_css(struct cgroup_subsys_state *css)
RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL);
wake_up_all(&css->cgroup->offline_waitq);
css->cgroup->nr_dying_subsys[ss->id]++;
/*
* Parent css and cgroup cannot be freed until after the freeing
* of child css, see css_free_rwork_fn().
*/
while ((css = css->parent)) {
css->nr_descendants--;
css->cgroup->nr_dying_subsys[ss->id]++;
}
}
/**
@@ -6038,6 +6036,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
*/
static void kill_css(struct cgroup_subsys_state *css)
{
struct cgroup_subsys *ss = css->ss;
lockdep_assert_held(&cgroup_mutex);
if (css->flags & CSS_DYING)
@@ -6074,6 +6074,16 @@ static void kill_css(struct cgroup_subsys_state *css)
* css is confirmed to be seen as killed on all CPUs.
*/
percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn);
css->cgroup->nr_dying_subsys[ss->id]++;
/*
* Parent css and cgroup cannot be freed until after the freeing
* of child css, see css_free_rwork_fn().
*/
while ((css = css->parent)) {
css->nr_descendants--;
css->cgroup->nr_dying_subsys[ss->id]++;
}
}
/**

View File

@@ -168,6 +168,11 @@ struct cpuset {
int nr_deadline_tasks;
int nr_migrate_dl_tasks;
u64 sum_migrate_dl_bw;
/*
* CPU used for temporary DL bandwidth allocation during attach;
* -1 if no DL bandwidth was allocated in the current attach.
*/
int dl_bw_cpu;
/* Invalid partition error code, not lock protected */
enum prs_errcode prs_err;

View File

@@ -288,6 +288,7 @@ struct cpuset top_cpuset = {
.flags = BIT(CS_CPU_EXCLUSIVE) |
BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE),
.partition_root_state = PRS_ROOT,
.dl_bw_cpu = -1,
};
/**
@@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs)
if (!trial)
return NULL;
trial->dl_bw_cpu = -1;
/* Setup cpumask pointer array */
cpumask_var_t *pmask[4] = {
&trial->cpus_allowed,
@@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs)
{
cs->nr_migrate_dl_tasks = 0;
cs->sum_migrate_dl_bw = 0;
cs->dl_bw_cpu = -1;
}
/* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
@@ -3056,6 +3060,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
reset_migrate_dl_data(cs);
goto out_unlock;
}
cs->dl_bw_cpu = cpu;
}
out_success:
@@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset)
mutex_lock(&cpuset_mutex);
dec_attach_in_progress_locked(cs);
if (cs->nr_migrate_dl_tasks) {
int cpu = cpumask_any(cs->effective_cpus);
if (cs->dl_bw_cpu >= 0)
dl_bw_free(cs->dl_bw_cpu, cs->sum_migrate_dl_bw);
dl_bw_free(cpu, cs->sum_migrate_dl_bw);
if (cs->nr_migrate_dl_tasks)
reset_migrate_dl_data(cs);
}
mutex_unlock(&cpuset_mutex);
}

View File

@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg,
ret = PTR_ERR(rpool);
goto err;
} else {
new = rpool->resources[index].usage + 1;
new = (s64)rpool->resources[index].usage + 1;
if (new > rpool->resources[index].max) {
ret = -EAGAIN;
goto err;

View File

@@ -32,6 +32,7 @@ static const struct rhashtable_params scx_sched_hash_params = {
.key_len = sizeof_field(struct scx_sched, ops.sub_cgroup_id),
.key_offset = offsetof(struct scx_sched, ops.sub_cgroup_id),
.head_offset = offsetof(struct scx_sched, hash_node),
.insecure_elasticity = true, /* inserted under scx_sched_lock */
};
static struct rhashtable scx_sched_hash;
@@ -52,8 +53,6 @@ DEFINE_STATIC_KEY_FALSE(__scx_enabled);
DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem);
static atomic_t scx_enable_state_var = ATOMIC_INIT(SCX_DISABLED);
static DEFINE_RAW_SPINLOCK(scx_bypass_lock);
static cpumask_var_t scx_bypass_lb_donee_cpumask;
static cpumask_var_t scx_bypass_lb_resched_cpumask;
static bool scx_init_task_enabled;
static bool scx_switching_all;
DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
@@ -469,24 +468,35 @@ static inline void update_locked_rq(struct rq *rq)
__this_cpu_write(scx_locked_rq_state, rq);
}
#define SCX_CALL_OP(sch, op, rq, args...) \
/*
* SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not
* clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
*/
#define SCX_CALL_OP(sch, op, locked_rq, args...) \
do { \
if (rq) \
update_locked_rq(rq); \
struct rq *__prev_locked_rq; \
\
if (locked_rq) { \
__prev_locked_rq = scx_locked_rq(); \
update_locked_rq(locked_rq); \
} \
(sch)->ops.op(args); \
if (rq) \
update_locked_rq(NULL); \
if (locked_rq) \
update_locked_rq(__prev_locked_rq); \
} while (0)
#define SCX_CALL_OP_RET(sch, op, rq, args...) \
#define SCX_CALL_OP_RET(sch, op, locked_rq, args...) \
({ \
struct rq *__prev_locked_rq; \
__typeof__((sch)->ops.op(args)) __ret; \
\
if (rq) \
update_locked_rq(rq); \
if (locked_rq) { \
__prev_locked_rq = scx_locked_rq(); \
update_locked_rq(locked_rq); \
} \
__ret = (sch)->ops.op(args); \
if (rq) \
update_locked_rq(NULL); \
if (locked_rq) \
update_locked_rq(__prev_locked_rq); \
__ret; \
})
@@ -498,39 +508,39 @@ do { \
* those subject tasks.
*
* Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held -
* either via the @rq argument here, or (for ops.select_cpu()) via @p's pi_lock
* held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. So if
* kf_tasks[] is set, @p's scheduler-protected fields are stable.
* either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's
* pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu.
* So if kf_tasks[] is set, @p's scheduler-protected fields are stable.
*
* kf_tasks[] can not stack, so task-based SCX ops must not nest. The
* WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants
* while a previous one is still in progress.
*/
#define SCX_CALL_OP_TASK(sch, op, rq, task, args...) \
#define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...) \
do { \
WARN_ON_ONCE(current->scx.kf_tasks[0]); \
current->scx.kf_tasks[0] = task; \
SCX_CALL_OP((sch), op, rq, task, ##args); \
SCX_CALL_OP((sch), op, locked_rq, task, ##args); \
current->scx.kf_tasks[0] = NULL; \
} while (0)
#define SCX_CALL_OP_TASK_RET(sch, op, rq, task, args...) \
#define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...) \
({ \
__typeof__((sch)->ops.op(task, ##args)) __ret; \
WARN_ON_ONCE(current->scx.kf_tasks[0]); \
current->scx.kf_tasks[0] = task; \
__ret = SCX_CALL_OP_RET((sch), op, rq, task, ##args); \
__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task, ##args); \
current->scx.kf_tasks[0] = NULL; \
__ret; \
})
#define SCX_CALL_OP_2TASKS_RET(sch, op, rq, task0, task1, args...) \
#define SCX_CALL_OP_2TASKS_RET(sch, op, locked_rq, task0, task1, args...) \
({ \
__typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \
WARN_ON_ONCE(current->scx.kf_tasks[0]); \
current->scx.kf_tasks[0] = task0; \
current->scx.kf_tasks[1] = task1; \
__ret = SCX_CALL_OP_RET((sch), op, rq, task0, task1, ##args); \
__ret = SCX_CALL_OP_RET((sch), op, locked_rq, task0, task1, ##args); \
current->scx.kf_tasks[0] = NULL; \
current->scx.kf_tasks[1] = NULL; \
__ret; \
@@ -1388,18 +1398,55 @@ static void call_task_dequeue(struct scx_sched *sch, struct rq *rq,
p->scx.flags &= ~SCX_TASK_IN_CUSTODY;
}
static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p,
u64 enq_flags)
static void local_dsq_post_enq(struct scx_sched *sch, struct scx_dispatch_q *dsq,
struct task_struct *p, u64 enq_flags)
{
struct rq *rq = container_of(dsq, struct rq, scx.local_dsq);
bool preempt = false;
call_task_dequeue(scx_root, rq, p, 0);
call_task_dequeue(sch, rq, p, 0);
/*
* Note that @rq's lock may be dropped between this enqueue and @p
* actually getting on CPU. This gives higher-class tasks (e.g. RT)
* an opportunity to wake up on @rq and prevent @p from running.
* Here are some concrete examples:
*
* Example 1:
*
* We dispatch two tasks from a single ops.dispatch():
* - First, a local task to this CPU's local DSQ;
* - Second, a local/remote task to a remote CPU's local DSQ.
* We must drop the local rq lock in order to finish the second
* dispatch. In that time, an RT task can wake up on the local rq.
*
* Example 2:
*
* We dispatch a local/remote task to a remote CPU's local DSQ.
* We must drop the remote rq lock before the dispatched task can run,
* which gives an RT task an opportunity to wake up on the remote rq.
*
* Both examples work the same if we replace dispatching with moving
* the tasks from a user-created DSQ.
*
* We must detect these wakeups so that we can re-enqueue IMMED tasks
* from @rq's local DSQ. scx_wakeup_preempt() serves exactly this
* purpose, but for it to be invoked, we must ensure that we bump
* @rq->next_class to &ext_sched_class if it's currently idle.
*
* wakeup_preempt() does the bumping, and since we only invoke it if
* @rq->next_class is below &ext_sched_class, it will also
* resched_curr(rq).
*/
if (sched_class_above(p->sched_class, rq->next_class))
wakeup_preempt(rq, p, 0);
/*
* If @rq is in balance, the CPU is already vacant and looking for the
* next task to run. No need to preempt or trigger resched after moving
* @p into its local DSQ.
* Note that the wakeup_preempt() above may have already triggered
* a resched if @rq->next_class was idle. It's harmless, since
* need_resched is cleared immediately after task pick.
*/
if (rq->scx.flags & SCX_RQ_IN_BALANCE)
return;
@@ -1407,11 +1454,8 @@ static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p
if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr &&
rq->curr->sched_class == &ext_sched_class) {
rq->curr->scx.slice = 0;
preempt = true;
}
if (preempt || sched_class_above(&ext_sched_class, rq->curr->sched_class))
resched_curr(rq);
}
}
static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq,
@@ -1494,11 +1538,13 @@ static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq,
if (!(dsq->id & SCX_DSQ_FLAG_BUILTIN))
rcu_assign_pointer(dsq->first_task, p);
} else {
bool was_empty;
was_empty = list_empty(&dsq->list);
/*
* dsq->list can contain parked BPF iterator cursors, so
* list_empty() here isn't a reliable proxy for "no real
* task in the DSQ". Test dsq->first_task directly.
*/
list_add_tail(&p->scx.dsq_list.node, &dsq->list);
if (was_empty && !(dsq->id & SCX_DSQ_FLAG_BUILTIN))
if (!dsq->first_task && !(dsq->id & SCX_DSQ_FLAG_BUILTIN))
rcu_assign_pointer(dsq->first_task, p);
}
}
@@ -1518,7 +1564,7 @@ static void dispatch_enqueue(struct scx_sched *sch, struct rq *rq,
* concurrently in a non-atomic way.
*/
if (is_local) {
local_dsq_post_enq(dsq, p, enq_flags);
local_dsq_post_enq(sch, dsq, p, enq_flags);
} else {
/*
* Task on global/bypass DSQ: leave custody, task on
@@ -2129,7 +2175,8 @@ static void wakeup_preempt_scx(struct rq *rq, struct task_struct *p, int wake_fl
schedule_reenq_local(rq, 0);
}
static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
static void move_local_task_to_local_dsq(struct scx_sched *sch,
struct task_struct *p, u64 enq_flags,
struct scx_dispatch_q *src_dsq,
struct rq *dst_rq)
{
@@ -2149,7 +2196,7 @@ static void move_local_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
dsq_inc_nr(dst_dsq, p, enq_flags);
p->scx.dsq = dst_dsq;
local_dsq_post_enq(dst_dsq, p, enq_flags);
local_dsq_post_enq(sch, dst_dsq, p, enq_flags);
}
/**
@@ -2370,7 +2417,7 @@ static struct rq *move_task_between_dsqs(struct scx_sched *sch,
/* @p is going from a non-local DSQ to a local DSQ */
if (src_rq == dst_rq) {
task_unlink_from_dsq(p, src_dsq);
move_local_task_to_local_dsq(p, enq_flags,
move_local_task_to_local_dsq(sch, p, enq_flags,
src_dsq, dst_rq);
raw_spin_unlock(&src_dsq->lock);
} else {
@@ -2423,7 +2470,7 @@ static bool consume_dispatch_q(struct scx_sched *sch, struct rq *rq,
if (rq == task_rq) {
task_unlink_from_dsq(p, dsq);
move_local_task_to_local_dsq(p, enq_flags, dsq, rq);
move_local_task_to_local_dsq(sch, p, enq_flags, dsq, rq);
raw_spin_unlock(&dsq->lock);
return true;
}
@@ -3183,7 +3230,7 @@ bool scx_prio_less(const struct task_struct *a, const struct task_struct *b,
if (sch_a == sch_b && SCX_HAS_OP(sch_a, core_sched_before) &&
!scx_bypassing(sch_a, task_cpu(a)))
return SCX_CALL_OP_2TASKS_RET(sch_a, core_sched_before,
NULL,
task_rq(a),
(struct task_struct *)a,
(struct task_struct *)b);
else
@@ -3631,6 +3678,22 @@ static void __scx_disable_and_exit_task(struct scx_sched *sch,
SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args);
}
/*
* Undo a completed __scx_init_task(sch, p, false) when scx_enable_task() never
* ran. The task state has not been transitioned, so this mirrors the
* SCX_TASK_INIT branch in __scx_disable_and_exit_task().
*/
static void scx_sub_init_cancel_task(struct scx_sched *sch, struct task_struct *p)
{
struct scx_exit_task_args args = { .cancelled = true };
lockdep_assert_held(&p->pi_lock);
lockdep_assert_rq_held(task_rq(p));
if (SCX_HAS_OP(sch, exit_task))
SCX_CALL_OP_TASK(sch, exit_task, task_rq(p), p, &args);
}
static void scx_disable_and_exit_task(struct scx_sched *sch,
struct task_struct *p)
{
@@ -3639,11 +3702,12 @@ static void scx_disable_and_exit_task(struct scx_sched *sch,
/*
* If set, @p exited between __scx_init_task() and scx_enable_task() in
* scx_sub_enable() and is initialized for both the associated sched and
* its parent. Disable and exit for the child too.
* its parent. Exit for the child too - scx_enable_task() never ran for
* it, so undo only init_task.
*/
if ((p->scx.flags & SCX_TASK_SUB_INIT) &&
!WARN_ON_ONCE(!scx_enabling_sub_sched)) {
__scx_disable_and_exit_task(scx_enabling_sub_sched, p);
if (p->scx.flags & SCX_TASK_SUB_INIT) {
if (!WARN_ON_ONCE(!scx_enabling_sub_sched))
scx_sub_init_cancel_task(scx_enabling_sub_sched, p);
p->scx.flags &= ~SCX_TASK_SUB_INIT;
}
@@ -4324,9 +4388,10 @@ void scx_cgroup_cancel_attach(struct cgroup_taskset *tset)
void scx_group_set_weight(struct task_group *tg, unsigned long weight)
{
struct scx_sched *sch = scx_root;
struct scx_sched *sch;
percpu_down_read(&scx_cgroup_ops_rwsem);
sch = scx_root;
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) &&
tg->scx.weight != weight)
@@ -4339,9 +4404,10 @@ void scx_group_set_weight(struct task_group *tg, unsigned long weight)
void scx_group_set_idle(struct task_group *tg, bool idle)
{
struct scx_sched *sch = scx_root;
struct scx_sched *sch;
percpu_down_read(&scx_cgroup_ops_rwsem);
sch = scx_root;
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle))
SCX_CALL_OP(sch, cgroup_set_idle, NULL, tg_cgrp(tg), idle);
@@ -4355,9 +4421,10 @@ void scx_group_set_idle(struct task_group *tg, bool idle)
void scx_group_set_bandwidth(struct task_group *tg,
u64 period_us, u64 quota_us, u64 burst_us)
{
struct scx_sched *sch = scx_root;
struct scx_sched *sch;
percpu_down_read(&scx_cgroup_ops_rwsem);
sch = scx_root;
if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_bandwidth) &&
(tg->scx.bw_period_us != period_us ||
@@ -4380,21 +4447,6 @@ static struct cgroup *root_cgroup(void)
return &cgrp_dfl_root.cgrp;
}
static struct cgroup *sch_cgroup(struct scx_sched *sch)
{
return sch->cgrp;
}
/* for each descendant of @cgrp including self, set ->scx_sched to @sch */
static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch)
{
struct cgroup *pos;
struct cgroup_subsys_state *css;
cgroup_for_each_live_descendant_pre(pos, css, cgrp)
rcu_assign_pointer(pos->scx_sched, sch);
}
static void scx_cgroup_lock(void)
{
#ifdef CONFIG_EXT_GROUP_SCHED
@@ -4412,12 +4464,30 @@ static void scx_cgroup_unlock(void)
}
#else /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */
static struct cgroup *root_cgroup(void) { return NULL; }
static struct cgroup *sch_cgroup(struct scx_sched *sch) { return NULL; }
static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) {}
static void scx_cgroup_lock(void) {}
static void scx_cgroup_unlock(void) {}
#endif /* CONFIG_EXT_GROUP_SCHED || CONFIG_EXT_SUB_SCHED */
#ifdef CONFIG_EXT_SUB_SCHED
static struct cgroup *sch_cgroup(struct scx_sched *sch)
{
return sch->cgrp;
}
/* for each descendant of @cgrp including self, set ->scx_sched to @sch */
static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch)
{
struct cgroup *pos;
struct cgroup_subsys_state *css;
cgroup_for_each_live_descendant_pre(pos, css, cgrp)
rcu_assign_pointer(pos->scx_sched, sch);
}
#else /* CONFIG_EXT_SUB_SCHED */
static struct cgroup *sch_cgroup(struct scx_sched *sch) { return NULL; }
static void set_cgroup_sched(struct cgroup *cgrp, struct scx_sched *sch) {}
#endif /* CONFIG_EXT_SUB_SCHED */
/*
* Omitted operations:
*
@@ -4712,6 +4782,8 @@ static void scx_sched_free_rcu_work(struct work_struct *work)
irq_work_sync(&sch->disable_irq_work);
kthread_destroy_worker(sch->helper);
timer_shutdown_sync(&sch->bypass_lb_timer);
free_cpumask_var(sch->bypass_lb_donee_cpumask);
free_cpumask_var(sch->bypass_lb_resched_cpumask);
#ifdef CONFIG_EXT_SUB_SCHED
kfree(sch->cgrp_path);
@@ -4938,6 +5010,25 @@ void scx_softlockup(u32 dur_s)
smp_processor_id(), dur_s);
}
/*
* scx_hardlockup() runs from NMI and eventually calls scx_claim_exit(),
* which takes scx_sched_lock. scx_sched_lock isn't NMI-safe and grabbing
* it from NMI context can lead to deadlocks. Defer via irq_work; the
* disable path runs off irq_work anyway.
*/
static atomic_t scx_hardlockup_cpu = ATOMIC_INIT(-1);
static void scx_hardlockup_irq_workfn(struct irq_work *work)
{
int cpu = atomic_xchg(&scx_hardlockup_cpu, -1);
if (cpu >= 0 && handle_lockup("hard lockup - CPU %d", cpu))
printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n",
cpu);
}
static DEFINE_IRQ_WORK(scx_hardlockup_irq_work, scx_hardlockup_irq_workfn);
/**
* scx_hardlockup - sched_ext hardlockup handler
*
@@ -4946,17 +5037,19 @@ void scx_softlockup(u32 dur_s)
* Try kicking out the current scheduler in an attempt to recover the system to
* a good state before taking more drastic actions.
*
* Returns %true if sched_ext is enabled and abort was initiated, which may
* resolve the reported hardlockup. %false if sched_ext is not enabled or
* someone else already initiated abort.
* Queues an irq_work; the handle_lockup() call happens in IRQ context (see
* scx_hardlockup_irq_workfn).
*
* Returns %true if sched_ext is enabled and the work was queued, %false
* otherwise.
*/
bool scx_hardlockup(int cpu)
{
if (!handle_lockup("hard lockup - CPU %d", cpu))
if (!rcu_access_pointer(scx_root))
return false;
printk_deferred(KERN_ERR "sched_ext: Hard lockup - CPU %d, disabling BPF scheduler\n",
cpu);
atomic_cmpxchg(&scx_hardlockup_cpu, -1, cpu);
irq_work_queue(&scx_hardlockup_irq_work);
return true;
}
@@ -5000,6 +5093,15 @@ static u32 bypass_lb_cpu(struct scx_sched *sch, s32 donor,
if (cpumask_empty(donee_mask))
break;
/*
* If an earlier pass placed @p on @donor_dsq from a different
* CPU and the donee hasn't consumed it yet, @p is still on the
* previous CPU and task_rq(@p) != @donor_rq. @p can't be moved
* without its rq locked. Skip.
*/
if (task_rq(p) != donor_rq)
continue;
donee = cpumask_any_and_distribute(donee_mask, p->cpus_ptr);
if (donee >= nr_cpu_ids)
continue;
@@ -5058,8 +5160,8 @@ static u32 bypass_lb_cpu(struct scx_sched *sch, s32 donor,
static void bypass_lb_node(struct scx_sched *sch, int node)
{
const struct cpumask *node_mask = cpumask_of_node(node);
struct cpumask *donee_mask = scx_bypass_lb_donee_cpumask;
struct cpumask *resched_mask = scx_bypass_lb_resched_cpumask;
struct cpumask *donee_mask = sch->bypass_lb_donee_cpumask;
struct cpumask *resched_mask = sch->bypass_lb_resched_cpumask;
u32 nr_tasks = 0, nr_cpus = 0, nr_balanced = 0;
u32 nr_target, nr_donor_target;
u32 before_min = U32_MAX, before_max = 0;
@@ -5698,6 +5800,8 @@ static void scx_sub_disable(struct scx_sched *sch)
if (sch->ops.exit)
SCX_CALL_OP(sch, exit, NULL, sch->exit_info);
if (sch->sub_kset)
kset_unregister(sch->sub_kset);
kobject_del(&sch->kobj);
}
#else /* CONFIG_EXT_SUB_SCHED */
@@ -5829,6 +5933,10 @@ static void scx_root_disable(struct scx_sched *sch)
* could observe an object of the same name still in the hierarchy when
* the next scheduler is loaded.
*/
#ifdef CONFIG_EXT_SUB_SCHED
if (sch->sub_kset)
kset_unregister(sch->sub_kset);
#endif
kobject_del(&sch->kobj);
free_kick_syncs();
@@ -5921,6 +6029,25 @@ static void scx_disable(struct scx_sched *sch, enum scx_exit_kind kind)
irq_work_queue(&sch->disable_irq_work);
}
/**
* scx_flush_disable_work - flush the disable work and wait for it to finish
* @sch: the scheduler
*
* sch->disable_work might still not queued, causing kthread_flush_work()
* as a noop. Syncing the irq_work first is required to guarantee the
* kthread work has been queued before waiting for it.
*/
static void scx_flush_disable_work(struct scx_sched *sch)
{
int kind;
do {
irq_work_sync(&sch->disable_irq_work);
kthread_flush_work(&sch->disable_work);
kind = atomic_read(&sch->exit_kind);
} while (kind != SCX_EXIT_NONE && kind != SCX_EXIT_DONE);
}
static void dump_newline(struct seq_buf *s)
{
trace_sched_ext_dump("");
@@ -6032,9 +6159,8 @@ static void ops_dump_exit(void)
scx_dump_data.cpu = -1;
}
static void scx_dump_task(struct scx_sched *sch,
struct seq_buf *s, struct scx_dump_ctx *dctx,
struct task_struct *p, char marker)
static void scx_dump_task(struct scx_sched *sch, struct seq_buf *s, struct scx_dump_ctx *dctx,
struct rq *rq, struct task_struct *p, char marker)
{
static unsigned long bt[SCX_EXIT_BT_LEN];
struct scx_sched *task_sch = scx_task_sched(p);
@@ -6075,7 +6201,7 @@ static void scx_dump_task(struct scx_sched *sch,
if (SCX_HAS_OP(sch, dump_task)) {
ops_dump_init(s, " ");
SCX_CALL_OP(sch, dump_task, NULL, dctx, p);
SCX_CALL_OP(sch, dump_task, rq, dctx, p);
ops_dump_exit();
}
@@ -6199,8 +6325,7 @@ static void scx_dump_state(struct scx_sched *sch, struct scx_exit_info *ei,
used = seq_buf_used(&ns);
if (SCX_HAS_OP(sch, dump_cpu)) {
ops_dump_init(&ns, " ");
SCX_CALL_OP(sch, dump_cpu, NULL,
&dctx, cpu, idle);
SCX_CALL_OP(sch, dump_cpu, rq, &dctx, cpu, idle);
ops_dump_exit();
}
@@ -6223,11 +6348,11 @@ static void scx_dump_state(struct scx_sched *sch, struct scx_exit_info *ei,
if (rq->curr->sched_class == &ext_sched_class &&
(dump_all_tasks || scx_task_on_sched(sch, rq->curr)))
scx_dump_task(sch, &s, &dctx, rq->curr, '*');
scx_dump_task(sch, &s, &dctx, rq, rq->curr, '*');
list_for_each_entry(p, &rq->scx.runnable_list, scx.runnable_node)
if (dump_all_tasks || scx_task_on_sched(sch, p))
scx_dump_task(sch, &s, &dctx, p, ' ');
scx_dump_task(sch, &s, &dctx, rq, p, ' ');
next:
rq_unlock_irqrestore(rq, &rf);
}
@@ -6437,6 +6562,15 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops,
init_irq_work(&sch->disable_irq_work, scx_disable_irq_workfn);
kthread_init_work(&sch->disable_work, scx_disable_workfn);
timer_setup(&sch->bypass_lb_timer, scx_bypass_lb_timerfn, 0);
if (!alloc_cpumask_var(&sch->bypass_lb_donee_cpumask, GFP_KERNEL)) {
ret = -ENOMEM;
goto err_stop_helper;
}
if (!alloc_cpumask_var(&sch->bypass_lb_resched_cpumask, GFP_KERNEL)) {
ret = -ENOMEM;
goto err_free_lb_cpumask;
}
sch->ops = *ops;
rcu_assign_pointer(ops->priv, sch);
@@ -6446,14 +6580,14 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops,
char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto err_stop_helper;
goto err_free_lb_resched;
}
cgroup_path(cgrp, buf, PATH_MAX);
sch->cgrp_path = kstrdup(buf, GFP_KERNEL);
kfree(buf);
if (!sch->cgrp_path) {
ret = -ENOMEM;
goto err_stop_helper;
goto err_free_lb_resched;
}
sch->cgrp = cgrp;
@@ -6488,10 +6622,12 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops,
#endif /* CONFIG_EXT_SUB_SCHED */
return sch;
#ifdef CONFIG_EXT_SUB_SCHED
err_free_lb_resched:
free_cpumask_var(sch->bypass_lb_resched_cpumask);
err_free_lb_cpumask:
free_cpumask_var(sch->bypass_lb_donee_cpumask);
err_stop_helper:
kthread_destroy_worker(sch->helper);
#endif
err_free_pcpu:
for_each_possible_cpu(cpu) {
if (cpu == bypass_fail_cpu)
@@ -6510,7 +6646,7 @@ static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops,
err_free_sch:
kfree(sch);
err_put_cgrp:
#if defined(CONFIG_EXT_GROUP_SCHED) || defined(CONFIG_EXT_SUB_SCHED)
#ifdef CONFIG_EXT_SUB_SCHED
cgroup_put(cgrp);
#endif
return ERR_PTR(ret);
@@ -6601,7 +6737,7 @@ static void scx_root_enable_workfn(struct kthread_work *work)
if (ret)
goto err_unlock;
#if defined(CONFIG_EXT_GROUP_SCHED) || defined(CONFIG_EXT_SUB_SCHED)
#ifdef CONFIG_EXT_SUB_SCHED
cgroup_get(cgrp);
#endif
sch = scx_alloc_and_add_sched(ops, cgrp, NULL);
@@ -6639,8 +6775,10 @@ static void scx_root_enable_workfn(struct kthread_work *work)
rcu_assign_pointer(scx_root, sch);
ret = scx_link_sched(sch);
if (ret)
if (ret) {
cpus_read_unlock();
goto err_disable;
}
scx_idle_enable(ops);
@@ -6821,7 +6959,7 @@ static void scx_root_enable_workfn(struct kthread_work *work)
* completion. sch's base reference will be put by bpf_scx_unreg().
*/
scx_error(sch, "scx_root_enable() failed (%d)", ret);
kthread_flush_work(&sch->disable_work);
scx_flush_disable_work(sch);
cmd->ret = 0;
}
@@ -7072,23 +7210,30 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
abort:
put_task_struct(p);
scx_task_iter_stop(&sti);
scx_enabling_sub_sched = NULL;
/*
* Undo __scx_init_task() for tasks we marked. scx_enable_task() never
* ran for @sch on them, so calling scx_disable_task() here would invoke
* ops.disable() without a matching ops.enable(). scx_enabling_sub_sched
* must stay set until SUB_INIT is cleared from every marked task -
* scx_disable_and_exit_task() reads it when a task exits concurrently.
*/
scx_task_iter_start(&sti, sch->cgrp);
while ((p = scx_task_iter_next_locked(&sti))) {
if (p->scx.flags & SCX_TASK_SUB_INIT) {
__scx_disable_and_exit_task(sch, p);
scx_sub_init_cancel_task(sch, p);
p->scx.flags &= ~SCX_TASK_SUB_INIT;
}
}
scx_task_iter_stop(&sti);
scx_enabling_sub_sched = NULL;
err_unlock_and_disable:
/* we'll soon enter disable path, keep bypass on */
scx_cgroup_unlock();
percpu_up_write(&scx_fork_rwsem);
err_disable:
mutex_unlock(&scx_enable_mutex);
kthread_flush_work(&sch->disable_work);
scx_flush_disable_work(sch);
cmd->ret = 0;
}
@@ -7349,7 +7494,7 @@ static void bpf_scx_unreg(void *kdata, struct bpf_link *link)
struct scx_sched *sch = rcu_dereference_protected(ops->priv, true);
scx_disable(sch, SCX_EXIT_UNREG);
kthread_flush_work(&sch->disable_work);
scx_flush_disable_work(sch);
RCU_INIT_POINTER(ops->priv, NULL);
kobject_put(&sch->kobj);
}
@@ -8033,12 +8178,22 @@ static bool scx_dsq_move(struct bpf_iter_scx_dsq_kern *kit,
struct task_struct *p, u64 dsq_id, u64 enq_flags)
{
struct scx_dispatch_q *src_dsq = kit->dsq, *dst_dsq;
struct scx_sched *sch = src_dsq->sched;
struct scx_sched *sch;
struct rq *this_rq, *src_rq, *locked_rq;
bool dispatched = false;
bool in_balance;
unsigned long flags;
/*
* The verifier considers an iterator slot initialized on any
* KF_ITER_NEW return, so a BPF program may legally reach here after
* bpf_iter_scx_dsq_new() failed and left @kit->dsq NULL.
*/
if (unlikely(!src_dsq))
return false;
sch = src_dsq->sched;
if (!scx_vet_enq_flags(sch, dsq_id, &enq_flags))
return false;
@@ -8526,7 +8681,7 @@ __bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice,
guard(rcu)();
sch = scx_prog_sched(aux);
if (unlikely(!scx_task_on_sched(sch, p)))
if (unlikely(!sch || !scx_task_on_sched(sch, p)))
return false;
p->scx.slice = slice;
@@ -8549,7 +8704,7 @@ __bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime,
guard(rcu)();
sch = scx_prog_sched(aux);
if (unlikely(!scx_task_on_sched(sch, p)))
if (unlikely(!sch || !scx_task_on_sched(sch, p)))
return false;
p->scx.dsq_vtime = vtime;
@@ -8633,11 +8788,12 @@ __bpf_kfunc void scx_bpf_kick_cpu(s32 cpu, u64 flags, const struct bpf_prog_aux
/**
* scx_bpf_dsq_nr_queued - Return the number of queued tasks
* @dsq_id: id of the DSQ
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
* Return the number of tasks in the DSQ matching @dsq_id. If not found,
* -%ENOENT is returned.
*/
__bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id)
__bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id, const struct bpf_prog_aux *aux)
{
struct scx_sched *sch;
struct scx_dispatch_q *dsq;
@@ -8645,7 +8801,7 @@ __bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id)
preempt_disable();
sch = rcu_dereference_sched(scx_root);
sch = scx_prog_sched(aux);
if (unlikely(!sch)) {
ret = -ENODEV;
goto out;
@@ -8677,21 +8833,21 @@ __bpf_kfunc s32 scx_bpf_dsq_nr_queued(u64 dsq_id)
/**
* scx_bpf_destroy_dsq - Destroy a custom DSQ
* @dsq_id: DSQ to destroy
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
* Destroy the custom DSQ identified by @dsq_id. Only DSQs created with
* scx_bpf_create_dsq() can be destroyed. The caller must ensure that the DSQ is
* empty and no further tasks are dispatched to it. Ignored if called on a DSQ
* which doesn't exist. Can be called from any online scx_ops operations.
*/
__bpf_kfunc void scx_bpf_destroy_dsq(u64 dsq_id)
__bpf_kfunc void scx_bpf_destroy_dsq(u64 dsq_id, const struct bpf_prog_aux *aux)
{
struct scx_sched *sch;
rcu_read_lock();
sch = rcu_dereference(scx_root);
guard(rcu)();
sch = scx_prog_sched(aux);
if (sch)
destroy_dsq(sch, dsq_id);
rcu_read_unlock();
}
/**
@@ -9445,8 +9601,8 @@ BTF_KFUNCS_START(scx_kfunc_ids_any)
BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_IMPLICIT_ARGS | KF_RCU);
BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_IMPLICIT_ARGS | KF_RCU);
BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_destroy_dsq, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_dsq_peek, KF_IMPLICIT_ARGS | KF_RCU_PROTECTED | KF_RET_NULL)
BTF_ID_FLAGS(func, scx_bpf_dsq_reenq, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_reenqueue_local___v2, KF_IMPLICIT_ARGS)
@@ -9479,6 +9635,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_any)
static const struct btf_kfunc_id_set scx_kfunc_set_any = {
.owner = THIS_MODULE,
.set = &scx_kfunc_ids_any,
.filter = scx_kfunc_context_filter,
};
/*
@@ -9526,13 +9683,12 @@ static const u32 scx_kf_allow_flags[] = {
};
/*
* Verifier-time filter for context-sensitive SCX kfuncs. Registered via the
* .filter field on each per-group btf_kfunc_id_set. The BPF core invokes this
* for every kfunc call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or
* Verifier-time filter for SCX kfuncs. Registered via the .filter field on
* each per-group btf_kfunc_id_set. The BPF core invokes this for every kfunc
* call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or
* BPF_PROG_TYPE_SYSCALL), regardless of which set originally introduced the
* kfunc - so the filter must short-circuit on kfuncs it doesn't govern (e.g.
* scx_kfunc_ids_any) by falling through to "allow" when none of the
* context-sensitive sets contain the kfunc.
* kfunc - so the filter must short-circuit on kfuncs it doesn't govern by
* falling through to "allow" when none of the SCX sets contain the kfunc.
*/
int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
{
@@ -9541,18 +9697,21 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
bool in_enqueue = btf_id_set8_contains(&scx_kfunc_ids_enqueue_dispatch, kfunc_id);
bool in_dispatch = btf_id_set8_contains(&scx_kfunc_ids_dispatch, kfunc_id);
bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id);
bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id);
bool in_any = btf_id_set8_contains(&scx_kfunc_ids_any, kfunc_id);
u32 moff, flags;
/* Not a context-sensitive kfunc (e.g. from scx_kfunc_ids_any) - allow. */
if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || in_cpu_release))
/* Not an SCX kfunc - allow. */
if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch ||
in_cpu_release || in_idle || in_any))
return 0;
/* SYSCALL progs (e.g. BPF test_run()) may call unlocked and select_cpu kfuncs. */
if (prog->type == BPF_PROG_TYPE_SYSCALL)
return (in_unlocked || in_select_cpu) ? 0 : -EACCES;
return (in_unlocked || in_select_cpu || in_idle || in_any) ? 0 : -EACCES;
if (prog->type != BPF_PROG_TYPE_STRUCT_OPS)
return -EACCES;
return (in_any || in_idle) ? 0 : -EACCES;
/*
* add_subprog_and_kfunc() collects all kfunc calls, including dead code
@@ -9565,14 +9724,15 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
return 0;
/*
* Non-SCX struct_ops: only unlocked kfuncs are safe. The other
* context-sensitive kfuncs assume the rq lock is held by the SCX
* dispatch path, which doesn't apply to other struct_ops users.
* Non-SCX struct_ops: SCX kfuncs are not permitted.
*/
if (prog->aux->st_ops != &bpf_sched_ext_ops)
return in_unlocked ? 0 : -EACCES;
return -EACCES;
/* SCX struct_ops: check the per-op allow list. */
if (in_any || in_idle)
return 0;
moff = prog->aux->attach_st_ops_member_off;
flags = scx_kf_allow_flags[SCX_MOFF_IDX(moff)];
@@ -9656,12 +9816,6 @@ static int __init scx_init(void)
return ret;
}
if (!alloc_cpumask_var(&scx_bypass_lb_donee_cpumask, GFP_KERNEL) ||
!alloc_cpumask_var(&scx_bypass_lb_resched_cpumask, GFP_KERNEL)) {
pr_err("sched_ext: Failed to allocate cpumasks\n");
return -ENOMEM;
}
return 0;
}
__initcall(scx_init);

View File

@@ -927,14 +927,24 @@ static s32 select_cpu_from_kfunc(struct scx_sched *sch, struct task_struct *p,
* Accessing p->cpus_ptr / p->nr_cpus_allowed needs either @p's rq
* lock or @p's pi_lock. Three cases:
*
* - inside ops.select_cpu(): try_to_wake_up() holds @p's pi_lock.
* - inside ops.select_cpu(): try_to_wake_up() holds the wake-up
* task's pi_lock; the wake-up task is recorded in kf_tasks[0]
* by SCX_CALL_OP_TASK_RET().
* - other rq-locked SCX op: scx_locked_rq() points at the held rq.
* - truly unlocked (UNLOCKED ops, SYSCALL, non-SCX struct_ops):
* nothing held, take pi_lock ourselves.
*
* In the first two cases, BPF schedulers may pass an arbitrary task
* that the held lock doesn't cover. Refuse those.
*/
if (this_rq()->scx.in_select_cpu) {
if (!scx_kf_arg_task_ok(sch, p))
return -EINVAL;
lockdep_assert_held(&p->pi_lock);
} else if (!scx_locked_rq()) {
} else if (scx_locked_rq()) {
if (task_rq(p) != scx_locked_rq())
goto cross_task;
} else {
raw_spin_lock_irqsave(&p->pi_lock, irq_flags);
we_locked = true;
}
@@ -960,6 +970,11 @@ static s32 select_cpu_from_kfunc(struct scx_sched *sch, struct task_struct *p,
raw_spin_unlock_irqrestore(&p->pi_lock, irq_flags);
return cpu;
cross_task:
scx_error(sch, "select_cpu kfunc called cross-task on %s[%d]",
p->comm, p->pid);
return -EINVAL;
}
/**
@@ -1467,6 +1482,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_idle)
static const struct btf_kfunc_id_set scx_kfunc_set_idle = {
.owner = THIS_MODULE,
.set = &scx_kfunc_ids_idle,
.filter = scx_kfunc_context_filter,
};
/*

View File

@@ -12,6 +12,7 @@
struct sched_ext_ops;
extern struct btf_id_set8 scx_kfunc_ids_idle;
extern struct btf_id_set8 scx_kfunc_ids_select_cpu;
void scx_idle_update_selcpu_topology(struct sched_ext_ops *ops);

View File

@@ -1075,6 +1075,8 @@ struct scx_sched {
struct irq_work disable_irq_work;
struct kthread_work disable_work;
struct timer_list bypass_lb_timer;
cpumask_var_t bypass_lb_donee_cpumask;
cpumask_var_t bypass_lb_resched_cpumask;
struct rcu_work rcu_work;
/* all ancestors including self */

View File

@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void)
int ret;
ret = register_stat_tracer(&annotated_branch_stats);
if (!ret) {
if (ret) {
printk(KERN_WARNING "Warning: could not register "
"annotated branches stats\n");
return 1;
return ret;
}
return 0;
}
@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void)
int ret;
ret = register_stat_tracer(&all_branch_stats);
if (!ret) {
if (ret) {
printk(KERN_WARNING "Warning: could not register "
"all branches stats\n");
return 1;
return ret;
}
return 0;
}

View File

@@ -1523,6 +1523,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
parg->offset = *size;
*size += parg->type->size * (parg->count ?: 1);
if (*size > MAX_PROBE_EVENT_SIZE) {
ret = -E2BIG;
trace_probe_log_err(ctx->offset, EVENT_TOO_BIG);
goto fail;
}
if (parg->count) {
len = strlen(parg->type->fmttype) + 6;
parg->fmt = kmalloc(len, GFP_KERNEL);

View File

@@ -38,6 +38,7 @@
#define MAX_BTF_ARGS_LEN 128
#define MAX_DENTRY_ARGS_LEN 256
#define MAX_STRING_SIZE PATH_MAX
#define MAX_PROBE_EVENT_SIZE 3072
/* Reserved field names */
#define FIELD_STRING_IP "__probe_ip"
@@ -561,7 +562,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(BAD_TYPE4STR, "This type does not fit for string."),\
C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\
C(TOO_MANY_ARGS, "Too many arguments are specified"), \
C(TOO_MANY_EARGS, "Too many entry arguments specified"),
C(TOO_MANY_EARGS, "Too many entry arguments specified"), \
C(EVENT_TOO_BIG, "Event too big (too many fields?)"),
#undef C
#define C(a, b) TP_ERR_##a

Some files were not shown because too many files have changed in this diff Show More