Merge 33d0c9c5f0 ("Merge tag 'spi-fix-v7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi") into android-mainline

Steps on the way to v7.1-rc2

Change-Id: I9ccffb1e1a07e635fe3e573349cbc8ed05b62c42
Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
Carlos Llamas committed 2026-05-26 23:01:06 +00:00
commit e9d885afda
151 files changed
+2038 -992

No files matched your search

+5
View File
@@ -207,6 +207,7 @@ Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
Corey Minyard <minyard@acm.org>
Damian Hobson-Garcia <dhobsong@igel.co.jp>
Dan Carpenter <error27@gmail.com> <dan.carpenter@linaro.org>
Dan Carpenter <error27@gmail.com> <dan.carpenter@oracle.com>
Dan Williams <djbw@kernel.org> <dan.j.williams@intel.com>
Daniel Borkmann <daniel@iogearbox.net> <danborkmann@googlemail.com>
@@ -495,6 +496,7 @@ Leon Romanovsky <leon@kernel.org> <leon@leon.nu>
Leon Romanovsky <leon@kernel.org> <leonro@mellanox.com>
Leon Romanovsky <leon@kernel.org> <leonro@nvidia.com>
Leo Yan <leo.yan@linux.dev> <leo.yan@linaro.org>
Liam R. Howlett <liam@infradead.org> <Liam.Howlett@oracle.com>
Liam Mark <quic_lmark@quicinc.com> <lmark@codeaurora.org>
Linas Vepstas <linas@austin.ibm.com>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
@@ -505,6 +507,8 @@ Linus Walleij <linusw@kernel.org> <linus.walleij@stericsson.com>
Linus Walleij <linusw@kernel.org> <linus.walleij@linaro.org>
Linus Walleij <linusw@kernel.org> <triad@df.lth.se>
<linux-hardening@vger.kernel.org> <kernel-hardening@lists.openwall.com>
Li Wang <li.wang@linux.dev> <liwang@redhat.com>
Li Wang <li.wang@linux.dev> <wangli.ahau@gmail.com>
Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
Lior David <quic_liord@quicinc.com> <liord@codeaurora.org>
@@ -687,6 +691,7 @@ Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com>
Puranjay Mohan <puranjay@kernel.org> <puranjay12@gmail.com>
Qais Yousef <qyousef@layalina.io> <qais.yousef@imgtec.com>
Qais Yousef <qyousef@layalina.io> <qais.yousef@arm.com>
Qi Zheng <qi.zheng@linux.dev> <zhengqi.arch@bytedance.com>
Quentin Monnet <qmo@kernel.org> <quentin.monnet@netronome.com>
Quentin Monnet <qmo@kernel.org> <quentin@isovalent.com>
Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com>
+2
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:
+67 -33
View File
@@ -13868,7 +13868,6 @@ M: Pratyush Yadav <pratyush@kernel.org>
R: Dave Young <ruirui.yang@linux.dev>
L: kexec@lists.infradead.org
S: Maintained
W: http://lse.sourceforge.net/kdump/
F: Documentation/admin-guide/kdump/
F: fs/proc/vmcore.c
F: include/linux/crash_core.h
@@ -15260,7 +15259,7 @@ M: Andrea Cervesato <andrea.cervesato@suse.com>
M: Cyril Hrubis <chrubis@suse.cz>
M: Jan Stancek <jstancek@redhat.com>
M: Petr Vorel <pvorel@suse.cz>
M: Li Wang <liwang@redhat.com>
M: Li Wang <li.wang@linux.dev>
M: Yang Xu <xuyang2018.jy@fujitsu.com>
M: Xiao Yang <yangx.jy@fujitsu.com>
L: ltp@lists.linux.it (subscribers-only)
@@ -15407,7 +15406,7 @@ F: include/net/netns/mctp.h
F: net/mctp/
MAPLE TREE
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
R: Alice Ryhl <aliceryhl@google.com>
R: Andrew Ballance <andrewjballance@gmail.com>
L: maple-tree@lists.infradead.org
@@ -16767,7 +16766,7 @@ MEMORY MANAGEMENT - CORE
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Mike Rapoport <rppt@kernel.org>
R: Suren Baghdasaryan <surenb@google.com>
@@ -16813,7 +16812,7 @@ F: mm/sparse.c
F: mm/util.c
F: mm/vmpressure.c
F: mm/vmstat.c
N: include/linux/page[-_]*
N: include\/linux\/page[-_][a-zA-Z]*
MEMORY MANAGEMENT - EXECMEM
M: Andrew Morton <akpm@linux-foundation.org>
@@ -16903,7 +16902,7 @@ MEMORY MANAGEMENT - MISC
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Mike Rapoport <rppt@kernel.org>
R: Suren Baghdasaryan <surenb@google.com>
@@ -16970,6 +16969,7 @@ S: Maintained
F: include/linux/compaction.h
F: include/linux/gfp.h
F: include/linux/page-isolation.h
F: include/linux/pageblock-flags.h
F: mm/compaction.c
F: mm/debug_page_alloc.c
F: mm/debug_page_ref.c
@@ -16991,7 +16991,7 @@ M: Andrew Morton <akpm@linux-foundation.org>
M: Johannes Weiner <hannes@cmpxchg.org>
R: David Hildenbrand <david@kernel.org>
R: Michal Hocko <mhocko@kernel.org>
R: Qi Zheng <zhengqi.arch@bytedance.com>
R: Qi Zheng <qi.zheng@linux.dev>
R: Shakeel Butt <shakeel.butt@linux.dev>
R: Lorenzo Stoakes <ljs@kernel.org>
L: linux-mm@kvack.org
@@ -17004,7 +17004,7 @@ M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Rik van Riel <riel@surriel.com>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Harry Yoo <harry@kernel.org>
R: Jann Horn <jannh@google.com>
@@ -17051,7 +17051,7 @@ M: David Hildenbrand <david@kernel.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Baolin Wang <baolin.wang@linux.alibaba.com>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Nico Pache <npache@redhat.com>
R: Ryan Roberts <ryan.roberts@arm.com>
R: Dev Jain <dev.jain@arm.com>
@@ -17089,7 +17089,7 @@ F: tools/testing/selftests/mm/uffd-*.[ch]
MEMORY MANAGEMENT - RUST
M: Alice Ryhl <aliceryhl@google.com>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
L: linux-mm@kvack.org
L: rust-for-linux@vger.kernel.org
S: Maintained
@@ -17103,7 +17103,7 @@ F: rust/kernel/page.rs
MEMORY MAPPING
M: Andrew Morton <akpm@linux-foundation.org>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Jann Horn <jannh@google.com>
@@ -17135,7 +17135,7 @@ F: tools/testing/vma/
MEMORY MAPPING - LOCKING
M: Andrew Morton <akpm@linux-foundation.org>
M: Suren Baghdasaryan <surenb@google.com>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Shakeel Butt <shakeel.butt@linux.dev>
@@ -17150,7 +17150,7 @@ F: mm/mmap_lock.c
MEMORY MAPPING - MADVISE (MEMORY ADVICE)
M: Andrew Morton <akpm@linux-foundation.org>
M: Liam R. Howlett <Liam.Howlett@oracle.com>
M: Liam R. Howlett <liam@infradead.org>
M: Lorenzo Stoakes <ljs@kernel.org>
M: David Hildenbrand <david@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
@@ -18680,19 +18680,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>
@@ -18827,18 +18867,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/
@@ -20782,6 +20815,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/
@@ -23377,7 +23411,7 @@ RUST [ALLOC]
M: Danilo Krummrich <dakr@kernel.org>
R: Lorenzo Stoakes <ljs@kernel.org>
R: Vlastimil Babka <vbabka@kernel.org>
R: Liam R. Howlett <Liam.Howlett@oracle.com>
R: Liam R. Howlett <liam@infradead.org>
R: Uladzislau Rezki <urezki@gmail.com>
L: rust-for-linux@vger.kernel.org
S: Maintained
@@ -24322,7 +24356,7 @@ F: include/media/i2c/rj54n1cb0c.h
SHRINKER
M: Andrew Morton <akpm@linux-foundation.org>
M: Dave Chinner <david@fromorbit.com>
R: Qi Zheng <zhengqi.arch@bytedance.com>
R: Qi Zheng <qi.zheng@linux.dev>
R: Roman Gushchin <roman.gushchin@linux.dev>
R: Muchun Song <muchun.song@linux.dev>
L: linux-mm@kvack.org
+19 -16
View File
@@ -605,15 +605,12 @@ static umode_t acpi_tad_attr_is_visible(struct kobject *kobj,
return 0;
}
static const struct attribute_group acpi_tad_attr_group = {
static const struct attribute_group acpi_tad_group = {
.attrs = acpi_tad_attrs,
.is_visible = acpi_tad_attr_is_visible,
};
static const struct attribute_group *acpi_tad_attr_groups[] = {
&acpi_tad_attr_group,
NULL,
};
__ATTRIBUTE_GROUPS(acpi_tad);
#ifdef CONFIG_RTC_CLASS
/* RTC class device interface */
@@ -683,9 +680,8 @@ static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
acpi_tad_rt_to_tm(&rt, &tm_now);
value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time),
rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC);
if (value <= 0 || value > U32_MAX)
value = rtc_tm_to_time64(&t->time) - rtc_tm_to_time64(&tm_now);
if (value <= 0 || value >= U32_MAX)
return -EINVAL;
}
@@ -748,8 +744,7 @@ static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
if (retval != ACPI_TAD_WAKE_DISABLED) {
t->enabled = 1;
t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now),
(u64)retval * NSEC_PER_SEC));
rtc_time64_to_tm(rtc_tm_to_time64(&tm_now) + retval, &t->time);
} else {
t->enabled = 0;
t->time = tm_now;
@@ -795,9 +790,9 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
}
static void acpi_tad_remove(struct platform_device *pdev)
static void acpi_tad_remove(void *data)
{
struct device *dev = &pdev->dev;
struct device *dev = data;
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
device_init_wakeup(dev, false);
@@ -824,6 +819,7 @@ static int acpi_tad_probe(struct platform_device *pdev)
struct acpi_tad_driver_data *dd;
acpi_status status;
unsigned long long caps;
int ret;
/*
* Initialization failure messages are mostly about firmware issues, so
@@ -863,13 +859,21 @@ static int acpi_tad_probe(struct platform_device *pdev)
}
/*
* The platform bus type layer tells the ACPI PM domain powers up the
* device, so set the runtime PM status of it to "active".
* The platform bus type probe callback tells the ACPI PM domain to
* power up the device, so set the runtime PM status of it to "active".
*/
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_suspend(dev);
/*
* acpi_tad_remove() needs to run after unregistering the RTC class
* device to avoid racing with the latter's callbacks.
*/
ret = devm_add_action_or_reset(&pdev->dev, acpi_tad_remove, &pdev->dev);
if (ret)
return ret;
if (caps & ACPI_TAD_RT)
acpi_tad_register_rtc(dev, caps);
@@ -885,10 +889,9 @@ static struct platform_driver acpi_tad_driver = {
.driver = {
.name = "acpi-tad",
.acpi_match_table = acpi_tad_ids,
.dev_groups = acpi_tad_attr_groups,
.dev_groups = acpi_tad_groups,
},
.probe = acpi_tad_probe,
.remove = acpi_tad_remove,
};
MODULE_DEVICE_TABLE(acpi, acpi_tad_ids);
+30 -25
View File
@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
return NULL;
}
static bool is_memory_injection(u32 type, u32 flags)
{
if (flags & SETWA_FLAGS_EINJV2)
return !!(type & ACPI_EINJV2_MEMORY);
if (type & ACPI5_VENDOR_BIT)
return !!(vendor_flags & SETWA_FLAGS_MEM);
return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM);
}
/* Execute instructions in trigger error action table */
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags,
u64 param1, u64 param2)
{
struct acpi_einj_trigger trigger_tab;
@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
* This will cause resource conflict with regular memory. So
* remove it from trigger table resources.
*/
if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
if ((param_extension || acpi5) && is_memory_injection(type, flags)) {
struct apei_resources addr_resources;
apei_resources_init(&addr_resources);
@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
return rc;
trigger_paddr = apei_exec_ctx_get_output(&ctx);
if (notrigger == 0) {
rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2);
if (rc)
return rc;
}
@@ -718,28 +728,6 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
return -EINVAL;
/* check if type is a valid EINJv2 error type */
if (is_v2) {
if (!(type & available_error_type_v2))
return -EINVAL;
}
/*
* We need extra sanity checks for memory errors.
* Other types leap directly to injection.
*/
/* ensure param1/param2 existed */
if (!(param_extension || acpi5))
goto inject;
/* ensure injection is memory related */
if (type & ACPI5_VENDOR_BIT) {
if (vendor_flags != SETWA_FLAGS_MEM)
goto inject;
} else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {
goto inject;
}
/*
* Injections targeting a CXL 1.0/1.1 port have to be injected
* via the einj_cxl_rch_error_inject() path as that does the proper
@@ -748,6 +736,23 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))
return -EINVAL;
/* check if type is a valid EINJv2 error type */
if (is_v2) {
if (!(type & available_error_type_v2))
return -EINVAL;
}
/* ensure param1/param2 existed */
if (!(param_extension || acpi5))
goto inject;
/*
* We need extra sanity checks for memory errors.
* Other types leap directly to injection.
*/
if (!is_memory_injection(type, flags))
goto inject;
/*
* Disallow crazy address masks that give BIOS leeway to pick
* injection address almost anywhere. Insist on page or
+3 -3
View File
@@ -362,7 +362,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
end:
if (cmd == CMD_WRITE) {
if (unlikely(ret)) {
for_each_online_cpu(i) {
for_each_possible_cpu(i) {
struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i);
if (!desc)
@@ -524,13 +524,13 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data)
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY;
for_each_online_cpu(i) {
for_each_possible_cpu(i) {
if (i == cpu)
continue;
match_cpc_ptr = per_cpu(cpc_desc_ptr, i);
if (!match_cpc_ptr)
goto err_fault;
continue;
match_pdomain = &(match_cpc_ptr->domain_info);
if (match_pdomain->domain != pdomain->domain)
+8
View File
@@ -916,6 +916,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82K8"),
},
},
{
.callback = video_detect_force_native,
/* HP OMEN Gaming Laptop 16-n0xxx */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-n0xxx"),
},
},
/*
* x86 android tablets which directly control the backlight through
+7 -14
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 @@ out_remove_del:
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);
}
+1 -1
View File
@@ -172,7 +172,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
if (ret == -ENODATA) {
if (!deferrable)
dev_warn(dev, "Defer on undeferable control: %x\n", reg);
dev_warn(dev, "Defer on undeferrable control: %x\n", reg);
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
if (ret)
+10
View File
@@ -900,11 +900,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
-2
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);
+21 -3
View File
@@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr)
return op;
}
static struct spi_mem_op
spinand_fill_page_read_packed_op(struct spinand_device *spinand, u64 addr)
{
struct spi_mem_op op = spinand->op_templates->page_read;
op.cmd.opcode |= addr >> 16;
op.addr.val = addr & 0xFFFF;
return op;
}
struct spi_mem_op
spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr)
{
@@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand,
{
struct nand_device *nand = spinand_to_nand(spinand);
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
struct spi_mem_op op = SPINAND_OP(spinand, page_read, row);
bool packed = spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ;
struct spi_mem_op op = packed ?
SPINAND_OP(spinand, page_read_packed, row) :
SPINAND_OP(spinand, page_read, row);
return spi_mem_exec_op(spinand->spimem, &op);
}
@@ -1489,9 +1503,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand)
if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase))
return -EOPNOTSUPP;
tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read))
if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ)
tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(0);
else
tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0);
if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) {
return -EOPNOTSUPP;
}
tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0);
if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec))
+3 -3
View File
@@ -99,7 +99,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
#define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \
SPI_MEM_DTR_OP_ADDR(4, reg, 8), \
SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8))
@@ -518,7 +518,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
0,
SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
@@ -529,7 +529,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
&write_cache_octal_variants,
&update_cache_octal_variants),
0,
SPINAND_ODTR_PACKED_PAGE_READ,
SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops),
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
+3 -1
View File
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/array_size.h>
#include <linux/debugfs.h>
#include <linux/mtd/spi-nor.h>
#include <linux/spi/spi.h>
@@ -92,7 +93,8 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
seq_printf(s, "address nbytes\t%u\n", nor->addr_nbytes);
seq_puts(s, "flags\t\t");
spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names));
spi_nor_print_flags(s, nor->flags, snor_f_names,
ARRAY_SIZE(snor_f_names));
seq_puts(s, "\n");
seq_puts(s, "\nopcodes\n");
+3
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,
+60 -49
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 @@ out:
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;
}
}
+5 -3
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;
+10 -6
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;
}
+2 -1
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",
+11 -6
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);
}
+30 -21
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;
+5
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.
+22
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
+1
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)
+4 -5
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 {
+12 -40
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);
+36 -40
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.
@@ -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);
@@ -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);
+134 -12
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)
@@ -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);
+6 -1
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);
+1 -1
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 */
@@ -5549,9 +5549,12 @@ read_again:
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 @@ read_again:
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);
+2 -2
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);
+30 -19
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;
+1 -1
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");
+12 -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,
+11 -1
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);
}
+11 -4
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;
+2 -1
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;
+1
View File
@@ -1231,6 +1231,7 @@ config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator"
depends on ARM || ARM64 || COMPILE_TEST
depends on BACKLIGHT_CLASS_DEVICE
depends on GPIOLIB
depends on I2C
select REGMAP_I2C
help
+1 -2
View File
@@ -794,6 +794,7 @@ static int aml_spisg_probe(struct platform_device *pdev)
dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX);
init_completion(&spisg->completion);
ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg);
if (ret) {
dev_err(&pdev->dev, "irq request failed\n");
@@ -806,8 +807,6 @@ static int aml_spisg_probe(struct platform_device *pdev)
goto out_clk;
}
init_completion(&spisg->completion);
pm_runtime_put(&spisg->pdev->dev);
return 0;
+1 -1
View File
@@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi)
* then spi control did't work thoroughly, add one byte delay
*/
if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV)
usleep_range(10, 10);
udelay(10);
if (xspi->tx_buf)
ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++);
else
+18 -18
View File
@@ -1860,14 +1860,10 @@ static int cqspi_probe(struct platform_device *pdev)
if (irq < 0)
return -ENXIO;
ret = pm_runtime_set_active(dev);
if (ret)
return ret;
ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks);
if (ret) {
dev_err(dev, "Cannot enable QSPI clocks.\n");
goto disable_rpm;
return ret;
}
/* Obtain QSPI reset control */
@@ -1962,10 +1958,11 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->sclk = 0;
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_use_autosuspend(dev);
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
}
host->num_chipselect = cqspi->num_chipselect;
@@ -1977,7 +1974,7 @@ static int cqspi_probe(struct platform_device *pdev)
ret = cqspi_request_mmap_dma(cqspi);
if (ret == -EPROBE_DEFER) {
dev_err_probe(&pdev->dev, ret, "Failed to request mmap DMA\n");
goto disable_controller;
goto disable_rpm;
}
}
@@ -1995,14 +1992,16 @@ static int cqspi_probe(struct platform_device *pdev)
release_dma_chan:
if (cqspi->rx_chan)
dma_release_channel(cqspi->rx_chan);
disable_controller:
disable_rpm:
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
pm_runtime_dont_use_autosuspend(dev);
}
cqspi_controller_enable(cqspi, 0);
disable_clks:
if (pm_runtime_get_sync(&pdev->dev) >= 0)
clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks);
disable_rpm:
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
pm_runtime_disable(dev);
clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks);
return ret;
}
@@ -2026,18 +2025,19 @@ static void cqspi_remove(struct platform_device *pdev)
if (cqspi->rx_chan)
dma_release_channel(cqspi->rx_chan);
cqspi_controller_enable(cqspi, 0);
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
ret = pm_runtime_get_sync(&pdev->dev);
if (ret >= 0)
if (ret >= 0) {
cqspi_controller_enable(cqspi, 0);
clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks);
}
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
}
}
+13 -2
View File
@@ -741,7 +741,6 @@ static int cdns_spi_probe(struct platform_device *pdev)
/* Set to default valid value */
ctlr->max_speed_hz = xspi->clk_rate / 4;
xspi->speed_hz = ctlr->max_speed_hz;
pm_runtime_put_autosuspend(&pdev->dev);
} else {
ctlr->mode_bits |= SPI_NO_CS;
ctlr->target_abort = cdns_target_abort;
@@ -752,12 +751,17 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto clk_dis_all;
}
if (!spi_controller_is_target(ctlr))
pm_runtime_put_autosuspend(&pdev->dev);
return ret;
clk_dis_all:
if (!spi_controller_is_target(ctlr)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
}
remove_ctlr:
spi_controller_put(ctlr);
@@ -776,16 +780,23 @@ static void cdns_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
int ret = 0;
if (!spi_controller_is_target(ctlr))
ret = pm_runtime_get_sync(&pdev->dev);
spi_controller_get(ctlr);
spi_unregister_controller(ctlr);
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
if (ret >= 0)
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
if (!spi_controller_is_target(ctlr)) {
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
}
spi_controller_put(ctlr);
+2 -4
View File
@@ -98,7 +98,6 @@
#define CR0_FRF_MICROWIRE 0x2
#define CR0_XFM_OFFSET 18
#define CR0_XFM_MASK (0x03 << SPI_XFM_OFFSET)
#define CR0_XFM_TR 0x0
#define CR0_XFM_TO 0x1
#define CR0_XFM_RO 0x2
@@ -109,8 +108,6 @@
#define CR0_SOI_OFFSET 23
#define CR0_MTM_OFFSET 0x21
/* Bit fields in SER, 2bit */
#define SER_MASK 0x3
@@ -357,7 +354,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
/* When int_cs_inactive comes, spi target abort */
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) {
if (rs->cs_inactive &&
(readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) {
ctlr->target_abort(ctlr);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR);
+1 -1
View File
@@ -579,7 +579,7 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
rspi->info->find_pclk_rate(rspi->pclk, hz, &best_clock);
if (!best_clock.clk_rate)
return -EINVAL;
return 0;
ret = clk_set_rate(best_clock.clk, best_clock.clk_rate);
if (ret)
-1
View File
@@ -89,7 +89,6 @@ int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep);
int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
int smb3_parse_opt(const char *options, const char *key, char **val);
int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
int cifs_discard_remaining_data(struct TCP_Server_Info *server);
-31
View File
@@ -536,37 +536,6 @@ cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_contex
return 0;
}
int smb3_parse_opt(const char *options, const char *key, char **val)
{
int rc = -ENOENT;
char *opts, *orig, *p;
orig = opts = kstrdup(options, GFP_KERNEL);
if (!opts)
return -ENOMEM;
while ((p = strsep(&opts, ","))) {
char *nval;
if (!*p)
continue;
if (strncasecmp(p, key, strlen(key)))
continue;
nval = strchr(p, '=');
if (nval) {
if (nval == p)
continue;
*nval++ = 0;
*val = kstrdup(nval, GFP_KERNEL);
rc = !*val ? -ENOMEM : 0;
goto out;
}
}
out:
kfree(orig);
return rc;
}
/*
* Remove duplicate path delimiters. Windows is supposed to do that
* but there are some bugs that prevent rename from working if there are
+1 -1
View File
@@ -230,7 +230,7 @@ replay_again:
num_rqst = 0;
server = cifs_pick_channel(ses);
vars = kzalloc_obj(*vars, GFP_ATOMIC);
vars = kzalloc_obj(*vars, GFP_KERNEL);
if (vars == NULL) {
rc = -ENOMEM;
goto out;
+11
View File
@@ -111,10 +111,21 @@ smb2_add_credits(struct TCP_Server_Info *server,
cifs_trace_rw_credits_zero_in_flight);
}
server->in_flight--;
/*
* Rebalance credits when an op drains in_flight. For session setup,
* do this only when the total accumulated credits are high enough (>2)
* so that a newly established secondary channel can reserve credits for
* echoes and oplocks. We expect this to happen at the end of the final
* session setup response.
*/
if (server->in_flight == 0 &&
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
((optype & CIFS_OP_MASK) != CIFS_SESS_OP))
rc = change_conf(server);
else if (server->in_flight == 0 &&
((optype & CIFS_OP_MASK) == CIFS_SESS_OP) && *val > 2)
rc = change_conf(server);
/*
* Sometimes server returns 0 credits on oplock break ack - we need to
* rebalance credits in this case.
+2
View File
@@ -17,6 +17,8 @@
#include <linux/property.h>
#include <linux/types.h>
struct notifier_block;
struct acpi_handle_list {
u32 count;
acpi_handle *handles;
+6
View File
@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status {
#define ACPI_EINJ_CXL_MEM_FATAL (1<<17)
#define ACPI_EINJ_VENDOR_DEFINED (1<<31)
/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */
#define ACPI_EINJV2_PROCESSOR (1)
#define ACPI_EINJV2_MEMORY (1<<1)
#define ACPI_EINJV2_PCIE (1<<2)
/*******************************************************************************
*
* ERST - Error Record Serialization Table (ACPI 4.0)
+1
View File
@@ -286,6 +286,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);
+1 -1
View File
@@ -4,7 +4,7 @@
/*
* Maple Tree - An RCU-safe adaptive tree for storing ranges
* Copyright (c) 2018-2022 Oracle
* Authors: Liam R. Howlett <Liam.Howlett@Oracle.com>
* Authors: Liam R. Howlett <liam@infradead.org>
* Matthew Wilcox <willy@infradead.org>
*/
+1 -1
View File
@@ -4391,7 +4391,7 @@ static inline void mmap_action_map_kernel_pages_full(struct vm_area_desc *desc,
int mmap_action_prepare(struct vm_area_desc *desc);
int mmap_action_complete(struct vm_area_struct *vma,
struct mmap_action *action);
struct mmap_action *action, bool is_compat);
/* Look up the first VMA which exactly match the interval vm_start ... vm_end */
static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm,
+3
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,
+7
View File
@@ -290,6 +290,12 @@
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \
SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \
SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
#define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \
SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \
SPI_MEM_DTR_OP_ADDR(2, addr, 8), \
@@ -483,6 +489,7 @@ struct spinand_ecc_info {
#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)
#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)
#define SPINAND_NO_RAW_ACCESS BIT(4)
#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5)
/**
* struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
+29
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
+1 -1
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 */
+13
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
+15
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 */
/**
+1 -2
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) {
+13 -8
View File
@@ -762,19 +762,24 @@ int kho_add_subtree(const char *name, void *blob, size_t size)
goto out_pack;
}
err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME,
&phys, sizeof(phys));
if (err < 0)
goto out_pack;
fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME,
&phys, sizeof(phys));
if (fdt_err < 0)
goto out_del_node;
err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME,
&size_u64, sizeof(size_u64));
if (err < 0)
goto out_pack;
fdt_err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME,
&size_u64, sizeof(size_u64));
if (fdt_err < 0)
goto out_del_node;
WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob,
size, false));
err = 0;
goto out_pack;
out_del_node:
fdt_del_node(root_fdt, off);
out_pack:
fdt_pack(root_fdt);
+10 -5
View File
@@ -514,11 +514,12 @@ int luo_session_deserialize(void)
{
struct luo_session_header *sh = &luo_session_global.incoming;
static bool is_deserialized;
static int err;
static int saved_err;
int err;
/* If has been deserialized, always return the same error code */
if (is_deserialized)
return err;
return saved_err;
is_deserialized = true;
if (!sh->active)
@@ -547,7 +548,8 @@ int luo_session_deserialize(void)
pr_warn("Failed to allocate session [%.*s] during deserialization %pe\n",
(int)sizeof(sh->ser[i].name),
sh->ser[i].name, session);
return PTR_ERR(session);
err = PTR_ERR(session);
goto save_err;
}
err = luo_session_insert(sh, session);
@@ -555,7 +557,7 @@ int luo_session_deserialize(void)
pr_warn("Failed to insert session [%s] %pe\n",
session->name, ERR_PTR(err));
luo_session_free(session);
return err;
goto save_err;
}
scoped_guard(mutex, &session->mutex) {
@@ -565,7 +567,7 @@ int luo_session_deserialize(void)
if (err) {
pr_warn("Failed to deserialize files for session [%s] %pe\n",
session->name, ERR_PTR(err));
return err;
goto save_err;
}
}
@@ -574,6 +576,9 @@ int luo_session_deserialize(void)
sh->ser = NULL;
return 0;
save_err:
saved_err = err;
return err;
}
int luo_session_serialize(void)
+1 -1
View File
@@ -2,7 +2,7 @@
/*
* Maple Tree implementation
* Copyright (c) 2018-2022 Oracle Corporation
* Authors: Liam R. Howlett <Liam.Howlett@oracle.com>
* Authors: Liam R. Howlett <liam@infradead.org>
* Matthew Wilcox <willy@infradead.org>
* Copyright (c) 2023 ByteDance
* Author: Peng Zhang <zhangpeng.00@bytedance.com>
+2 -2
View File
@@ -2,7 +2,7 @@
/*
* test_maple_tree.c: Test the maple tree API
* Copyright (c) 2018-2022 Oracle Corporation
* Author: Liam R. Howlett <Liam.Howlett@Oracle.com>
* Author: Liam R. Howlett <liam@infradead.org>
*
* Any tests that only require the interface of the tree.
*/
@@ -4021,6 +4021,6 @@ static void __exit maple_tree_harvest(void)
module_init(maple_tree_seed);
module_exit(maple_tree_harvest);
MODULE_AUTHOR("Liam R. Howlett <Liam.Howlett@Oracle.com>");
MODULE_AUTHOR("Liam R. Howlett <liam@infradead.org>");
MODULE_DESCRIPTION("maple tree API test module");
MODULE_LICENSE("GPL");
+55 -30
View File
@@ -161,15 +161,6 @@ module_param(monitor_region_end, ulong, 0600);
*/
static unsigned long addr_unit __read_mostly = 1;
/*
* PID of the DAMON thread
*
* If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
* Else, -1.
*/
static int kdamond_pid __read_mostly = -1;
module_param(kdamond_pid, int, 0400);
static struct damos_stat damon_lru_sort_hot_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat,
lru_sort_tried_hot_regions, lru_sorted_hot_regions,
@@ -386,12 +377,8 @@ static int damon_lru_sort_turn(bool on)
{
int err;
if (!on) {
err = damon_stop(&ctx, 1);
if (!err)
kdamond_pid = -1;
return err;
}
if (!on)
return damon_stop(&ctx, 1);
err = damon_lru_sort_apply_parameters();
if (err)
@@ -400,9 +387,6 @@ static int damon_lru_sort_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
kdamond_pid = damon_kdamond_pid(ctx);
if (kdamond_pid < 0)
return kdamond_pid;
return damon_call(ctx, &call_control);
}
@@ -430,42 +414,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
MODULE_PARM_DESC(addr_unit,
"Scale factor for DAMON_LRU_SORT to ops address conversion (default: 1)");
static bool damon_lru_sort_enabled(void)
{
if (!ctx)
return false;
return damon_is_running(ctx);
}
static int damon_lru_sort_enabled_store(const char *val,
const struct kernel_param *kp)
{
bool is_enabled = enabled;
bool enable;
int err;
err = kstrtobool(val, &enable);
err = kstrtobool(val, &enabled);
if (err)
return err;
if (is_enabled == enable)
if (damon_lru_sort_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!damon_initialized())
goto set_param_out;
return 0;
err = damon_lru_sort_turn(enable);
if (err)
return err;
return damon_lru_sort_turn(enabled);
}
set_param_out:
enabled = enable;
return err;
static int damon_lru_sort_enabled_load(char *buffer,
const struct kernel_param *kp)
{
return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_lru_sort_enabled_store,
.get = param_get_bool,
.get = damon_lru_sort_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_LRU_SORT (default: disabled)");
static int damon_lru_sort_kdamond_pid_store(const char *val,
const struct kernel_param *kp)
{
/*
* kdamond_pid is read-only, but kernel command line could write it.
* Do nothing here.
*/
return 0;
}
static int damon_lru_sort_kdamond_pid_load(char *buffer,
const struct kernel_param *kp)
{
int kdamond_pid = -1;
if (ctx) {
kdamond_pid = damon_kdamond_pid(ctx);
if (kdamond_pid < 0)
kdamond_pid = -1;
}
return sprintf(buffer, "%d\n", kdamond_pid);
}
static const struct kernel_param_ops kdamond_pid_param_ops = {
.set = damon_lru_sort_kdamond_pid_store,
.get = damon_lru_sort_kdamond_pid_load,
};
/*
* PID of the DAMON thread
*
* If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
* Else, -1.
*/
module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
static int __init damon_lru_sort_init(void)
{
int err;
+55 -30
View File
@@ -144,15 +144,6 @@ static unsigned long addr_unit __read_mostly = 1;
static bool skip_anon __read_mostly;
module_param(skip_anon, bool, 0600);
/*
* PID of the DAMON thread
*
* If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
* Else, -1.
*/
static int kdamond_pid __read_mostly = -1;
module_param(kdamond_pid, int, 0400);
static struct damos_stat damon_reclaim_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
reclaim_tried_regions, reclaimed_regions, quota_exceeds);
@@ -288,12 +279,8 @@ static int damon_reclaim_turn(bool on)
{
int err;
if (!on) {
err = damon_stop(&ctx, 1);
if (!err)
kdamond_pid = -1;
return err;
}
if (!on)
return damon_stop(&ctx, 1);
err = damon_reclaim_apply_parameters();
if (err)
@@ -302,9 +289,6 @@ static int damon_reclaim_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
kdamond_pid = damon_kdamond_pid(ctx);
if (kdamond_pid < 0)
return kdamond_pid;
return damon_call(ctx, &call_control);
}
@@ -332,42 +316,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
MODULE_PARM_DESC(addr_unit,
"Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)");
static bool damon_reclaim_enabled(void)
{
if (!ctx)
return false;
return damon_is_running(ctx);
}
static int damon_reclaim_enabled_store(const char *val,
const struct kernel_param *kp)
{
bool is_enabled = enabled;
bool enable;
int err;
err = kstrtobool(val, &enable);
err = kstrtobool(val, &enabled);
if (err)
return err;
if (is_enabled == enable)
if (damon_reclaim_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!damon_initialized())
goto set_param_out;
return 0;
err = damon_reclaim_turn(enable);
if (err)
return err;
return damon_reclaim_turn(enabled);
}
set_param_out:
enabled = enable;
return err;
static int damon_reclaim_enabled_load(char *buffer,
const struct kernel_param *kp)
{
return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_reclaim_enabled_store,
.get = param_get_bool,
.get = damon_reclaim_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_RECLAIM (default: disabled)");
static int damon_reclaim_kdamond_pid_store(const char *val,
const struct kernel_param *kp)
{
/*
* kdamond_pid is read-only, but kernel command line could write it.
* Do nothing here.
*/
return 0;
}
static int damon_reclaim_kdamond_pid_load(char *buffer,
const struct kernel_param *kp)
{
int kdamond_pid = -1;
if (ctx) {
kdamond_pid = damon_kdamond_pid(ctx);
if (kdamond_pid < 0)
kdamond_pid = -1;
}
return sprintf(buffer, "%d\n", kdamond_pid);
}
static const struct kernel_param_ops kdamond_pid_param_ops = {
.set = damon_reclaim_kdamond_pid_store,
.get = damon_reclaim_kdamond_pid_load,
};
/*
* PID of the DAMON thread
*
* If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
* Else, -1.
*/
module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
static int __init damon_reclaim_init(void)
{
int err;
+20 -10
View File
@@ -19,14 +19,17 @@
static int damon_stat_enabled_store(
const char *val, const struct kernel_param *kp);
static int damon_stat_enabled_load(char *buffer,
const struct kernel_param *kp);
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_stat_enabled_store,
.get = param_get_bool,
.get = damon_stat_enabled_load,
};
static bool enabled __read_mostly = IS_ENABLED(
CONFIG_DAMON_STAT_ENABLED_DEFAULT);
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
module_param_cb(enabled, &enabled_param_ops, NULL, 0600);
MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT");
static unsigned long estimated_memory_bandwidth __read_mostly;
@@ -273,17 +276,23 @@ static void damon_stat_stop(void)
damon_stat_context = NULL;
}
static bool damon_stat_enabled(void)
{
if (!damon_stat_context)
return false;
return damon_is_running(damon_stat_context);
}
static int damon_stat_enabled_store(
const char *val, const struct kernel_param *kp)
{
bool is_enabled = enabled;
int err;
err = kstrtobool(val, &enabled);
if (err)
return err;
if (is_enabled == enabled)
if (damon_stat_enabled() == enabled)
return 0;
if (!damon_initialized())
@@ -293,16 +302,17 @@ static int damon_stat_enabled_store(
*/
return 0;
if (enabled) {
err = damon_stat_start();
if (err)
enabled = false;
return err;
}
if (enabled)
return damon_stat_start();
damon_stat_stop();
return 0;
}
static int damon_stat_enabled_load(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N');
}
static int __init damon_stat_init(void)
{
int err = 0;
+22 -2
View File
@@ -533,9 +533,14 @@ static ssize_t memcg_path_show(struct kobject *kobj,
{
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
int len;
return sysfs_emit(buf, "%s\n",
if (!mutex_trylock(&damon_sysfs_lock))
return -EBUSY;
len = sysfs_emit(buf, "%s\n",
filter->memcg_path ? filter->memcg_path : "");
mutex_unlock(&damon_sysfs_lock);
return len;
}
static ssize_t memcg_path_store(struct kobject *kobj,
@@ -550,8 +555,13 @@ static ssize_t memcg_path_store(struct kobject *kobj,
return -ENOMEM;
strscpy(path, buf, count + 1);
if (!mutex_trylock(&damon_sysfs_lock)) {
kfree(path);
return -EBUSY;
}
kfree(filter->memcg_path);
filter->memcg_path = path;
mutex_unlock(&damon_sysfs_lock);
return count;
}
@@ -1187,8 +1197,13 @@ static ssize_t path_show(struct kobject *kobj,
{
struct damos_sysfs_quota_goal *goal = container_of(kobj,
struct damos_sysfs_quota_goal, kobj);
int len;
return sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
if (!mutex_trylock(&damon_sysfs_lock))
return -EBUSY;
len = sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
mutex_unlock(&damon_sysfs_lock);
return len;
}
static ssize_t path_store(struct kobject *kobj,
@@ -1203,8 +1218,13 @@ static ssize_t path_store(struct kobject *kobj,
return -ENOMEM;
strscpy(path, buf, count + 1);
if (!mutex_trylock(&damon_sysfs_lock)) {
kfree(path);
return -EBUSY;
}
kfree(goal->path);
goal->path = path;
mutex_unlock(&damon_sysfs_lock);
return count;
}
+1
View File
@@ -204,6 +204,7 @@ void __init hugetlb_cma_reserve(void)
*/
per_node = DIV_ROUND_UP(hugetlb_cma_size,
nodes_weight(hugetlb_bootmem_nodes));
per_node = round_up(per_node, PAGE_SIZE << order);
pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
}
+19 -10
View File
@@ -805,12 +805,17 @@ static long memcg_state_val_in_pages(int idx, long val)
* Used in mod_memcg_state() and mod_memcg_lruvec_state() to avoid race with
* reparenting of non-hierarchical state_locals.
*/
static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg)
static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg,
bool *rcu_locked)
{
if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
/* Rebinding can cause this value to be changed at runtime */
if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
*rcu_locked = false;
return memcg;
}
rcu_read_lock();
*rcu_locked = true;
while (memcg_is_dying(memcg))
memcg = parent_mem_cgroup(memcg);
@@ -818,20 +823,21 @@ static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *me
return memcg;
}
static inline void get_non_dying_memcg_end(void)
static inline void get_non_dying_memcg_end(bool rcu_locked)
{
if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
if (!rcu_locked)
return;
rcu_read_unlock();
}
#else
static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg)
static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg,
bool *rcu_locked)
{
return memcg;
}
static inline void get_non_dying_memcg_end(void)
static inline void get_non_dying_memcg_end(bool rcu_locked)
{
}
#endif
@@ -865,12 +871,14 @@ static void __mod_memcg_state(struct mem_cgroup *memcg,
void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx,
int val)
{
bool rcu_locked = false;
if (mem_cgroup_disabled())
return;
memcg = get_non_dying_memcg_start(memcg);
memcg = get_non_dying_memcg_start(memcg, &rcu_locked);
__mod_memcg_state(memcg, idx, val);
get_non_dying_memcg_end();
get_non_dying_memcg_end(rcu_locked);
}
#ifdef CONFIG_MEMCG_V1
@@ -933,14 +941,15 @@ static void mod_memcg_lruvec_state(struct lruvec *lruvec,
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
struct mem_cgroup_per_node *pn;
struct mem_cgroup *memcg;
bool rcu_locked = false;
pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
memcg = get_non_dying_memcg_start(pn->memcg);
memcg = get_non_dying_memcg_start(pn->memcg, &rcu_locked);
pn = memcg->nodeinfo[pgdat->node_id];
__mod_memcg_lruvec_state(pn, idx, val);
get_non_dying_memcg_end();
get_non_dying_memcg_end(rcu_locked);
}
/**
+6 -10
View File
@@ -1835,7 +1835,9 @@ static int balance_dirty_pages(struct bdi_writeback *wb,
balance_domain_limits(mdtc, strictlimit);
}
if (nr_dirty > gdtc->bg_thresh && !writeback_in_progress(wb))
if (!writeback_in_progress(wb) &&
(nr_dirty > gdtc->bg_thresh ||
(strictlimit && gdtc->wb_dirty > gdtc->wb_bg_thresh)))
wb_start_background_writeback(wb);
/*
@@ -1862,15 +1864,9 @@ free_running:
* Unconditionally start background writeback if it's not
* already in progress. We need to do this because the global
* dirty threshold check above (nr_dirty > gdtc->bg_thresh)
* doesn't account for these cases:
*
* a) strictlimit BDIs: throttling is calculated using per-wb
* thresholds. The per-wb threshold can be exceeded even when
* nr_dirty < gdtc->bg_thresh
*
* b) memcg-based throttling: memcg uses its own dirty count and
* thresholds and can trigger throttling even when global
* nr_dirty < gdtc->bg_thresh
* doesn't account for the memcg-based throttling case. memcg
* uses its own dirty count and thresholds and can trigger
* throttling even when global nr_dirty < gdtc->bg_thresh
*
* Writeback needs to be started else the writer stalls in the
* throttle loop waiting for dirty pages to be written back
+11 -1
View File
@@ -443,8 +443,10 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
return ret;
}
static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio)
static int mfill_copy_folio_retry(struct mfill_state *state,
struct folio *folio)
{
const struct vm_uffd_ops *orig_ops = vma_uffd_ops(state->vma);
unsigned long src_addr = state->src_addr;
void *kaddr;
int err;
@@ -465,6 +467,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio
if (err)
return err;
/*
* The VMA type may have changed while the lock was dropped
* (e.g. replaced with a hugetlb mapping), making the caller's
* ops pointer stale.
*/
if (vma_uffd_ops(state->vma) != orig_ops)
return -EAGAIN;
err = mfill_establish_pmd(state);
if (err)
return err;
+17 -9
View File
@@ -1237,7 +1237,7 @@ int __compat_vma_mmap(struct vm_area_desc *desc,
/* Update the VMA from the descriptor. */
compat_set_vma_from_desc(vma, desc);
/* Complete any specified mmap actions. */
return mmap_action_complete(vma, &desc->action);
return mmap_action_complete(vma, &desc->action, /*is_compat=*/true);
}
EXPORT_SYMBOL(__compat_vma_mmap);
@@ -1394,7 +1394,8 @@ static int call_vma_mapped(struct vm_area_struct *vma)
}
static int mmap_action_finish(struct vm_area_struct *vma,
struct mmap_action *action, int err)
struct mmap_action *action, int err,
bool is_compat)
{
size_t len;
@@ -1405,8 +1406,12 @@ static int mmap_action_finish(struct vm_area_struct *vma,
/* do_munmap() might take rmap lock, so release if held. */
maybe_rmap_unlock_action(vma, action);
if (!err)
return 0;
/*
* If this is invoked from the compatibility layer, post-mmap() hook
* logic will handle cleanup for us.
*/
if (!err || is_compat)
return err;
/*
* If an error occurs, unmap the VMA altogether and return an error. We
@@ -1456,13 +1461,15 @@ EXPORT_SYMBOL(mmap_action_prepare);
* mmap_action_complete - Execute VMA descriptor action.
* @vma: The VMA to perform the action upon.
* @action: The action to perform.
* @is_compat: Is this being invoked from the compatibility layer?
*
* Similar to mmap_action_prepare().
*
* Return: 0 on success, or error, at which point the VMA will be unmapped.
* Return: 0 on success, or error, at which point the VMA will be unmapped if
* !@is_compat.
*/
int mmap_action_complete(struct vm_area_struct *vma,
struct mmap_action *action)
struct mmap_action *action, bool is_compat)
{
int err = 0;
@@ -1483,7 +1490,7 @@ int mmap_action_complete(struct vm_area_struct *vma,
break;
}
return mmap_action_finish(vma, action, err);
return mmap_action_finish(vma, action, err, is_compat);
}
EXPORT_SYMBOL(mmap_action_complete);
#else
@@ -1505,7 +1512,8 @@ int mmap_action_prepare(struct vm_area_desc *desc)
EXPORT_SYMBOL(mmap_action_prepare);
int mmap_action_complete(struct vm_area_struct *vma,
struct mmap_action *action)
struct mmap_action *action,
bool is_compat)
{
int err = 0;
@@ -1522,7 +1530,7 @@ int mmap_action_complete(struct vm_area_struct *vma,
break;
}
return mmap_action_finish(vma, action, err);
return mmap_action_finish(vma, action, err, is_compat);
}
EXPORT_SYMBOL(mmap_action_complete);
#endif
+2 -1
View File
@@ -2780,7 +2780,8 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
__mmap_complete(&map, vma);
if (have_mmap_prepare && allocated_new) {
error = mmap_action_complete(vma, &desc.action);
error = mmap_action_complete(vma, &desc.action,
/*is_compat=*/false);
if (error)
return error;
}
+1 -1
View File
@@ -4361,7 +4361,7 @@ need_realloc:
return NULL;
if (p) {
memcpy(n, p, old_size);
memcpy(n, p, min(size, old_size));
vfree(p);
}
+1 -2
View File
@@ -297,8 +297,7 @@ net_devmem_bind_dmabuf(struct net_device *dev,
for (i = 0; i < owner->area.num_niovs; i++) {
niov = &owner->area.niovs[i];
niov->type = NET_IOV_DMABUF;
niov->owner = &owner->area;
net_iov_init(niov, &owner->area, NET_IOV_DMABUF);
page_pool_set_dma_addr_netmem(net_iov_to_netmem(niov),
net_devmem_get_dma_addr(niov));
if (direction == DMA_TO_DEVICE)
+5 -5
View File
@@ -3210,8 +3210,10 @@ int neigh_xmit(int index, struct net_device *dev,
rcu_read_lock();
tbl = rcu_dereference(neigh_tables[index]);
if (!tbl)
goto out_unlock;
if (!tbl) {
rcu_read_unlock();
goto out_kfree_skb;
}
if (index == NEIGH_ARP_TABLE) {
u32 key = *((u32 *)addr);
@@ -3227,7 +3229,6 @@ int neigh_xmit(int index, struct net_device *dev,
goto out_kfree_skb;
}
err = READ_ONCE(neigh->output)(neigh, skb);
out_unlock:
rcu_read_unlock();
}
else if (index == NEIGH_LINK_TABLE) {
@@ -3237,11 +3238,10 @@ out_unlock:
goto out_kfree_skb;
err = dev_queue_xmit(skb);
}
out:
return err;
out_kfree_skb:
kfree_skb(skb);
goto out;
return err;
}
EXPORT_SYMBOL(neigh_xmit);
+18 -1
View File
@@ -704,6 +704,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
return 0;
}
/*
* Test whether the caller left np->local_ip unset, so that
* netpoll_setup() should auto-populate it from the egress device.
*
* np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
* so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2,
* IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm —
* doing so would misclassify a caller-supplied address as unset and
* silently overwrite it with whatever address the device exposes.
*/
static bool netpoll_local_ip_unset(const struct netpoll *np)
{
if (np->ipv6)
return ipv6_addr_any(&np->local_ip.in6);
return !np->local_ip.ip;
}
int netpoll_setup(struct netpoll *np)
{
struct net *net = current->nsproxy->net_ns;
@@ -747,7 +764,7 @@ int netpoll_setup(struct netpoll *np)
rtnl_lock();
}
if (!np->local_ip.ip) {
if (netpoll_local_ip_unset(np)) {
if (!np->ipv6) {
err = netpoll_take_ipv4(np, ndev);
if (err)
+5 -5
View File
@@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool)
if (!pool->system)
free_percpu(pool->recycle_stats);
#endif
if (pool->mp_ops) {
pool->mp_ops->destroy(pool);
static_branch_dec(&page_pool_mem_providers);
}
}
/**
@@ -1146,11 +1151,6 @@ static void __page_pool_destroy(struct page_pool *pool)
page_pool_unlist(pool);
page_pool_uninit(pool);
if (pool->mp_ops) {
pool->mp_ops->destroy(pool);
static_branch_dec(&page_pool_mem_providers);
}
kfree(pool);
}
+58 -50
View File
@@ -151,16 +151,6 @@ static struct mr_table *__ipmr_get_table(struct net *net, u32 id)
return NULL;
}
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
{
struct mr_table *mrt;
rcu_read_lock();
mrt = __ipmr_get_table(net, id);
rcu_read_unlock();
return mrt;
}
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
struct mr_table **mrt)
{
@@ -293,7 +283,7 @@ static void __net_exit ipmr_rules_exit_rtnl(struct net *net,
struct mr_table *mrt, *next;
list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
list_del(&mrt->list);
list_del_rcu(&mrt->list);
ipmr_free_table(mrt, dev_kill_list);
}
}
@@ -315,28 +305,30 @@ bool ipmr_rule_default(const struct fib_rule *rule)
}
EXPORT_SYMBOL(ipmr_rule_default);
#else
#define ipmr_for_each_table(mrt, net) \
for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
static struct mr_table *ipmr_mr_table_iter(struct net *net,
struct mr_table *mrt)
{
if (!mrt)
return net->ipv4.mrt;
return rcu_dereference(net->ipv4.mrt);
return NULL;
}
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
static struct mr_table *__ipmr_get_table(struct net *net, u32 id)
{
return net->ipv4.mrt;
return rcu_dereference_check(net->ipv4.mrt,
lockdep_rtnl_is_held() ||
!rcu_access_pointer(net->ipv4.mrt));
}
#define __ipmr_get_table ipmr_get_table
#define ipmr_for_each_table(mrt, net) \
for (mrt = __ipmr_get_table(net, 0); mrt; mrt = NULL)
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
struct mr_table **mrt)
{
*mrt = net->ipv4.mrt;
*mrt = rcu_dereference(net->ipv4.mrt);
if (!*mrt)
return -EAGAIN;
return 0;
}
@@ -347,7 +339,8 @@ static int __net_init ipmr_rules_init(struct net *net)
mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
if (IS_ERR(mrt))
return PTR_ERR(mrt);
net->ipv4.mrt = mrt;
rcu_assign_pointer(net->ipv4.mrt, mrt);
return 0;
}
@@ -358,9 +351,10 @@ static void __net_exit ipmr_rules_exit(struct net *net)
static void __net_exit ipmr_rules_exit_rtnl(struct net *net,
struct list_head *dev_kill_list)
{
ipmr_free_table(net->ipv4.mrt, dev_kill_list);
struct mr_table *mrt = rcu_dereference_protected(net->ipv4.mrt, 1);
net->ipv4.mrt = NULL;
RCU_INIT_POINTER(net->ipv4.mrt, NULL);
ipmr_free_table(mrt, dev_kill_list);
}
static int ipmr_rules_dump(struct net *net, struct notifier_block *nb,
@@ -381,6 +375,17 @@ bool ipmr_rule_default(const struct fib_rule *rule)
EXPORT_SYMBOL(ipmr_rule_default);
#endif
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
{
struct mr_table *mrt;
rcu_read_lock();
mrt = __ipmr_get_table(net, id);
rcu_read_unlock();
return mrt;
}
static inline int ipmr_hash_cmp(struct rhashtable_compare_arg *arg,
const void *ptr)
{
@@ -441,12 +446,11 @@ static void ipmr_free_table(struct mr_table *mrt, struct list_head *dev_kill_lis
WARN_ON_ONCE(!mr_can_free_table(net));
timer_shutdown_sync(&mrt->ipmr_expire_timer);
mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC |
MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC,
&ipmr_dev_kill_list);
rhltable_destroy(&mrt->mfc_hash);
kfree(mrt);
timer_shutdown_sync(&mrt->ipmr_expire_timer);
mr_table_free(mrt);
WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list));
list_splice(&ipmr_dev_kill_list, dev_kill_list);
@@ -1135,12 +1139,19 @@ static int ipmr_cache_report(const struct mr_table *mrt,
static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
struct sk_buff *skb, struct net_device *dev)
{
struct net *net = read_pnet(&mrt->net);
const struct iphdr *iph = ip_hdr(skb);
struct mfc_cache *c;
struct mfc_cache *c = NULL;
bool found = false;
int err;
spin_lock_bh(&mfc_unres_lock);
if (!check_net(net)) {
err = -EINVAL;
goto err;
}
list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
if (c->mfc_mcastgrp == iph->daddr &&
c->mfc_origin == iph->saddr) {
@@ -1153,10 +1164,8 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
/* Create a new entry if allowable */
c = ipmr_cache_alloc_unres();
if (!c) {
spin_unlock_bh(&mfc_unres_lock);
kfree_skb(skb);
return -ENOBUFS;
err = -ENOBUFS;
goto err;
}
/* Fill in the new cache entry */
@@ -1166,17 +1175,8 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
/* Reflect first query at mrouted. */
err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
if (err < 0) {
/* If the report failed throw the cache entry
out - Brad Parker
*/
spin_unlock_bh(&mfc_unres_lock);
ipmr_cache_free(c);
kfree_skb(skb);
return err;
}
if (err < 0)
goto err;
atomic_inc(&mrt->cache_resolve_queue_len);
list_add(&c->_c.list, &mrt->mfc_unres_queue);
@@ -1189,18 +1189,26 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
/* See if we can append the packet */
if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
kfree_skb(skb);
c = NULL;
err = -ENOBUFS;
} else {
if (dev) {
skb->dev = dev;
skb->skb_iif = dev->ifindex;
}
skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
err = 0;
goto err;
}
if (dev) {
skb->dev = dev;
skb->skb_iif = dev->ifindex;
}
skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
spin_unlock_bh(&mfc_unres_lock);
return 0;
err:
spin_unlock_bh(&mfc_unres_lock);
if (c)
ipmr_cache_free(c);
kfree_skb(skb);
return err;
}
@@ -1346,7 +1354,7 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags,
}
if (flags & MRT_FLUSH_MFC) {
if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
if (atomic_read(&mrt->cache_resolve_queue_len) != 0 || !check_net(net)) {
spin_lock_bh(&mfc_unres_lock);
list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
list_del(&c->list);
+16
View File
@@ -28,6 +28,20 @@ void vif_device_init(struct vif_device *v,
v->link = dev->ifindex;
}
static void __mr_free_table(struct work_struct *work)
{
struct mr_table *mrt = container_of(to_rcu_work(work),
struct mr_table, work);
rhltable_destroy(&mrt->mfc_hash);
kfree(mrt);
}
void mr_table_free(struct mr_table *mrt)
{
queue_rcu_work(system_unbound_wq, &mrt->work);
}
struct mr_table *
mr_table_alloc(struct net *net, u32 id,
struct mr_table_ops *ops,
@@ -50,6 +64,8 @@ mr_table_alloc(struct net *net, u32 id,
kfree(mrt);
return ERR_PTR(err);
}
INIT_RCU_WORK(&mrt->work, __mr_free_table);
INIT_LIST_HEAD(&mrt->mfc_cache_list);
INIT_LIST_HEAD(&mrt->mfc_unres_queue);
+15 -3
View File
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
arpptr += dev->addr_len;
memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32);
tgt_devaddr = arpptr;
arpptr += dev->addr_len;
if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) {
if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0,
sizeof(arpinfo->tgt_devaddr.mask))))
return 0;
tgt_devaddr = NULL;
} else {
tgt_devaddr = arpptr;
arpptr += dev->addr_len;
}
memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
dev->addr_len)) ||
dev->addr_len)))
return 0;
if (tgt_devaddr &&
NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
dev->addr_len)))
+8
View File
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += pln;
if (mangle->flags & ARPT_MANGLE_TDEV) {
if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
skb->dev->type == ARPHRD_IEEE1394))
return NF_DROP;
if (ARPT_DEV_ADDR_LEN_MAX < hln ||
(arpptr + hln > skb_tail_pointer(skb)))
return NF_DROP;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += hln;
if (mangle->flags & ARPT_MANGLE_TIP) {
if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
skb->dev->type == ARPHRD_IEEE1394))
return NF_DROP;
if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
(arpptr + pln > skb_tail_pointer(skb)))
return NF_DROP;
+3 -2
View File
@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
u32 remaining, user_timeout;
u32 user_timeout;
s32 remaining;
s32 elapsed;
user_timeout = READ_ONCE(icsk->icsk_user_timeout);
@@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
if (unlikely(elapsed < 0))
elapsed = 0;
remaining = msecs_to_jiffies(user_timeout) - elapsed;
remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
return min_t(u32, remaining, when);
}
+6 -3
View File
@@ -491,6 +491,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
struct net *net = dev_net(skb->dev);
struct inet6_dev *idev;
struct ipv6hdr *oldhdr;
unsigned int chdr_len;
unsigned char *buf;
int accept_rpl_seg;
int i, err;
@@ -592,8 +593,10 @@ looped_back:
skb_pull(skb, ((hdr->hdrlen + 1) << 3));
skb_postpull_rcsum(skb, oldhdr,
sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
if (unlikely(!hdr->segments_left)) {
if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3);
if (unlikely(!hdr->segments_left ||
skb_headroom(skb) < chdr_len + skb->mac_len)) {
if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0,
GFP_ATOMIC)) {
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
@@ -603,7 +606,7 @@ looped_back:
oldhdr = ipv6_hdr(skb);
}
skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
skb_push(skb, chdr_len);
skb_reset_network_header(skb);
skb_mac_header_rebuild(skb);
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+9
View File
@@ -287,7 +287,16 @@ static int rpl_input(struct sk_buff *skb)
if (!dst) {
ip6_route_input(skb);
/* ip6_route_input() sets a NOREF dst; force a refcount on it
* before caching or further use.
*/
skb_dst_force(skb);
dst = skb_dst(skb);
if (unlikely(!dst)) {
err = -ENETUNREACH;
goto drop;
}
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
+9
View File
@@ -515,7 +515,16 @@ static int seg6_input_core(struct net *net, struct sock *sk,
if (!dst) {
ip6_route_input(skb);
/* ip6_route_input() sets a NOREF dst; force a refcount on it
* before caching or further use.
*/
skb_dst_force(skb);
dst = skb_dst(skb);
if (unlikely(!dst)) {
err = -ENETUNREACH;
goto drop;
}
/* cache only if we don't create a dst reference loop */
if (!dst->error && lwtst != dst->lwtstate) {
+1
View File
@@ -1278,6 +1278,7 @@ static void __reset_counters(struct pm_nl_pernet *pernet)
WRITE_ONCE(pernet->endp_signal_max, 0);
WRITE_ONCE(pernet->endp_subflow_max, 0);
WRITE_ONCE(pernet->endp_laminar_max, 0);
WRITE_ONCE(pernet->endp_fullmesh_max, 0);
pernet->endpoints = 0;
}
+2 -1
View File
@@ -3302,7 +3302,8 @@ bool __mptcp_close(struct sock *sk, long timeout)
goto cleanup;
}
if (mptcp_data_avail(msk) || timeout < 0) {
if (mptcp_data_avail(msk) || timeout < 0 ||
(sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
/* If the msk has read data, or the caller explicitly ask it,
* do the MPTCP equivalent of TCP reset, aka MPTCP fastclose
*/
+6 -6
View File
@@ -159,10 +159,10 @@ static int mptcp_setsockopt_sol_socket_tstamp(struct mptcp_sock *msk, int optnam
lock_sock(sk);
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
bool slow = lock_sock_fast(ssk);
sock_set_timestamp(sk, optname, !!val);
unlock_sock_fast(ssk, slow);
lock_sock(ssk);
sock_set_timestamp(ssk, optname, !!val);
release_sock(ssk);
}
release_sock(sk);
@@ -235,10 +235,10 @@ static int mptcp_setsockopt_sol_socket_timestamping(struct mptcp_sock *msk,
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
bool slow = lock_sock_fast(ssk);
sock_set_timestamping(sk, optname, timestamping);
unlock_sock_fast(ssk, slow);
lock_sock(ssk);
sock_set_timestamping(ssk, optname, timestamping);
release_sock(ssk);
}
release_sock(sk);
+7 -3
View File
@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
if (!ih)
goto out_unlock;
if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir])
ct->proto.sctp.init[!dir] = 0;
ct->proto.sctp.init[dir] = 1;
/* Do not record INIT matching peer vtag (stale or retransmitted INIT). */
if (old_state == SCTP_CONNTRACK_NONE ||
ct->proto.sctp.vtag[!dir] != ih->init_tag) {
if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir])
ct->proto.sctp.init[!dir] = 0;
ct->proto.sctp.init[dir] = 1;
}
pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir);
ct->proto.sctp.vtag[!dir] = ih->init_tag;
+118 -34
View File
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
return 1;
}
/* Parse optional port number after IP address.
* Returns false on malformed input, true otherwise.
* If port is non-NULL, stores parsed port in network byte order.
* If no port is present, sets *port to default SIP port.
*/
static bool sip_parse_port(const char *dptr, const char **endp,
const char *limit, __be16 *port)
{
unsigned int p = 0;
int len = 0;
if (dptr >= limit)
return false;
if (*dptr != ':') {
if (port)
*port = htons(SIP_PORT);
if (endp)
*endp = dptr;
return true;
}
dptr++; /* skip ':' */
while (dptr < limit && isdigit(*dptr)) {
p = p * 10 + (*dptr - '0');
dptr++;
len++;
if (len > 5) /* max "65535" */
return false;
}
if (len == 0)
return false;
/* reached limit while parsing port */
if (dptr >= limit)
return false;
if (p < 1024 || p > 65535)
return false;
if (port)
*port = htons(p);
if (endp)
*endp = dptr;
return true;
}
/* skip ip address. returns its length. */
static int epaddr_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
return 0;
}
/* Port number */
if (*dptr == ':') {
dptr++;
dptr += digits_len(ct, dptr, limit, shift);
}
if (!sip_parse_port(dptr, &dptr, limit, NULL))
return 0;
return dptr - aux;
}
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
return epaddr_len(ct, dptr, limit, shift);
}
/* simple_strtoul stops after first non-number character.
* But as we're not dealing with c-strings, we can't rely on
* hitting \r,\n,\0 etc. before moving past end of buffer.
*
* This is a variant of simple_strtoul, but doesn't require
* a c-string.
*
* If value exceeds UINT_MAX, 0 is returned.
*/
static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp)
{
const unsigned int max = sizeof("4294967295");
unsigned int olen = len;
const char *s = cp;
u64 result = 0;
if (len > max)
len = max;
while (olen > 0 && isdigit(*s)) {
unsigned int value;
if (len == 0)
goto err;
value = *s - '0';
result = result * 10 + value;
if (result > UINT_MAX)
goto err;
s++;
len--;
olen--;
}
if (endp)
*endp = (char *)s;
return result;
err:
if (endp)
*endp = (char *)cp;
return 0;
}
/* Parse a SIP request line of the form:
*
* Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct,
{
const char *start = dptr, *limit = dptr + datalen, *end;
unsigned int mlen;
unsigned int p;
int shift = 0;
/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,
if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
return -1;
if (end < limit && *end == ':') {
end++;
p = simple_strtoul(end, (char **)&end, 10);
if (p < 1024 || p > 65535)
return -1;
*port = htons(p);
} else
*port = htons(SIP_PORT);
if (!sip_parse_port(end, &end, limit, port))
return -1;
if (end == dptr)
return 0;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
union nf_inet_addr *addr, __be16 *port)
{
const char *c, *limit = dptr + datalen;
unsigned int p;
int ret;
ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
return -1;
if (*c == ':') {
c++;
p = simple_strtoul(c, (char **)&c, 10);
if (p < 1024 || p > 65535)
return -1;
*port = htons(p);
} else
*port = htons(SIP_PORT);
if (!sip_parse_port(c, &c, limit, port))
return -1;
if (dataoff)
*dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
return 0;
start += strlen(name);
*val = simple_strtoul(start, &end, 0);
*val = sip_strtouint(start, limit - start, (char **)&end);
if (start == end)
return -1;
if (matchoff && matchlen) {
@@ -1064,6 +1143,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff = sdpoff;
for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
char *end;
if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
&mediaoff, &medialen) <= 0)
@@ -1079,8 +1160,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff += t->len;
medialen -= t->len;
port = simple_strtoul(*dptr + mediaoff, NULL, 10);
if (port == 0)
port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end);
if (port == 0 || *dptr + mediaoff == end)
continue;
if (port < 1024 || port > 65535) {
nf_ct_helper_log(skb, ct, "wrong port %u", port);
@@ -1254,7 +1335,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
*/
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
expires = simple_strtoul(*dptr + matchoff, NULL, 10);
expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
SIP_HDR_CONTACT, NULL,
@@ -1358,7 +1439,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
expires = simple_strtoul(*dptr + matchoff, NULL, 10);
expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
while (1) {
unsigned int c_expires = expires;
@@ -1418,10 +1499,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen, matchend;
unsigned int code, cseq, i;
char *end;
if (*datalen < strlen("SIP/2.0 200"))
return NF_ACCEPT;
code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
code = sip_strtouint(*dptr + strlen("SIP/2.0 "),
*datalen - strlen("SIP/2.0 "), NULL);
if (!code) {
nf_ct_helper_log(skb, ct, "cannot get code");
return NF_DROP;
@@ -1432,8 +1515,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
if (!cseq && *(*dptr + matchoff) != '0') {
cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1482,6 +1565,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
const struct sip_handler *handler;
char *end;
handler = &sip_handlers[i];
if (handler->request == NULL)
@@ -1498,8 +1582,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
if (!cseq && *(*dptr + matchoff) != '0') {
cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1575,7 +1659,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
&matchoff, &matchlen) <= 0)
break;
clen = simple_strtoul(dptr + matchoff, (char **)&end, 10);
clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end);
if (dptr + matchoff == end)
break;
+1
View File
@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
"rport=", &poff, &plen,
&n) > 0 &&
n >= 1024 && n <= 65535 &&
htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
+225 -89
View File
@@ -374,6 +374,38 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook)
call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu);
}
static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook)
{
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
}
static void nft_trans_hook_destroy(struct nft_trans_hook *trans_hook)
{
list_del(&trans_hook->list);
kfree(trans_hook);
}
static void nft_netdev_unregister_trans_hook(struct net *net,
const struct nft_table *table,
struct list_head *hook_list)
{
struct nft_trans_hook *trans_hook, *next;
struct nf_hook_ops *ops;
struct nft_hook *hook;
list_for_each_entry_safe(trans_hook, next, hook_list, list) {
hook = trans_hook->hook;
if (!(table->flags & NFT_TABLE_F_DORMANT)) {
list_for_each_entry(ops, &hook->ops_list, list)
nf_unregister_net_hook(net, ops);
}
nft_netdev_hook_unlink_free_rcu(hook);
nft_trans_hook_destroy(trans_hook);
}
}
static void nft_netdev_unregister_hooks(struct net *net,
struct list_head *hook_list,
bool release_netdev)
@@ -384,10 +416,8 @@ static void nft_netdev_unregister_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nf_unregister_net_hook(net, ops);
if (release_netdev) {
list_del(&hook->list);
nft_netdev_hook_free_rcu(hook);
}
if (release_netdev)
nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -1942,15 +1972,69 @@ static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook)
return nla_put_string(skb, attr, hook->ifname);
}
struct nft_hook_dump_ctx {
struct nft_hook *first;
int n;
};
static int nft_dump_basechain_hook_one(struct sk_buff *skb,
struct nft_hook *hook,
struct nft_hook_dump_ctx *dump_ctx)
{
if (!dump_ctx->first)
dump_ctx->first = hook;
if (nft_nla_put_hook_dev(skb, hook))
return -1;
dump_ctx->n++;
return 0;
}
static int nft_dump_basechain_hook_list(struct sk_buff *skb,
const struct net *net,
const struct list_head *hook_list,
struct nft_hook_dump_ctx *dump_ctx)
{
struct nft_hook *hook;
int err;
list_for_each_entry_rcu(hook, hook_list, list,
lockdep_commit_lock_is_held(net)) {
err = nft_dump_basechain_hook_one(skb, hook, dump_ctx);
if (err < 0)
return err;
}
return 0;
}
static int nft_dump_basechain_trans_hook_list(struct sk_buff *skb,
const struct list_head *trans_hook_list,
struct nft_hook_dump_ctx *dump_ctx)
{
struct nft_trans_hook *trans_hook;
int err;
list_for_each_entry(trans_hook, trans_hook_list, list) {
err = nft_dump_basechain_hook_one(skb, trans_hook->hook, dump_ctx);
if (err < 0)
return err;
}
return 0;
}
static int nft_dump_basechain_hook(struct sk_buff *skb,
const struct net *net, int family,
const struct nft_base_chain *basechain,
const struct list_head *hook_list)
const struct list_head *hook_list,
const struct list_head *trans_hook_list)
{
const struct nf_hook_ops *ops = &basechain->ops;
struct nft_hook *hook, *first = NULL;
struct nft_hook_dump_ctx dump_hook_ctx = {};
struct nlattr *nest, *nest_devs;
int n = 0;
nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK);
if (nest == NULL)
@@ -1965,23 +2049,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb,
if (!nest_devs)
goto nla_put_failure;
if (!hook_list)
if (!hook_list && !trans_hook_list)
hook_list = &basechain->hook_list;
list_for_each_entry_rcu(hook, hook_list, list,
lockdep_commit_lock_is_held(net)) {
if (!first)
first = hook;
if (nft_nla_put_hook_dev(skb, hook))
goto nla_put_failure;
n++;
if (hook_list &&
nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) {
goto nla_put_failure;
} else if (trans_hook_list &&
nft_dump_basechain_trans_hook_list(skb, trans_hook_list,
&dump_hook_ctx)) {
goto nla_put_failure;
}
nla_nest_end(skb, nest_devs);
if (n == 1 &&
!hook_is_prefix(first) &&
nla_put_string(skb, NFTA_HOOK_DEV, first->ifname))
if (dump_hook_ctx.n == 1 &&
!hook_is_prefix(dump_hook_ctx.first) &&
nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname))
goto nla_put_failure;
}
nla_nest_end(skb, nest);
@@ -1995,7 +2079,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event, u32 flags,
int family, const struct nft_table *table,
const struct nft_chain *chain,
const struct list_head *hook_list)
const struct list_head *hook_list,
const struct list_head *trans_hook_list)
{
struct nlmsghdr *nlh;
@@ -2011,7 +2096,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
NFTA_CHAIN_PAD))
goto nla_put_failure;
if (!hook_list &&
if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELCHAIN ||
event == NFT_MSG_DESTROYCHAIN)) {
nlmsg_end(skb, nlh);
@@ -2022,7 +2107,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
const struct nft_base_chain *basechain = nft_base_chain(chain);
struct nft_stats __percpu *stats;
if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list))
if (nft_dump_basechain_hook(skb, net, family, basechain,
hook_list, trans_hook_list))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
@@ -2058,7 +2144,8 @@ nla_put_failure:
}
static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
const struct list_head *hook_list)
const struct list_head *hook_list,
const struct list_head *trans_hook_list)
{
struct nftables_pernet *nft_net;
struct sk_buff *skb;
@@ -2078,7 +2165,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq,
event, flags, ctx->family, ctx->table,
ctx->chain, hook_list);
ctx->chain, hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -2124,7 +2211,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
NFT_MSG_NEWCHAIN,
NLM_F_MULTI,
table->family, table,
chain, NULL) < 0)
chain, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -2178,7 +2265,7 @@ static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info,
err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN,
0, family, table, chain, NULL);
0, family, table, chain, NULL, NULL);
if (err < 0)
goto err_fill_chain_info;
@@ -2271,10 +2358,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) {
list_for_each_entry_safe(hook, next,
&basechain->hook_list, list) {
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
}
&basechain->hook_list, list)
nft_netdev_hook_unlink_free_rcu(hook);
}
module_put(basechain->type->owner);
if (rcu_access_pointer(basechain->stats)) {
@@ -2343,8 +2428,12 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
list_for_each_entry(hook, hook_list, list) {
if (!strncmp(hook->ifname, this->ifname,
min(hook->ifnamelen, this->ifnamelen)))
min(hook->ifnamelen, this->ifnamelen))) {
if (hook->flags & NFT_HOOK_REMOVE)
continue;
return hook;
}
}
return NULL;
@@ -2974,6 +3063,7 @@ err_hooks:
list_for_each_entry(ops, &h->ops_list, list)
nf_unregister_net_hook(ctx->net, ops);
}
/* hook.list is on stack, no need for list_del_rcu() */
list_del(&h->list);
nft_netdev_hook_free_rcu(h);
}
@@ -3102,6 +3192,32 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
return nf_tables_addchain(&ctx, family, policy, flags, extack);
}
static int nft_trans_delhook(struct nft_hook *hook,
struct list_head *del_list)
{
struct nft_trans_hook *trans_hook;
trans_hook = kmalloc_obj(*trans_hook, GFP_KERNEL);
if (!trans_hook)
return -ENOMEM;
trans_hook->hook = hook;
list_add_tail(&trans_hook->list, del_list);
hook->flags |= NFT_HOOK_REMOVE;
return 0;
}
static void nft_trans_delhook_abort(struct list_head *del_list)
{
struct nft_trans_hook *trans_hook, *next;
list_for_each_entry_safe(trans_hook, next, del_list, list) {
trans_hook->hook->flags &= ~NFT_HOOK_REMOVE;
nft_trans_hook_destroy(trans_hook);
}
}
static int nft_delchain_hook(struct nft_ctx *ctx,
struct nft_base_chain *basechain,
struct netlink_ext_ack *extack)
@@ -3128,7 +3244,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_chain_del_hook;
}
list_move(&hook->list, &chain_del_list);
if (nft_trans_delhook(hook, &chain_del_list) < 0) {
err = -ENOMEM;
goto err_chain_del_hook;
}
}
trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN);
@@ -3148,7 +3267,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
return 0;
err_chain_del_hook:
list_splice(&chain_del_list, &basechain->hook_list);
nft_trans_delhook_abort(&chain_del_list);
nft_chain_release_hook(&chain_hook);
return err;
@@ -8852,10 +8971,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nft_unregister_flowtable_ops(net, flowtable, ops);
if (release_netdev) {
list_del(&hook->list);
nft_netdev_hook_free_rcu(hook);
}
if (release_netdev)
nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -8926,8 +9043,7 @@ err_unregister_net_hooks:
nft_unregister_flowtable_ops(net, flowtable, ops);
}
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -8937,9 +9053,25 @@ static void nft_hooks_destroy(struct list_head *hook_list)
{
struct nft_hook *hook, *next;
list_for_each_entry_safe(hook, next, hook_list, list) {
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
list_for_each_entry_safe(hook, next, hook_list, list)
nft_netdev_hook_unlink_free_rcu(hook);
}
static void nft_flowtable_unregister_trans_hook(struct net *net,
struct nft_flowtable *flowtable,
struct list_head *hook_list)
{
struct nft_trans_hook *trans_hook, *next;
struct nf_hook_ops *ops;
struct nft_hook *hook;
list_for_each_entry_safe(trans_hook, next, hook_list, list) {
hook = trans_hook->hook;
list_for_each_entry(ops, &hook->ops_list, list)
nft_unregister_flowtable_ops(net, flowtable, ops);
nft_netdev_hook_unlink_free_rcu(hook);
nft_trans_hook_destroy(trans_hook);
}
}
@@ -9028,8 +9160,7 @@ err_flowtable_update_hook:
nft_unregister_flowtable_ops(ctx->net,
flowtable, ops);
}
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -9202,7 +9333,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_flowtable_del_hook;
}
list_move(&hook->list, &flowtable_del_list);
if (nft_trans_delhook(hook, &flowtable_del_list) < 0) {
err = -ENOMEM;
goto err_flowtable_del_hook;
}
}
trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE,
@@ -9223,7 +9357,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
return 0;
err_flowtable_del_hook:
list_splice(&flowtable_del_list, &flowtable->hook_list);
nft_trans_delhook_abort(&flowtable_del_list);
nft_flowtable_hook_release(&flowtable_hook);
return err;
@@ -9288,8 +9422,10 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event,
u32 flags, int family,
struct nft_flowtable *flowtable,
struct list_head *hook_list)
struct list_head *hook_list,
struct list_head *trans_hook_list)
{
struct nft_trans_hook *trans_hook;
struct nlattr *nest, *nest_devs;
struct nft_hook *hook;
struct nlmsghdr *nlh;
@@ -9306,7 +9442,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
NFTA_FLOWTABLE_PAD))
goto nla_put_failure;
if (!hook_list &&
if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELFLOWTABLE ||
event == NFT_MSG_DESTROYFLOWTABLE)) {
nlmsg_end(skb, nlh);
@@ -9328,13 +9464,20 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
if (!nest_devs)
goto nla_put_failure;
if (!hook_list)
if (!hook_list && !trans_hook_list)
hook_list = &flowtable->hook_list;
list_for_each_entry_rcu(hook, hook_list, list,
lockdep_commit_lock_is_held(net)) {
if (nft_nla_put_hook_dev(skb, hook))
goto nla_put_failure;
if (hook_list) {
list_for_each_entry_rcu(hook, hook_list, list,
lockdep_commit_lock_is_held(net)) {
if (nft_nla_put_hook_dev(skb, hook))
goto nla_put_failure;
}
} else if (trans_hook_list) {
list_for_each_entry(trans_hook, trans_hook_list, list) {
if (nft_nla_put_hook_dev(skb, trans_hook->hook))
goto nla_put_failure;
}
}
nla_nest_end(skb, nest_devs);
nla_nest_end(skb, nest);
@@ -9388,7 +9531,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
NFT_MSG_NEWFLOWTABLE,
NLM_F_MULTI | NLM_F_APPEND,
table->family,
flowtable, NULL) < 0)
flowtable, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -9488,7 +9631,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq,
NFT_MSG_NEWFLOWTABLE, 0, family,
flowtable, NULL);
flowtable, NULL, NULL);
if (err < 0)
goto err_fill_flowtable_info;
@@ -9501,7 +9644,9 @@ err_fill_flowtable_info:
static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
struct nft_flowtable *flowtable,
struct list_head *hook_list, int event)
struct list_head *hook_list,
struct list_head *trans_hook_list,
int event)
{
struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
@@ -9521,7 +9666,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid,
ctx->seq, event, flags,
ctx->family, flowtable, hook_list);
ctx->family, flowtable,
hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -9535,13 +9681,8 @@ err:
static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
{
struct nft_hook *hook, *next;
flowtable->data.type->free(&flowtable->data);
list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
list_del_rcu(&hook->list);
nft_netdev_hook_free_rcu(hook);
}
nft_hooks_destroy(&flowtable->hook_list);
kfree(flowtable->name);
module_put(flowtable->data.type->owner);
kfree(flowtable);
@@ -10060,9 +10201,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans))
nft_hooks_destroy(&nft_trans_chain_hooks(trans));
else
if (!nft_trans_chain_update(trans))
nf_tables_chain_destroy(nft_trans_chain(trans));
break;
case NFT_MSG_DELRULE:
@@ -10083,9 +10222,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
if (nft_trans_flowtable_update(trans))
nft_hooks_destroy(&nft_trans_flowtable_hooks(trans));
else
if (!nft_trans_flowtable_update(trans))
nf_tables_flowtable_destroy(nft_trans_flowtable(trans));
break;
}
@@ -10845,31 +10982,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_chain_update(trans)) {
nft_chain_commit_update(nft_trans_container_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN,
&nft_trans_chain_hooks(trans));
list_splice(&nft_trans_chain_hooks(trans),
&nft_trans_basechain(trans)->hook_list);
&nft_trans_chain_hooks(trans), NULL);
list_splice_rcu(&nft_trans_chain_hooks(trans),
&nft_trans_basechain(trans)->hook_list);
/* trans destroyed after rcu grace period */
} else {
nft_chain_commit_drop_policy(nft_trans_container_chain(trans));
nft_clear(net, nft_trans_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL);
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL, NULL);
nft_trans_destroy(trans);
}
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, NULL,
&nft_trans_chain_hooks(trans));
if (!(table->flags & NFT_TABLE_F_DORMANT)) {
nft_netdev_unregister_hooks(net,
&nft_trans_chain_hooks(trans),
true);
}
nft_netdev_unregister_trans_hook(net, table,
&nft_trans_chain_hooks(trans));
} else {
nft_chain_del(nft_trans_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
NULL);
NULL, NULL);
nf_tables_unregister_hook(ctx.net, ctx.table,
nft_trans_chain(trans));
}
@@ -10975,14 +11109,16 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
NULL,
NFT_MSG_NEWFLOWTABLE);
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
list_splice_rcu(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(net, nft_trans_flowtable(trans));
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
NULL,
NFT_MSG_NEWFLOWTABLE);
}
nft_trans_destroy(trans);
@@ -10992,16 +11128,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_flowtable_update(trans)) {
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
&nft_trans_flowtable_hooks(trans),
trans->msg_type);
nft_unregister_flowtable_net_hooks(net,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans));
nft_flowtable_unregister_trans_hook(net,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
NULL,
trans->msg_type);
nft_unregister_flowtable_net_hooks(net,
nft_trans_flowtable(trans),
@@ -11165,8 +11303,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
list_splice(&nft_trans_chain_hooks(trans),
&nft_trans_basechain(trans)->hook_list);
nft_trans_delhook_abort(&nft_trans_chain_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_chain(trans));
@@ -11280,8 +11417,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
if (nft_trans_flowtable_update(trans)) {
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_flowtable(trans));
+2 -1
View File
@@ -196,7 +196,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
if (err < 0)
return err;
if (priv->data.data[0] >= BITS_PER_TYPE(u32)) {
if (!priv->data.data[0] ||
priv->data.data[0] >= BITS_PER_TYPE(u32)) {
nft_data_release(&priv->data, desc.type);
return -EINVAL;
}
+1 -1
View File
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
return 0;
for (i = sp->len - 1; i >= 0; i--) {
pos = strict ? i - sp->len + 1 : 0;
pos = strict ? sp->len - i - 1 : 0;
if (pos >= info->len)
return 0;
e = &info->pol[pos];
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff. Show more