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:
commit
e9d885afda
151 files changed
+2038
-992
No files matched your search
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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))
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct notifier_block;
|
||||
|
||||
struct acpi_handle_list {
|
||||
u32 count;
|
||||
acpi_handle *handles;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
Reference in new issue
Block a user