Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH bpf v3 2/2] selftests/bpf: Test FIONREAD on a sockmap socket without a verdict program
From: John Fastabend @ 2026-07-14 19:25 UTC (permalink / raw)
  To: mattia.meleleo
  Cc: bpf, netdev, Jakub Sitnicki, Jiayuan Chen,
	Kumar Kartikeya Dwivedi, Emil Tsalapatis
In-Reply-To: <20260708-fionread-no-verdict-v3-2-b4ee31b3af53@coralogix.com>

On Wed, Jul 08, 2026 at 06:55:01PM +0200, Mattia Meleleo via B4 Relay wrote:
>From: Mattia Meleleo <mattia.meleleo@coralogix.com>
>
>Add a test validating that FIONREAD on a TCP socket in a sockmap
>without a verdict program reports data pending in sk_receive_queue.
>
>Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
>Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
>Signed-off-by: Mattia Meleleo <mattia.meleleo@coralogix.com>
>---

LGTM we could improve IO_TIMEOUT_SEC across all the tests if we wanted
per bot suggestion.

Reviewed-by: John Fastabend <john.fastabend@gmail.com>

^ permalink raw reply

* Re: [PATCH 1/2] PCI: Replace pci_dev->is_busmaster with accessors
From: Maurice Hieronymus @ 2026-07-14 19:34 UTC (permalink / raw)
  To: Lukas Wunner, Maurice Hieronymus
  Cc: Edward Cree, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Bjorn Helgaas, Justin Tee, Paul Ely,
	James E.J. Bottomley, Martin K. Petersen, Juergen Gross,
	Stefano Stabellini, Oleksandr Tyshchenko, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	Tamir Duberstein, Alexandre Courbot, Onur Özkan,
	Borislav Petkov, Tony Luck, Danilo Krummrich, rust-for-linux,
	netdev, linux-net-drivers, linux-kernel, linux-pci, linux-scsi,
	xen-devel, linux-edac
In-Reply-To: <alOkgrK7Fm6opB4r@wunner.de>

On Sun Jul 12, 2026 at 4:28 PM CEST, Lukas Wunner wrote:

> We already have the priv_flags member in struct pci_dev,
> please use that instead of adding another one for the same purpose.
>
v2 moves the bit into priv_flags and exposes accessor functions
for those drivers which needs to access the flags.

Best,

Maurice

^ permalink raw reply

* Re: [PATCH 2/2] PCI: Replace pci_dev->broken_parity_status with accessors
From: Maurice Hieronymus @ 2026-07-14 19:36 UTC (permalink / raw)
  To: Lukas Wunner, Maurice Hieronymus
  Cc: Edward Cree, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Bjorn Helgaas, Justin Tee, Paul Ely,
	James E.J. Bottomley, Martin K. Petersen, Juergen Gross,
	Stefano Stabellini, Oleksandr Tyshchenko, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	Tamir Duberstein, Alexandre Courbot, Onur Özkan,
	Borislav Petkov, Tony Luck, Danilo Krummrich, rust-for-linux,
	netdev, linux-net-drivers, linux-kernel, linux-pci, linux-scsi,
	xen-devel, linux-edac
In-Reply-To: <alOq4rsjATipBjY9@wunner.de>

On Sun Jul 12, 2026 at 4:55 PM CEST, Lukas Wunner wrote:
>
> For static bits in struct pci_dev, i.e. ones that are mostly read
> and almost never written, and in particular ones that are only
> written on device enumeration, it's perfectly fine and more convenient
> to keep them as bitfields.  broken_parity_status seems to fit that bill.
>
Its only writer is broken_parity_status_store(), so it is written from
sysfs at arbitrary times rather than on enumeration. But I agree the
exposure is small; apart from the sysfs attribute itself, EDAC is the
only reader.

> For other bits which are modified more frequently, move them to the existing
> priv_flags member if you believe they can be updated concurrently.
> I'm not sure is_busmaster fits that bill, it isn't updated that often.
>
The motivation is not update frequency. The planned Rust device
enabling rework [1] wants a guard object whose drop calls
pci_disable_device(), which may then run concurrently with
pci_set_master(). Moving is_busmaster out of the bitfield stops those
paths from writing to the word shared with the other bits.

> Quite honestly I'm wondering if there is anything to fix here.
> Yes I get it, userspace may interfere with adjacent bits.
> But broken_parity_status is only used for certain broken devices
> on EDAC-capable platforms.  That's a fringe use case.
> Is it really worth refactoring this?
>
I dropped this patch in v2 and moved only is_busmaster, into
priv_flags as you suggested.

> Perhaps we can deprecate the sysfs attribute in favor of using quirks
> for broken devices?
>
That sounds like the better long term fix to me, but I would leave it
to a separate discussion.

[1] https://lore.kernel.org/rust-for-linux/DJOEYVBS17MJ.1YD3TNGQBWHNK@kernel.org/

Best,

Maurice

^ permalink raw reply

* [PATCH v2] PCI: Move pci_dev->is_busmaster into priv_flags
From: Maurice Hieronymus @ 2026-07-14 19:37 UTC (permalink / raw)
  To: Edward Cree, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Bjorn Helgaas, Justin Tee, Paul Ely,
	James E.J. Bottomley, Martin K. Petersen, Juergen Gross,
	Stefano Stabellini, Oleksandr Tyshchenko, Miguel Ojeda,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
	Tamir Duberstein, Alexandre Courbot, Onur Özkan,
	Borislav Petkov, Tony Luck
  Cc: Danilo Krummrich, rust-for-linux, netdev, linux-net-drivers,
	linux-kernel, linux-pci, linux-scsi, xen-devel, linux-edac,
	Lukas Wunner, Maurice Hieronymus

`is_busmaster` is one bit of a ~60-bit C bitfield in `struct pci_dev`.
Bits sharing a bitfield word must not be modified concurrently, but its
writers take no common lock: `pci_set_master()` can run without the
device lock (e.g. from runtime PM resume paths), `pci_disable_device()`
clears the bit, and other bits in the same word are written from
entirely different contexts, e.g. `broken_parity_status` from sysfs.
Concurrent read-modify-write cycles of the shared word can then lose
updates.

Move `is_busmaster` into the existing `priv_flags` bitmap, which is
modified with atomic bitops. The bit definition stays private to
drivers/pci; xen-pciback, lpfc and sfc access the flag through the new
exported accessors `pci_dev_is_busmaster()` and
`pci_dev_assign_busmaster()`.

This also unblocks the Rust device enabling API rework [1], where a
guard object calls `pci_disable_device()` from contexts that may run
concurrently with `pci_set_master()`.

Link: https://lore.kernel.org/rust-for-linux/DJOEYVBS17MJ.1YD3TNGQBWHNK@kernel.org/ [1]
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Suggested-by: Lukas Wunner <lukas@wunner.de>
Cc: rust-for-linux@vger.kernel.org
Signed-off-by: Maurice Hieronymus <mhi@mailbox.org>
---
`struct pci_dev` keeps ~60 flags in one C bitfield. Bits sharing a
word must not be modified concurrently, but several writers take no
common lock: `pci_set_master()` writes `is_busmaster` and can run
without the device lock (e.g. runtime PM resume paths),
`pci_disable_device()` clears it, and `broken_parity_status_store()`
writes the same word from sysfs at any time without any lock.

Move `is_busmaster` into the existing `priv_flags` bitmap, which is
modified with atomic bitops. The bit definition stays private to
drivers/pci; the drivers that use the flag (xen-pciback, lpfc, sfc)
access it through new exported accessor functions.

This is a prerequisite for the Rust device enabling API rework [1]:
the guard object planned there calls `pci_disable_device()` from
contexts that may run concurrently with `pci_set_master()`.
---
Changes in v2:
- Move the bit into the existing priv_flags bitmap instead of adding a
  new public flags bitmap (Lukas). The bit definition stays private to
  drivers/pci; outside users go through new exported accessors.
- Drop the broken_parity_status conversion (Lukas).
- Link to v1: https://lore.kernel.org/r/20260711-pci-dev-flags-v1-0-2fcf2811138c@mailbox.org
---
 drivers/net/ethernet/sfc/falcon/farch.c     |  2 +-
 drivers/net/ethernet/sfc/siena/farch.c      |  2 +-
 drivers/pci/pci-driver.c                    |  2 +-
 drivers/pci/pci.c                           | 33 ++++++++++++++++++++++++++---
 drivers/pci/pci.h                           |  1 +
 drivers/scsi/lpfc/lpfc_init.c               |  4 ++--
 drivers/xen/xen-pciback/conf_space_header.c |  4 ++--
 drivers/xen/xen-pciback/pciback_ops.c       |  4 ++--
 include/linux/pci.h                         |  3 ++-
 9 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c
index 23d507a3820d..c73db6081190 100644
--- a/drivers/net/ethernet/sfc/falcon/farch.c
+++ b/drivers/net/ethernet/sfc/falcon/farch.c
@@ -724,7 +724,7 @@ int ef4_farch_fini_dmaq(struct ef4_nic *efx)
 	/* Do not attempt to write to the NIC during EEH recovery */
 	if (efx->state != STATE_RECOVERY) {
 		/* Only perform flush if DMA is enabled */
-		if (efx->pci_dev->is_busmaster) {
+		if (pci_dev_is_busmaster(efx->pci_dev)) {
 			efx->type->prepare_flush(efx);
 			rc = ef4_farch_do_flush(efx);
 			efx->type->finish_flush(efx);
diff --git a/drivers/net/ethernet/sfc/siena/farch.c b/drivers/net/ethernet/sfc/siena/farch.c
index 7613d7988894..815487b1b227 100644
--- a/drivers/net/ethernet/sfc/siena/farch.c
+++ b/drivers/net/ethernet/sfc/siena/farch.c
@@ -723,7 +723,7 @@ int efx_farch_fini_dmaq(struct efx_nic *efx)
 	/* Do not attempt to write to the NIC during EEH recovery */
 	if (efx->state != STATE_RECOVERY) {
 		/* Only perform flush if DMA is enabled */
-		if (efx->pci_dev->is_busmaster) {
+		if (pci_dev_is_busmaster(efx->pci_dev)) {
 			efx->type->prepare_flush(efx);
 			rc = efx_farch_do_flush(efx);
 			efx->type->finish_flush(efx);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index f36778e62ac1..f3b2255258df 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -649,7 +649,7 @@ static int pci_pm_reenable_device(struct pci_dev *pci_dev)
 	 * if the device was busmaster before the suspend, make it busmaster
 	 * again
 	 */
-	if (pci_dev->is_busmaster)
+	if (pci_dev_is_busmaster(pci_dev))
 		pci_set_master(pci_dev);
 
 	return retval;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 77b17b13ee61..80c962811737 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2045,7 +2045,7 @@ static void pci_enable_bridge(struct pci_dev *dev)
 		pci_enable_bridge(bridge);
 
 	if (pci_is_enabled(dev)) {
-		if (!dev->is_busmaster)
+		if (!pci_dev_is_busmaster(dev))
 			pci_set_master(dev);
 		return;
 	}
@@ -2205,7 +2205,7 @@ void pci_disable_device(struct pci_dev *dev)
 
 	do_pci_disable_device(dev);
 
-	dev->is_busmaster = 0;
+	pci_dev_assign_busmaster(dev, false);
 }
 EXPORT_SYMBOL(pci_disable_device);
 
@@ -4106,6 +4106,33 @@ void pci_unmap_iospace(struct resource *res)
 }
 EXPORT_SYMBOL(pci_unmap_iospace);
 
+/**
+ * pci_dev_is_busmaster - Query the bus mastering bookkeeping flag
+ * @pdev: the PCI device to query
+ *
+ * Returns: the current value of the bookkeeping flag; the PCI_COMMAND
+ * register is not consulted.
+ */
+bool pci_dev_is_busmaster(const struct pci_dev *pdev)
+{
+	return test_bit(PCI_DEV_BUSMASTER, &pdev->priv_flags);
+}
+EXPORT_SYMBOL(pci_dev_is_busmaster);
+
+/**
+ * pci_dev_assign_busmaster - Set the bus mastering bookkeeping flag
+ * @pdev: the PCI device
+ * @busmaster: new flag value
+ *
+ * Only updates the bookkeeping flag; the PCI_COMMAND register is left
+ * untouched.
+ */
+void pci_dev_assign_busmaster(struct pci_dev *pdev, bool busmaster)
+{
+	assign_bit(PCI_DEV_BUSMASTER, &pdev->priv_flags, busmaster);
+}
+EXPORT_SYMBOL(pci_dev_assign_busmaster);
+
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
 	u16 old_cmd, cmd;
@@ -4120,7 +4147,7 @@ static void __pci_set_master(struct pci_dev *dev, bool enable)
 			enable ? "enabling" : "disabling");
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
-	dev->is_busmaster = enable;
+	pci_dev_assign_busmaster(dev, enable);
 }
 
 /**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4469e1a77f3c..faa4a676e62c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -773,6 +773,7 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 #define PCI_LINK_CHANGING 5
 #define PCI_LINK_LBMS_SEEN	6
 #define PCI_DEV_ALLOW_BINDING 7
+#define PCI_DEV_BUSMASTER 8
 
 static inline void pci_dev_assign_added(struct pci_dev *dev)
 {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 82af59c913e9..657453e6d7d2 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -14398,7 +14398,7 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
 
 	pci_restore_state(pdev);
 
-	if (pdev->is_busmaster)
+	if (pci_dev_is_busmaster(pdev))
 		pci_set_master(pdev);
 
 	spin_lock_irq(&phba->hbalock);
@@ -15251,7 +15251,7 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
 	 */
 	pci_save_state(pdev);
 
-	if (pdev->is_busmaster)
+	if (pci_dev_is_busmaster(pdev))
 		pci_set_master(pdev);
 
 	spin_lock_irq(&phba->hbalock);
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c
index 8b50cbcbdfe1..ecc9adba369c 100644
--- a/drivers/xen/xen-pciback/conf_space_header.c
+++ b/drivers/xen/xen-pciback/conf_space_header.c
@@ -81,10 +81,10 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
 			dev_data->enable_intx = 0;
 	}
 
-	if (!dev->is_busmaster && is_master_cmd(value)) {
+	if (!pci_dev_is_busmaster(dev) && is_master_cmd(value)) {
 		dev_dbg(&dev->dev, "set bus master\n");
 		pci_set_master(dev);
-	} else if (dev->is_busmaster && !is_master_cmd(value)) {
+	} else if (pci_dev_is_busmaster(dev) && !is_master_cmd(value)) {
 		dev_dbg(&dev->dev, "clear bus master\n");
 		pci_clear_master(dev);
 	}
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
index bfc186bf05bc..01f4705421c9 100644
--- a/drivers/xen/xen-pciback/pciback_ops.c
+++ b/drivers/xen/xen-pciback/pciback_ops.c
@@ -125,14 +125,14 @@ void xen_pcibk_reset_device(struct pci_dev *dev)
 		if (pci_is_enabled(dev))
 			pci_disable_device(dev);
 
-		dev->is_busmaster = 0;
+		pci_dev_assign_busmaster(dev, false);
 	} else {
 		pci_read_config_word(dev, PCI_COMMAND, &cmd);
 		if (cmd & (PCI_COMMAND_INVALIDATE)) {
 			cmd &= ~(PCI_COMMAND_INVALIDATE);
 			pci_write_config_word(dev, PCI_COMMAND, cmd);
 
-			dev->is_busmaster = 0;
+			pci_dev_assign_busmaster(dev, false);
 		}
 	}
 }
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 64b308b6e61c..0542221ad996 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -461,7 +461,6 @@ struct pci_dev {
 	unsigned int	pref_64_window:1;	/* Pref mem window is 64-bit */
 	unsigned int	multifunction:1;	/* Multi-function device */
 
-	unsigned int	is_busmaster:1;		/* Is busmaster */
 	unsigned int	no_msi:1;		/* May not use MSI */
 	unsigned int	block_cfg_access:1;	/* Config space access blocked */
 	unsigned int	broken_parity_status:1;	/* Generates false positive parity */
@@ -1446,6 +1445,8 @@ void pci_disable_device(struct pci_dev *dev);
 extern unsigned int pcibios_max_latency;
 void pci_set_master(struct pci_dev *dev);
 void pci_clear_master(struct pci_dev *dev);
+bool pci_dev_is_busmaster(const struct pci_dev *pdev);
+void pci_dev_assign_busmaster(struct pci_dev *pdev, bool busmaster);
 
 int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
 int pci_set_cacheline_size(struct pci_dev *dev);

---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20260711-pci-dev-flags-fbbcf4ff9031

Best regards,
-- 
Maurice Hieronymus <mhi@mailbox.org>


^ permalink raw reply related

* Re: Ethtool is missing C2C link modes
From: Andrew Lunn @ 2026-07-14 19:43 UTC (permalink / raw)
  To: D H, Siddaraju
  Cc: Maxime Chevallier, David Laight, Michal Kubecek,
	netdev@vger.kernel.org, Chintalapalle, Balaji, Das, Shubham,
	Srinivasan, Vijay, Samudrala, Sridhar, Keller, Jacob E,
	Nguyen, Anthony L, singhai.anjali55@gmail.com, Brandeburg, Jesse
In-Reply-To: <SN7PR11MB6900984B5FBD60B71B3B8F329AF92@SN7PR11MB6900.namprd11.prod.outlook.com>

> Siddaraju: baseR is an end-to-end physical layer type that clearly defines
> 	the	interface & components stating from MAC RS(Reconciliation Sublayer)
> 	till the PMD + MDI signallings. AUI is an intermediate electrical interface
> 	layer(simplified KR) that connects 2 PMAs (PMA <=== AUI ===> PMA).
> 	AUI is a split function design approach where subfunction implementation
> 	from multiple vendors come together to exploit their domain expertise
> 	to produce a best Ethernet interconnect.

> Andrew: I _think_ ethtool reports the media, not some intermediary format.
> 	Is ETHTOOL_LINK_MODE_25000baseC2C_Full_BIT actually needed? 
> Siddaraju: We are here to find out that Andrew :).
> 	If we are following the strict convention that ethtool link modes
> 	report & represents the end-to-end flow "ONLY", then yes, AUI doesn't
> 	fit there. We are exploring phy_interface_t for intermediate interfaces
> 	and we hope we don't hit any roadblocks. Let's see.

Given these two answer, phy_interface_t is a better fit. I'm however
not sure it is fully correct. Historically, it was used to indicate
the interface between the MAC and base-T PHYs. PCS and PMD either did
not exist, or was an invisible layer, back in those days. At that
point phy_interface_t was the bottom of the reconciliation layer?

The introduction of SGMII and 1000BaseX made PCS a thing, even if
initially it was generally hidden away. PHY_INTERFACE_MODE_SGMII then
corresponds to the bottom of the PCS, with the Base-T PHY also talking
SGMII. phy_interface_t then moves from the reconciliation layer to a
lower layer?

So what exactly does phy_interface_t mean?

And historically, we have only had a single phy_interface_t value. Are
there use cases for needing different C2C values are different layers?
Could you have a single lane 100G C2C split into 4 lanes of 25G C2C?

Another thing we should consider. Most NICs above 10G currently don't
have Linux controlling the hardware. These lower layers are all hidden
away in firmware. For you hardware, is Linux actually controlling any
of this?  Are you adding support to phylink for these intermediary
building blocks? Should Linux currently care about C2C?

	Andrew

^ permalink raw reply

* Re: RFC: symmetric SET_MODULE_EEPROM_BY_PAGE with i2c_address for non-SFF pages
From: Andrew Lunn @ 2026-07-14 19:55 UTC (permalink / raw)
  To: Ayoub Kaanich; +Cc: Russell King, netdev@vger.kernel.org
In-Reply-To: <AS4PR08MB80212ED810625BB46A8EE1B7B7FA2@AS4PR08MB8021.eurprd08.prod.outlook.com>

> There is no equivalent SET. ethtool --set-module-eeprom (both
> netlink and the legacy ioctl fallback)

In general, we are trying to block user space drivers, by only
allowing read.

> Concrete use case:
> 
> We (Technica Engineering) manufacture automotive SFP/SFP+ modules for 100/1000BASE-T1 and multi-gig automotive Ethernet (TE-1441, PT-1445). Alongside the standard SFF-8472 EEPROM at 0x50, these modules expose an I2C-to-MDIO gateway at I2C address 0x40 (0x80/0x81 as 8-bit read/write):
> 
> Writes to that address are relayed by the module's own logic as MDIO Clause 22/45 transactions to the embedded automotive PHY, giving access to link speed, master/slave mode, and other PHY configuration without needing register-level documentation of the PHY itself.

What protocol does it use? Have you seen drivers/net/mdio/mdio-i2c.c.
That currently implements two different C22 or C45 over I2C.

You should add your protocol here, and then Linux can just drive the
PHY, like it does for any other PHY.

	Andrew

^ permalink raw reply

* Re: [PATCH net-next 13/15] net/mlx5e: psp: Make PSP steering config dynamic
From: Cosmin Ratiu @ 2026-07-14 20:05 UTC (permalink / raw)
  To: Tariq Toukan, horms@kernel.org
  Cc: Rahul Rameshbabu, Boris Pismenny, willemdebruijn.kernel@gmail.com,
	andrew+netdev@lunn.ch, daniel.zahka@gmail.com, Jianbo Liu,
	davem@davemloft.net, leon@kernel.org,
	linux-kernel@vger.kernel.org, pabeni@redhat.com,
	edumazet@google.com, linux-rdma@vger.kernel.org, Raed Salem,
	Chris Mi, Dragos Tatulea, sdf.kernel@gmail.com, kuba@kernel.org,
	Mark Bloch, sdf@fomichev.me, Saeed Mahameed,
	netdev@vger.kernel.org, aleksandr.loktionov@intel.com,
	Gal Pressman, Lama Kayal, jacob.e.keller@intel.com
In-Reply-To: <20260714173021.1862773-1-horms@kernel.org>

On Tue, 2026-07-14 at 18:30 +0100, Simon Horman wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [13]: [PATCH net-next 13/15] net/mlx5e: psp: Make PSP
> steering config dynamic ---
> commit 133d9a32cbf9c1b939ae4ca8473c41624c313951
> Author: Cosmin Ratiu <cratiu@nvidia.com>
> 
> net/mlx5e: psp: Make PSP steering config dynamic
> 
> This commit changes PSP steering tables to only be created when PSP
> configuration is enabled on a device, instead of at device
> initialization
> time. This avoids imposing steering overhead on all UDP packets when
> PSP
> is not being used.
> 
> > diff --git
> > a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
> > b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
> > index b526b3898c22e..3f212e46fc2f9 100644
> > --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
> > +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
> > @@ -220,18 +220,7 @@ static inline void
> > mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,
> >  
> >  static inline int mlx5e_accel_init_rx(struct mlx5e_priv *priv)
> >  {
> > -	int err;
> > -
> > -	err = mlx5_accel_psp_fs_init_rx_tables(priv);
> > -	if (err)
> > -		goto out;
> > -
> > -	err = mlx5e_ktls_init_rx(priv);
> > -	if (err)
> > -		mlx5_accel_psp_fs_cleanup_rx_tables(priv);
> > -
> > -out:
> > -	return err;
> > +	return mlx5e_ktls_init_rx(priv);
> >  }
> >  
> >  static inline void mlx5e_accel_cleanup_rx(struct mlx5e_priv *priv)
> > @@ -242,12 +231,6 @@ static inline void
> > mlx5e_accel_cleanup_rx(struct mlx5e_priv *priv)
> >  
> >  static inline int mlx5e_accel_init_tx(struct mlx5e_priv *priv)
> >  {
> > -	int err;
> > -
> > -	err = mlx5_accel_psp_fs_init_tx_tables(priv);
> > -	if (err)
> > -		return err;
> > -
> >  	return mlx5e_ktls_init_tx(priv);
> >  }
> 
> [Severity: Critical]
> Does removing the unconditional table creation here prevent PSP
> tables
> from being restored on device attach or resume?
> 
> Since mlx5_accel_psp_fs_cleanup_tx_tables() is still called during
> device
> detach or suspend, the PSP steering tables are destroyed. However,
> because
> mlx5e_accel_init_tx() no longer recreates them, the tables appear to
> remain
> missing after a suspend/resume or detach/attach cycle.
> 
> Because software psp_assoc structures remain bound to active sockets,
> could
> this leave the device in a state where the hardware TX steering table
> (which
> contains the CRYPTO_ENCRYPT action) is missing?
> 
> If so, would this cause egress traffic to bypass encryption and be
> transmitted in plaintext?

When the device is suspended, 1. all TX keys are released and 2.
steering rules are removed. 3. psp state is completely freed, including
the configuration intention.

When the device is resumed, psp is reinitialized to a blank state.

Before these changes, psp was also reset to a blank state (no keys, but
with steering rules readded). This also broke existing PSP connections.

I guess fixing this behavior during suspend is outside the scope of
this series. I don't like it, we should do something about it, but not
in this series.

Cosmin.

^ permalink raw reply

* Re: [PATCH net-next 15/15] net/mlx5e: psp: Report PSP dev registration errors
From: Cosmin Ratiu @ 2026-07-14 20:08 UTC (permalink / raw)
  To: Tariq Toukan, horms@kernel.org
  Cc: Rahul Rameshbabu, Boris Pismenny, willemdebruijn.kernel@gmail.com,
	andrew+netdev@lunn.ch, daniel.zahka@gmail.com, Jianbo Liu,
	davem@davemloft.net, leon@kernel.org,
	linux-kernel@vger.kernel.org, pabeni@redhat.com,
	edumazet@google.com, linux-rdma@vger.kernel.org, Raed Salem,
	Chris Mi, Dragos Tatulea, sdf.kernel@gmail.com, kuba@kernel.org,
	Mark Bloch, sdf@fomichev.me, Saeed Mahameed,
	netdev@vger.kernel.org, aleksandr.loktionov@intel.com,
	Gal Pressman, Lama Kayal, jacob.e.keller@intel.com
In-Reply-To: <20260714173151.1863310-2-horms@kernel.org>

On Tue, 2026-07-14 at 18:31 +0100, Simon Horman wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev
> ---
> --- Patch [15]: [PATCH net-next 15/15] net/mlx5e: psp: Report PSP dev
> registration errors ---
> commit 76afe7de4d1e708e7c01d267ef1fb9cf946de937
> Author: Cosmin Ratiu <cratiu@nvidia.com>
> 
> net/mlx5e: psp: Report PSP dev registration errors
> 
> This commit updates mlx5e_psp_register() to return an error code
> instead
> of void when psp_dev_create() fails. The caller, mlx5e_nic_enable(),
> is
> also updated to check this return value and abort if PSP registration
> fails.
> 
> > diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> > b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> > --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> > +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> > @@ -6199,7 +6199,9 @@ static int mlx5e_nic_enable(struct mlx5e_priv
> > *priv)
> >  
> >  	mlx5e_fs_init_l2_addr(priv->fs, netdev);
> >  	mlx5e_ipsec_init(priv);
> > -	mlx5e_psp_register(priv);
> > +	err = mlx5e_psp_register(priv);
> > +	if (err)
> > +		goto out_ipsec_cleanup;
> 
> [Severity: High]
> Could propagating this error cause the entire network interface to
> fail if
> the optional PSP offload fails to register?
> 
> If psp_dev_create() fails (e.g., due to memory pressure or ID
> exhaustion
> in xa_alloc_cyclic), mlx5e_nic_enable() will now abort, resulting in
> a
> complete loss of networking capability for the device.
> 
> Notice how the code immediately following this handles MACsec
> initialization
> failures by logging the error and allowing the NIC to continue
> operating:
> 
> 	err = mlx5e_macsec_init(priv);
> 	if (err)
> 		mlx5_core_err(mdev, "MACsec initialization failed,
> %d\n", err);
> 
> Should PSP registration failure fall back gracefully and allow the
> core NIC
> to function without the offload, similar to how MACsec is handled?
> 
> >  
> >  	err = mlx5e_macsec_init(priv);
> >  	if (err)
> >  		mlx5_core_err(mdev, "MACsec initialization failed,
> > %d\n", err);

This is an intentional change, as discussed in this thread with Jakub:

https://lore.kernel.org/netdev/20260417050201.192070-1-tariqt@nvidia.com/t/#u

We carefully chose to fail device init on the very unlikely event PSP
dev creation fails.

Cosmin.

^ permalink raw reply

* [PATCH net-next] net: macb: add support for 1000BASE-X autonegotiation to PCS
From: Nathan Whitehorn @ 2026-07-14 20:09 UTC (permalink / raw)
  To: netdev; +Cc: Nathan Whitehorn

The current PCS code unconditionally uses SGMII autonegotiation, though
the hardware supports both SGMII and 1000BASE-X modes. Decouple the
choice of PCS enablement from use of the SGMII mode when running at
gigabit rates and announce to phylink that 1000BASE-X is a supported
operating mode. This enables direct attachment of the PCS to e.g. an
SFP.

Tested and developed on Microchip Polarfire SoC hardware.

Signed-off-by: Nathan Whitehorn <nwhitehorn@pa.msu.edu>
---
 drivers/net/ethernet/cadence/macb_main.c | 31 ++++++++++++++++++------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index d394f1f43b68..284a3b03f8c7 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -583,7 +583,13 @@ static void macb_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
 
 static void macb_pcs_an_restart(struct phylink_pcs *pcs)
 {
-	/* Not supported */
+	struct macb *bp = container_of(pcs, struct macb, phylink_sgmii_pcs);
+	u32 old, new;
+
+	old = gem_readl(bp, PCSCNTRL);
+	new = old | BMCR_ANRESTART;
+	if (old != new)
+		gem_writel(bp, PCSCNTRL, new);
 }
 
 static int macb_pcs_config(struct phylink_pcs *pcs,
@@ -750,7 +756,9 @@ static void macb_mac_config(struct phylink_config *config, unsigned int mode,
 		ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));
 		ncr &= ~GEM_BIT(ENABLE_HS_MAC);
 
-		if (state->interface == PHY_INTERFACE_MODE_SGMII) {
+		if (state->interface == PHY_INTERFACE_MODE_1000BASEX) {
+			ctrl |= GEM_BIT(PCSSEL);
+		} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
 			ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
 		} else if (state->interface == PHY_INTERFACE_MODE_10GBASER) {
 			ctrl |= GEM_BIT(PCSSEL);
@@ -957,7 +965,8 @@ static struct phylink_pcs *macb_mac_select_pcs(struct phylink_config *config,
 
 	if (interface == PHY_INTERFACE_MODE_10GBASER)
 		return &bp->phylink_usx_pcs;
-	else if (interface == PHY_INTERFACE_MODE_SGMII)
+	else if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+	         interface == PHY_INTERFACE_MODE_SGMII)
 		return &bp->phylink_sgmii_pcs;
 	else
 		return NULL;
@@ -1025,13 +1034,15 @@ static int macb_mii_probe(struct net_device *dev)
 	struct macb *bp = netdev_priv(dev);
 
 	bp->phylink_sgmii_pcs.ops = &macb_phylink_pcs_ops;
+	bp->phylink_sgmii_pcs.poll = true;
 	bp->phylink_usx_pcs.ops = &macb_phylink_usx_pcs_ops;
 
 	bp->phylink_config.dev = &dev->dev;
 	bp->phylink_config.type = PHYLINK_NETDEV;
 	bp->phylink_config.mac_managed_pm = true;
 
-	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+	if (bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX ||
+	    bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
 		bp->phylink_config.poll_fixed_state = true;
 		bp->phylink_config.get_fixed_state = macb_get_pcs_fixed_state;
 		/* The PCSAUTONEG bit in PCSCNTRL is on out of reset. Setting
@@ -1060,9 +1071,12 @@ static int macb_mii_probe(struct net_device *dev)
 			  bp->phylink_config.supported_interfaces);
 		phy_interface_set_rgmii(bp->phylink_config.supported_interfaces);
 
-		if (bp->caps & MACB_CAPS_PCS)
+		if (bp->caps & MACB_CAPS_PCS) {
+			__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+				  bp->phylink_config.supported_interfaces);
 			__set_bit(PHY_INTERFACE_MODE_SGMII,
 				  bp->phylink_config.supported_interfaces);
+		}
 
 		if (bp->caps & MACB_CAPS_HIGH_SPEED) {
 			__set_bit(PHY_INTERFACE_MODE_10GBASER,
@@ -4931,7 +4945,9 @@ static int macb_init_dflt(struct platform_device *pdev)
 	/* Set MII management clock divider */
 	val = macb_mdc_clk_div(bp);
 	val |= macb_dbw(bp);
-	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
+	if (bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX)
+		val |= GEM_BIT(PCSSEL);
+	else if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
 		val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
 	macb_writel(bp, NCFGR, val);
 
@@ -5456,7 +5472,8 @@ static int init_reset_optional(struct platform_device *pdev)
 	struct macb *bp = netdev_priv(dev);
 	int ret;
 
-	if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+	if (bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX ||
+	    bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
 		/* Ensure PHY device used in SGMII mode is ready */
 		bp->phy = devm_phy_optional_get(&pdev->dev, NULL);
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH net] pds_core: yield the CPU while waiting for the adminq to drain
From: Nikhil P. Rao @ 2026-07-14 20:14 UTC (permalink / raw)
  To: netdev
  Cc: kuba, brett.creeley, eric.joyner, andrew+netdev, davem, edumazet,
	pabeni, Nikhil P. Rao

pdsc_adminq_wait_and_dec_once_unused() busy-waits for adminq_refcnt to
drop to one:

	while (!refcount_dec_if_one(&pdsc->adminq_refcnt))
		cpu_relax();

The refcount is held by pdsc_adminq_post() for the duration of an
in-flight command, which can wait up to devcmd_timeout seconds
(PDS_CORE_DEVCMD_TIMEOUT is 5) for the hardware to complete. cpu_relax()
is not a reschedule point, so on a non-preemptible kernel this loop can
spin on the CPU for several seconds, starving other tasks on that core.

Add cond_resched() to the loop so the waiter yields to other runnable
tasks while it polls, keeping cpu_relax() as the busy-wait hint between
checks.

Fixes: 7e82a8745b95 ("pds_core: Prevent race issues involving the adminq")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
Reviewed-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/net/ethernet/amd/pds_core/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
index 38a2446571af..19eeb5b06f4d 100644
--- a/drivers/net/ethernet/amd/pds_core/core.c
+++ b/drivers/net/ethernet/amd/pds_core/core.c
@@ -533,6 +533,7 @@ static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)
 		dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n",
 				    __func__);
 		cpu_relax();
+		cond_resched();
 	}
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/2] bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
From: Nnamdi Onyeyiri @ 2026-07-14 20:39 UTC (permalink / raw)
  To: jiayuan.chen
  Cc: nnamdio, john.fastabend, jakub, edumazet, ncardwell, kuniyu,
	davem, kuba, pabeni, horms, netdev, bpf, sashiko-reviews
In-Reply-To: <5b07d2ab-84ee-46ae-84c9-7542499d26d7@linux.dev>

Spurious wakeups in tcp_msg_wait_data() isn't being handled by
tcp_bpf_recvmsg() and tcp_bpf_recvmsg_parser(), leading to unexpected
EAGAIN errors returned by recvfrom()/recv().  Adding handling for the
wakeup and a selftest.

Changes in v2:
- In tcp_bpf_recvmsg, handle signals and the socket closing in the loop.
- Fix spurious wakeups when SO_RCVTIMEO has been set on the socket.
- Link to v1: https://patch.msgid.link/ak_rR-Skd8Mvn4mH@localhost.localdomain

Changes in v3:
- Added the sockmap_recvfrom selftest.
- Link to v2: https://patch.msgid.link/alFRK66z45eDNZA7@localhost.localdomain

Signed-off-by: Nnamdi Onyeyiri <nnamdio@gmail.com>
---
Nnamdi Onyeyiri (2):
  bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
  bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup

 net/ipv4/tcp_bpf.c                            |  55 +++-
 tools/testing/selftests/net/.gitignore        |   2 +
 tools/testing/selftests/net/Makefile          |   6 +
 .../selftests/net/sockmap_recvfrom.bpf.c      |  31 ++
 .../testing/selftests/net/sockmap_recvfrom.c  | 288 ++++++++++++++++++
 5 files changed, 373 insertions(+), 9 deletions(-)
 create mode 100644 tools/testing/selftests/net/sockmap_recvfrom.bpf.c
 create mode 100644 tools/testing/selftests/net/sockmap_recvfrom.c

-- 
2.52.0


^ permalink raw reply

* [PATCH v3 1/2] bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
From: Nnamdi Onyeyiri @ 2026-07-14 20:39 UTC (permalink / raw)
  To: jiayuan.chen
  Cc: nnamdio, john.fastabend, jakub, edumazet, ncardwell, kuniyu,
	davem, kuba, pabeni, horms, netdev, bpf, sashiko-reviews
In-Reply-To: <20260714203927.32289-1-nnamdio@gmail.com>

recvfrom()/recv() are documented as only returning EAGAIN for blocking sockets
when they have a receive timeout configured.  However, adding a blocking
ipv4 tcp socket without a receive timeout to a sockmap will cause EAGAIN errors
sporadically.  A socket with a receive timeout may return EAGAIN before the
timeout expires.

There are 2 code paths affected by this:

  1. tcp_bpf_recvmsg() - Used when the socket has been added to a sockmap
     that has no verdict program attached.

  2. tcp_bpf_recvmsg_parser() - Used when the socket has been added to a
     sockmap that has a verdict program.  To reproduce this issue, it is
     enough for the verdict program to do nothing but return SK_PASS.

In both cases this happens when tcp_msg_wait_data() wakes spuriously
(returning 0).  To fix it, we now loop back to msg_bytes_ready instead
of returning -EAGAIN on spurious wakeup.

To ensure the looping does not cause sockets with a SO_RCVTIMEO set to
wait excessively long, tcp_msg_wait_data() now takes a pointer to timeo,
allowing sk_wait_event() to update it as appropriate.

The logic in tcp_bpf_recvmsg_parser() that allow it to handle signals,
socket errors and closuers in its loop was also added to tcp_bpf_recvmsg().

Signed-off-by: Nnamdi Onyeyiri <nnamdio@gmail.com>
---
 net/ipv4/tcp_bpf.c | 55 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index cc0bd73f36b6..e58ab2d1ee94 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -179,7 +179,7 @@ EXPORT_SYMBOL_GPL(tcp_bpf_sendmsg_redir);
 
 #ifdef CONFIG_BPF_SYSCALL
 static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
-			     long timeo)
+			     long *timeo)
 {
 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
 	int ret = 0;
@@ -187,12 +187,12 @@ static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
 	if (sk->sk_shutdown & RCV_SHUTDOWN)
 		return 1;
 
-	if (!timeo)
+	if (!*timeo)
 		return ret;
 
 	add_wait_queue(sk_sleep(sk), &wait);
 	sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
-	ret = sk_wait_event(sk, &timeo,
+	ret = sk_wait_event(sk, timeo,
 			    !list_empty(&psock->ingress_msg) ||
 			    !skb_queue_empty_lockless(&sk->sk_receive_queue), &wait);
 	sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
@@ -229,6 +229,7 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
 	int copied_from_self = 0;
 	int copied = 0;
 	u32 seq;
+	long timeo;
 
 	if (unlikely(flags & MSG_ERRQUEUE))
 		return inet_recv_error(sk, msg, len);
@@ -262,6 +263,8 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
 		}
 	}
 
+	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
 msg_bytes_ready:
 	copied = __sk_msg_recvmsg(sk, psock, msg, len, flags, &copied_from_self);
 	/* The typical case for EFAULT is the socket was gracefully
@@ -280,7 +283,6 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
 	}
 	seq += copied_from_self;
 	if (!copied) {
-		long timeo;
 		int data;
 
 		if (sock_flag(sk, SOCK_DONE))
@@ -299,7 +301,6 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
 			goto out;
 		}
 
-		timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
 		if (!timeo) {
 			copied = -EAGAIN;
 			goto out;
@@ -310,13 +311,15 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
 			goto out;
 		}
 
-		data = tcp_msg_wait_data(sk, psock, timeo);
+		data = tcp_msg_wait_data(sk, psock, &timeo);
 		if (data < 0) {
 			copied = data;
 			goto unlock;
 		}
 		if (data && !sk_psock_queue_empty(psock))
 			goto msg_bytes_ready;
+		if (!data && timeo > 0)
+			goto msg_bytes_ready;
 		copied = -EAGAIN;
 	}
 out:
@@ -355,6 +358,7 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
 {
 	struct sk_psock *psock;
 	int copied, ret;
+	long timeo;
 
 	if (unlikely(flags & MSG_ERRQUEUE))
 		return inet_recv_error(sk, msg, len);
@@ -371,14 +375,45 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
 		return tcp_recvmsg(sk, msg, len, flags);
 	}
 	lock_sock(sk);
+
+	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
 msg_bytes_ready:
 	copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
 	if (!copied) {
-		long timeo;
 		int data;
 
-		timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-		data = tcp_msg_wait_data(sk, psock, timeo);
+		if (sock_flag(sk, SOCK_DONE)) {
+			ret = 0;
+			goto unlock;
+		}
+
+		if (sk->sk_err) {
+			ret = sock_error(sk);
+			goto unlock;
+		}
+
+		if (sk->sk_shutdown & RCV_SHUTDOWN) {
+			ret = 0;
+			goto unlock;
+		}
+
+		if (sk->sk_state == TCP_CLOSE) {
+			ret = -ENOTCONN;
+			goto unlock;
+		}
+
+		if (!timeo) {
+			ret = -EAGAIN;
+			goto unlock;
+		}
+
+		if (signal_pending(current)) {
+			ret = sock_intr_errno(timeo);
+			goto unlock;
+		}
+
+		data = tcp_msg_wait_data(sk, psock, &timeo);
 		if (data < 0) {
 			ret = data;
 			goto unlock;
@@ -390,6 +425,8 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
 			sk_psock_put(sk, psock);
 			return tcp_recvmsg(sk, msg, len, flags);
 		}
+		if (!data && timeo > 0)
+			goto msg_bytes_ready;
 		copied = -EAGAIN;
 	}
 	ret = copied;
-- 
2.52.0


^ permalink raw reply related

* [PATCH v3 2/2] bpf, sockmap: handle spurious tcp_msg_wait_data() wakeup
From: Nnamdi Onyeyiri @ 2026-07-14 20:39 UTC (permalink / raw)
  To: jiayuan.chen
  Cc: nnamdio, john.fastabend, jakub, edumazet, ncardwell, kuniyu,
	davem, kuba, pabeni, horms, netdev, bpf, sashiko-reviews
In-Reply-To: <20260714203927.32289-1-nnamdio@gmail.com>

This selftest exercises the tcp_bpf_recvmsg() and tcp_bpf_recvmsg_parser()
functions, to ensure that they are properly handling spurious wakeups in
tcp_msg_wait_data().

The expected behaviour is that:

  * Without a timeout - recvfrom() does not return an EAGAIN error.

  * With a timeout - recvfrom() returns EAGAIN, but only after the
    SO_RCVTIMEO timeout has expired.

If the spurious wakeups are not correctly handled, the above assertions
fail.

Signed-off-by: Nnamdi Onyeyiri <nnamdio@gmail.com>
---
 tools/testing/selftests/net/.gitignore        |   2 +
 tools/testing/selftests/net/Makefile          |   6 +
 .../selftests/net/sockmap_recvfrom.bpf.c      |  31 ++
 .../testing/selftests/net/sockmap_recvfrom.c  | 288 ++++++++++++++++++
 4 files changed, 327 insertions(+)
 create mode 100644 tools/testing/selftests/net/sockmap_recvfrom.bpf.c
 create mode 100644 tools/testing/selftests/net/sockmap_recvfrom.c

diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index c9f46031ac73..a1840a5d45f6 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -39,6 +39,8 @@ sk_connect_zero_addr
 sk_so_peek_off
 skf_net_off
 socket
+sockmap_recvfrom
+sockmap_recvfrom.bpf.o
 so_incoming_cpu
 so_netns_cookie
 so_rcv_listener
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 708d960ae07d..a05a4a924402 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -161,6 +161,7 @@ TEST_GEN_FILES := \
 	so_netns_cookie \
 	so_rcv_listener \
 	socket \
+	sockmap_recvfrom.bpf.o \
 	stress_reuseport_listen \
 	tcp_fastopen_backup_key \
 	tcp_inq \
@@ -191,6 +192,7 @@ TEST_GEN_PROGS := \
 	sk_connect_zero_addr \
 	sk_so_peek_off \
 	so_incoming_cpu \
+	sockmap_recvfrom \
 	tap \
 	tcp_port_share \
 	tls \
@@ -238,3 +240,7 @@ $(OUTPUT)/bind_bhash: LDLIBS += -lpthread
 $(OUTPUT)/io_uring_zerocopy_tx: CFLAGS += -I../../../include/
 
 include bpf.mk
+
+$(OUTPUT)/sockmap_recvfrom: $(BPFOBJ)
+$(OUTPUT)/sockmap_recvfrom: LDLIBS += $(BPFOBJ) -lelf -lz -lpthread
+$(OUTPUT)/sockmap_recvfrom: CFLAGS += -I$(OUTPUT)/tools/include
diff --git a/tools/testing/selftests/net/sockmap_recvfrom.bpf.c b/tools/testing/selftests/net/sockmap_recvfrom.bpf.c
new file mode 100644
index 000000000000..fec470c738f1
--- /dev/null
+++ b/tools/testing/selftests/net/sockmap_recvfrom.bpf.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+#define AF_INET 2
+
+char LICENSE[] SEC("license") = "GPL";
+
+struct {
+	__uint(type, BPF_MAP_TYPE_SOCKHASH);
+	__uint(max_entries, 1024);
+	__type(key, __u64);
+	__type(value, __u64);
+
+} map_socks SEC(".maps");
+
+SEC("sockops") int on_sockops(struct bpf_sock_ops *ctx)
+{
+	if (ctx->family == AF_INET && ctx->op == BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) {
+		__u64 cookie = bpf_get_socket_cookie(ctx);
+
+		bpf_sock_hash_update(ctx, &map_socks, &cookie, BPF_NOEXIST);
+	}
+
+	return 0;
+}
+
+SEC("sk_skb/stream_verdict") int on_recv(struct __sk_buff *ctx)
+{
+	return SK_PASS;
+}
diff --git a/tools/testing/selftests/net/sockmap_recvfrom.c b/tools/testing/selftests/net/sockmap_recvfrom.c
new file mode 100644
index 000000000000..f96b4673c977
--- /dev/null
+++ b/tools/testing/selftests/net/sockmap_recvfrom.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <arpa/inet.h>
+#include <bpf/libbpf.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdatomic.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "kselftest_harness.h"
+
+#define MAX_ITERATIONS 100
+#define PAYLOAD_END 'e'
+
+static int start_listening(struct __test_metadata *_metadata, uint16_t *port)
+{
+	struct sockaddr_in addr;
+	socklen_t addrlen;
+	int fd;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+
+	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+	ASSERT_NE(fd, -1);
+	ASSERT_EQ(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), 0);
+	ASSERT_EQ(listen(fd, 5), 0);
+
+	addrlen = sizeof(addr);
+
+	ASSERT_EQ(getsockname(fd, (struct sockaddr *)&addr, &addrlen), 0);
+
+	*port = addr.sin_port;
+
+	return fd;
+}
+
+static void process_client(struct __test_metadata *_metadata, int fd, atomic_int *running)
+{
+	char buf[1024];
+	struct timeval timeo;
+
+	timeo.tv_sec = 0;
+	timeo.tv_usec = 1000;
+
+	EXPECT_EQ(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)), 0);
+
+	while (atomic_load(running)) {
+		ssize_t len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
+
+		if (len == -1) {
+			EXPECT_TRUE(errno == EAGAIN || errno == EINTR);
+			continue;
+		}
+
+		EXPECT_GE(len, 0);
+
+		if (len <= 0 || buf[len - 1] == PAYLOAD_END)
+			break;
+	}
+
+	write(fd, "test", 4);
+
+	close(fd);
+}
+
+struct bpf_t {
+	struct bpf_object *obj;
+	struct bpf_link *on_sockops;
+	struct bpf_link *on_recv;
+};
+
+static void setup_bpf(struct __test_metadata *_metadata, const char *path, bool recv,
+						struct bpf_t *bpf)
+{
+	struct bpf_program *prog;
+	int cgroup;
+
+	memset(bpf, 0, sizeof(*bpf));
+	bpf->obj = bpf_object__open_file(path, NULL);
+
+	ASSERT_NE(bpf->obj, NULL);
+	ASSERT_EQ(bpf_object__load(bpf->obj), 0);
+
+	prog = bpf_object__find_program_by_name(bpf->obj, "on_sockops");
+	ASSERT_NE(prog, NULL);
+
+	cgroup = open("/sys/fs/cgroup", O_RDONLY);
+	ASSERT_NE(cgroup, -1);
+
+	bpf->on_sockops = bpf_program__attach_cgroup(prog, cgroup);
+	close(cgroup);
+
+	ASSERT_NE(bpf->on_sockops, NULL);
+
+	if (recv) {
+		struct bpf_map *map = bpf_object__find_map_by_name(bpf->obj, "map_socks");
+
+		ASSERT_NE(map, NULL);
+
+		prog = bpf_object__find_program_by_name(bpf->obj, "on_recv");
+		ASSERT_NE(prog, NULL);
+
+		bpf->on_recv = bpf_program__attach_sockmap(prog, bpf_map__fd(map));
+		ASSERT_NE(bpf->on_recv, NULL);
+	}
+}
+
+struct server_t {
+	int fd;
+	atomic_int running;
+	pthread_t thread;
+	struct __test_metadata *metadata;
+};
+
+static void *run_server(void *arg)
+{
+	struct server_t *server = arg;
+	struct __test_metadata *_metadata = server->metadata;
+
+	while (atomic_load(&server->running)) {
+		int client_fd = accept(server->fd, NULL, NULL);
+
+		if (client_fd == -1) {
+			if (!atomic_load(&server->running))
+				break;
+
+			continue;
+		}
+
+		process_client(_metadata, client_fd, &server->running);
+	}
+
+	return NULL;
+}
+
+static int send_payload(struct __test_metadata *_metadata, int fd, const char *buf, size_t len)
+{
+	size_t remaining = len;
+
+	do {
+		ssize_t bytes = write(fd, buf + (len - remaining), remaining);
+
+		if (bytes < 0) {
+			if (errno == EINTR)
+				continue;
+
+			return -1;
+		}
+
+		remaining -= bytes;
+	} while (remaining);
+
+	return 0;
+}
+
+FIXTURE(sockmap_recvfrom)
+{
+	struct server_t server;
+	struct sockaddr_in addr;
+	struct bpf_t bpf;
+	char *payload;
+	size_t payload_len;
+};
+
+FIXTURE_VARIANT(sockmap_recvfrom)
+{
+	bool with_recv;
+};
+
+FIXTURE_VARIANT_ADD(sockmap_recvfrom, recvmsg)
+{
+	.with_recv = false
+};
+
+FIXTURE_VARIANT_ADD(sockmap_recvfrom, recvmsg_parser)
+{
+	.with_recv = true
+};
+
+FIXTURE_SETUP(sockmap_recvfrom)
+{
+	memset(&self->addr, 0, sizeof(self->addr));
+
+	self->payload_len = 1024 * 1024 * 25;
+	self->payload = malloc(self->payload_len);
+	ASSERT_NE(self->payload, NULL);
+
+	memset(self->payload, 0, self->payload_len);
+	self->payload[self->payload_len - 1] = PAYLOAD_END;
+
+	setup_bpf(_metadata, "sockmap_recvfrom.bpf.o", variant->with_recv, &self->bpf);
+	atomic_store(&self->server.running, 1);
+	self->server.fd = start_listening(_metadata, &self->addr.sin_port);
+	self->server.metadata = _metadata;
+
+	self->addr.sin_family = AF_INET;
+	self->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	pthread_create(&self->server.thread, NULL, &run_server, &self->server);
+}
+
+FIXTURE_TEARDOWN(sockmap_recvfrom)
+{
+	atomic_store(&self->server.running, 0);
+
+	if (self->server.fd) {
+		shutdown(self->server.fd, SHUT_RD);
+		close(self->server.fd);
+	}
+
+	if (self->server.thread)
+		pthread_join(self->server.thread, NULL);
+
+	free(self->payload);
+	bpf_link__destroy(self->bpf.on_sockops);
+
+	if (self->bpf.on_recv)
+		bpf_link__destroy(self->bpf.on_recv);
+
+	bpf_object__close(self->bpf.obj);
+}
+
+TEST_F(sockmap_recvfrom, no_timeout)
+{
+	char ignored[128];
+
+	for (int i = 0; i < MAX_ITERATIONS; ++i) {
+		int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+		ASSERT_NE(fd, -1);
+		ASSERT_EQ(connect(fd, (struct sockaddr *)&self->addr, sizeof(self->addr)), 0);
+
+		ASSERT_EQ(send_payload(_metadata, fd, self->payload, self->payload_len), 0);
+
+		if (recvfrom(fd, ignored, sizeof(ignored), 0, NULL, NULL) < 0)
+			ASSERT_NE(errno, EAGAIN);
+
+		close(fd);
+	}
+}
+
+static int64_t to_nanos(struct timespec *time)
+{
+	return (time->tv_sec * 1000000000LL) + time->tv_nsec;
+}
+
+TEST_F(sockmap_recvfrom, with_timeout)
+{
+	char ignored[128];
+	struct timeval timeo;
+
+	timeo.tv_sec = 0;
+	timeo.tv_usec = 5000;
+
+	/* remove the payload end delimiter so the server never responds and recvfrom times out. */
+	self->payload[self->payload_len - 1] = 0;
+
+	for (int i = 0; i < MAX_ITERATIONS; ++i) {
+		struct timespec beg;
+		struct timespec end;
+		int err;
+
+		int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+		ASSERT_NE(fd, -1);
+		ASSERT_EQ(connect(fd, (struct sockaddr *)&self->addr, sizeof(self->addr)), 0);
+
+		ASSERT_EQ(send_payload(_metadata, fd, self->payload, self->payload_len), 0);
+
+		ASSERT_EQ(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)), 0);
+
+		clock_gettime(CLOCK_MONOTONIC, &beg);
+		ASSERT_EQ(recvfrom(fd, ignored, sizeof(ignored), 0, NULL, NULL), -1);
+		err = errno;
+		clock_gettime(CLOCK_MONOTONIC, &end);
+
+		ASSERT_EQ(err, EAGAIN);
+		ASSERT_GE(to_nanos(&end) - to_nanos(&beg), timeo.tv_usec * 1000);
+
+		close(fd);
+	}
+}
+
+TEST_HARNESS_MAIN
-- 
2.52.0


^ permalink raw reply related

* [PATCH net] pds_core: order completion reads after the ownership check
From: Nikhil P. Rao @ 2026-07-14 20:41 UTC (permalink / raw)
  To: netdev
  Cc: kuba, brett.creeley, eric.joyner, andrew+netdev, davem, edumazet,
	pabeni, Nikhil P. Rao

pdsc_process_adminq() and pdsc_process_notifyq() decide a completion is
valid from its ownership field - the color bit for the adminq, the event
id for the notifyq - then read the rest of the descriptor, with no
barrier in between.

On a weakly ordered architecture the CPU may read the payload first. Add
dma_rmb() between the ownership read and the payload reads.

Fixes: 7e82a8745b95 ("pds_core: Prevent race issues involving the adminq")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
Reviewed-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/net/ethernet/amd/pds_core/adminq.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c
index 097bb092bdb8..eadb4b604fbe 100644
--- a/drivers/net/ethernet/amd/pds_core/adminq.c
+++ b/drivers/net/ethernet/amd/pds_core/adminq.c
@@ -18,7 +18,13 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq)
 	comp = cq_info->comp;
 	eid = le64_to_cpu(comp->event.eid);
 	while (eid > pdsc->last_eid) {
-		u16 ecode = le16_to_cpu(comp->event.ecode);
+		u16 ecode;
+
+		/* Order the payload read after the event id, the field the
+		 * driver uses to detect a new completion.
+		 */
+		dma_rmb();
+		ecode = le16_to_cpu(comp->event.ecode);
 
 		switch (ecode) {
 		case PDS_EVENT_LINK_CHANGE:
@@ -101,6 +107,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)
 	spin_lock_irqsave(&pdsc->adminq_lock, irqflags);
 	comp = cq->info[cq->tail_idx].comp;
 	while (pdsc_color_match(comp->color, cq->done_color)) {
+		/* Order the payload reads after the color bit, the field the
+		 * driver uses to detect a new completion.
+		 */
+		dma_rmb();
 		q_info = &q->info[q->tail_idx];
 		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net] net: hsr: fix memory leak on slave unregistration by removing synced VLANs
From: Fernando Fernandez Mancera @ 2026-07-14 20:45 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Andrew Lunn, netdev, eric.dumazet, syzbot+456957213f32970c0762
In-Reply-To: <20260707082327.3238690-1-edumazet@google.com>

> When an HSR master device is brought UP, it auto-adds VLAN 0 via
> vlan_vid0_add(), which propagates VID 0 to its slave devices.
> 
> If a slave device is later unregistered while HSR is active (e.g., during
> netns cleanup or interface destruction), hsr_del_port() is called to
> detach the slave port from the HSR master. However, hsr_del_port() currently
> does not delete the VLAN IDs that were synced to the slave device by HSR.
> 
> As a result, the slave device retains a refcount on VID 0 (and any other
> synced VLANs). When the slave device is destroyed, its vlan_info /
> vlan_vid_info structure remains allocated, leading to a memory leak.
> 
> Fix this by calling vlan_vids_del_by_dev(port->dev, master->dev) in
> hsr_del_port() before unlinking the slave device, matching the cleanup
> behavior in bonding and team drivers.
> 
> Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
> Reported-by: syzbot+456957213f32970c0762@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/netdev/6a4cb6ca.57639fcc.86d58.000b.GAE@google.com/T/#u
> Signed-off-by: Eric Dumazet <edumazet@google.com>
>

Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>

Thanks!

^ permalink raw reply

* Re: [PATCH net v2] nfc: llcp: reject PDUs shorter than the LLCP header
From: David Laight @ 2026-07-14 20:53 UTC (permalink / raw)
  To: Doruk Tan Ozturk
  Cc: david, vadim.fedorenko, horms, oe-linux-nfc, netdev, linux-kernel,
	stable
In-Reply-To: <20260714164629.75051-1-doruk@0sec.ai>

On Tue, 14 Jul 2026 18:46:29 +0200
Doruk Tan Ozturk <doruk@0sec.ai> wrote:

> > Is there a similar problem with non-linear skb?
> > Maybe they can't get into this code, but who knows what can happen
> > with unusual configs.  
> 
> Good question. Today every skb that reaches __nfc_llcp_recv() is
> linear: the target path (nci_rx_data_packet -> nci_add_rx_data_frag ->
> nfc_tm_data_received) and the initiator path (nfc_data_exchange ->
> nfc_llcp_recv) both build the frame with alloc_skb()/nci_skb_alloc()
> plus skb_put()/skb_put_data(), and NCI reassembly uses skb_cow_head()
> and skb_push() into the linear area. Nothing on the NFC receive side
> attaches page frags or a frag_list, so skb->len == skb_headlen() and the
> v2 skb->len test was in fact sufficient for the in-tree drivers.
> 
> But relying on that is fragile: the parser reads the header out of the
> linear area (pdu->data[0]/data[1]) while skb->len is the total length,
> so a non-linear skb with a short linear head would slip past a skb->len
> test and still over-read the linear buffer. pskb_may_pull() is the
> right guard here -- it also covers the non-linear case, and it matches
> how the sibling NCI and HCI receive paths already validate their
> headers.
> 
> I will send a v3 that uses:
> 
> 	if (!pskb_may_pull(skb, LLCP_HEADER_SIZE)) {
> 		kfree_skb(skb);
> 		return;
> 	}
> 
> That is strictly stronger than the v2 check and does not reject any
> valid frame -- pskb_may_pull() pulls the two header bytes into the
> linear area when needed.

Does that help any code further down the rx path?
It might be better to drop non-linear packets with a comment that
they aren't expected to happen.

	David


> 
> Thanks,
> Doruk


^ permalink raw reply

* Re: [PATCH net v3] nfc: llcp: reject PDUs shorter than the LLCP header
From: Vadim Fedorenko @ 2026-07-14 20:57 UTC (permalink / raw)
  To: Doruk Tan Ozturk, david
  Cc: horms, david.laight.linux, oe-linux-nfc, netdev, linux-kernel,
	stable
In-Reply-To: <20260714164631.75068-1-doruk@0sec.ai>

On 14.07.2026 17:46, Doruk Tan Ozturk wrote:
> Every LLCP PDU begins with a two-byte header (DSAP/SSAP + PTYPE), but the
> receive path never checked that a frame is at least LLCP_HEADER_SIZE bytes
> before parsing it.
> 
> nfc_llcp_rx_skb() reads the header via nfc_llcp_ptype()/nfc_llcp_dsap()/
> nfc_llcp_ssap(), which dereference pdu->data[0] and pdu->data[1], and a
> CONNECT or CC PDU then computes
> 
> 	tlv_array_len = skb->len - LLCP_HEADER_SIZE;
> 
> as a size_t and hands it to the TLV walk. When the frame is shorter than
> the header the subtraction wraps to a huge value and the walk runs far
> past the buffer, an out-of-bounds read.
> 
> A nearby NFC device can reach this without authentication; LLCP link
> activation happens automatically after NFC-DEP.
> 
> Guard the common receive choke point __nfc_llcp_recv(), shared by both the
> target (nfc_llcp_data_received()) and initiator (nfc_llcp_recv()) paths, so
> a short skb is dropped before the rx_work worker parses it. Use
> pskb_may_pull() rather than a skb->len test so the two header bytes are
> guaranteed to sit in the skb linear area even for a non-linear skb,
> matching how the sibling NCI and HCI receive paths validate their headers.
> 
> Reproduced with a KFENCE out-of-bounds read via /dev/virtual_nci on
> linux-next.
> 
> Found by 0sec automated security-research tooling (https://0sec.ai).
> 
> Fixes: d646960f7986 ("NFC: Initial LLCP support")
> Cc: stable@vger.kernel.org
> Suggested-by: David Laight <david.laight.linux@gmail.com>
> Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
> ---
> v3: use pskb_may_pull() so the guard also covers non-linear skbs and
>      guarantees the header bytes are in the linear area (David Laight).
> v2: move the guard into __nfc_llcp_recv() so both the target and
>      initiator receive paths are covered by a single check.
> 
> diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c
> index aed5fe1afef0..e3b2627cb089 100644
> --- a/net/nfc/llcp_core.c
> +++ b/net/nfc/llcp_core.c
> @@ -1565,6 +1565,11 @@ static void nfc_llcp_rx_work(struct work_struct *work)
>   
>   static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
>   {
> +	if (!pskb_may_pull(skb, LLCP_HEADER_SIZE)) {
> +		kfree_skb(skb);
> +		return;
> +	}
> +
>   	local->rx_pending = skb;
>   	timer_delete(&local->link_timer);
>   	schedule_work(&local->rx_work);

Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>

^ permalink raw reply

* [PATCH net] pds_core: fix auxiliary device add/del races
From: Nikhil P. Rao @ 2026-07-14 21:07 UTC (permalink / raw)
  To: netdev
  Cc: kuba, brett.creeley, eric.joyner, andrew+netdev, davem, edumazet,
	pabeni, Nikhil P. Rao

Two paths add or delete the same slot (pf->vfs[vf_id].padev): a VF's
pdsc_reset_done() and the PF's devlink enable_vnet/disable_vnet handler.
They serialize on config_lock, but neither guards the slot under it
correctly.

add() registers and stores a new auxiliary device without first checking
the slot, so a second add of an already-populated slot leaks the first
device. del() makes that check outside config_lock, so two concurrent
dels can both pass it; the first clears the slot, and the second
dereferences a NULL pointer.

Check and update the slot under config_lock in both paths.

Fixes: b699bdc720c0 ("pds_core: specify auxiliary_device to be created")
Reported-by: sashiko-bot@kernel.org # Running on a local machine
Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
Reviewed-by: Brett Creeley <brett.creeley@amd.com>
---
 drivers/net/ethernet/amd/pds_core/auxbus.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
index 73b3481220b1..3acafe10a6d5 100644
--- a/drivers/net/ethernet/amd/pds_core/auxbus.c
+++ b/drivers/net/ethernet/amd/pds_core/auxbus.c
@@ -177,17 +177,21 @@ void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
 {
 	struct pds_auxiliary_dev *padev;
 
-	if (!*pd_ptr)
-		return;
-
 	mutex_lock(&pf->config_lock);
 
+	/* A concurrent del may have already torn this device down and
+	 * cleared it.
+	 */
 	padev = *pd_ptr;
+	if (!padev)
+		goto out_unlock;
+
 	pds_client_unregister(pf, padev->client_id);
 	auxiliary_device_delete(&padev->aux_dev);
 	auxiliary_device_uninit(&padev->aux_dev);
 	*pd_ptr = NULL;
 
+out_unlock:
 	mutex_unlock(&pf->config_lock);
 }
 
@@ -210,6 +214,13 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
 
 	mutex_lock(&pf->config_lock);
 
+	/* Nothing to do if the aux device is already present.  This also
+	 * guards against a second add overwriting *pd_ptr and leaking the
+	 * first, symmetric with the check in pdsc_auxbus_dev_del().
+	 */
+	if (*pd_ptr)
+		goto out_unlock;
+
 	mask = BIT_ULL(PDSC_S_FW_DEAD) |
 	       BIT_ULL(PDSC_S_STOPPING_DRIVER);
 	if (cf->state & mask) {
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net-next 1/2] dt-bindings: net: add DAPU Telecom DAP8211R(I) PHY binding
From: Andrew Lunn @ 2026-07-14 21:10 UTC (permalink / raw)
  To: Artem Shimko
  Cc: netdev, Heiner Kallweit, Russell King, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-kernel, devicetree
In-Reply-To: <20260713131223.279555-2-a.shimko.dev@gmail.com>

> +  rx-internal-delay-ps:
> +    description:
> +      RGMII RX clock delay in picoseconds. The PHY supports 150 ps steps
> +      from 0 to 2250 ps. If not specified, defaults to 1950 ps. If the
> +      requested value does not exactly match a supported step, the driver
> +      selects the nearest supported value and issues a warning.
> +    enum: [0, 150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500,
> +           1650, 1800, 1950, 2100, 2250]
> +    default: 1950

The cover letter says you round to the nearest, but here you list
specific values.

Please remove the rounding and return EINVAL for the value is not one
of the listed values.

   Andrew
> +examples:
> +  - |
> +    mdio {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        ethernet-phy@1 {
> +            compatible = "ethernet-phy-ieee802.3-c22";
> +            reg = <1>;
> +            rx-internal-delay-ps = <1050>;
> +            tx-internal-delay-ps = <1150>;

Using values which probably don't work is maybe not a good idea. There
are too many DT developers who just cut/paste and don't think.

These are optional, so don't even bother? Or 2100 which probably does
actually work.

      Andrew

^ permalink raw reply

* [PATCH net v3] rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()
From: Xiang Mei @ 2026-07-14 21:22 UTC (permalink / raw)
  To: Allison Henderson, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman
  Cc: netdev, linux-rdma, rds-devel, linux-kernel, Santosh Shilimkar,
	Ka-Cheong Poon, bestswngs, Xiang Mei

rds_tcp_laddr_check() looks up a scoped IPv6 interface with
dev_get_by_index_rcu(), drops the RCU read-side lock, and only then
passes the bare struct net_device * into ipv6_chk_addr().

dev_get_by_index_rcu() only keeps the device alive within the same RCU
read-side section. After rcu_read_unlock(), a concurrent RTM_DELLINK can
free the net_device; ipv6_chk_addr() then dereferences the stale pointer
in __ipv6_chk_addr_and_flags() (e.g. l3mdev_master_dev_rcu(dev)), reading
freed memory.

Keep the RCU read-side lock held across the ipv6_chk_addr() call instead
of dropping it right after the lookup, so the device cannot be freed
while it is in use.

  BUG: KASAN: slab-use-after-free in __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
  Read of size 8 at addr ffff8880106ec000 by task exploit/153
  Call Trace:
   ...
   kasan_report (mm/kasan/report.c:595)
   __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
   ipv6_chk_addr (net/ipv6/addrconf.c:2031 net/ipv6/addrconf.c:1972)
   rds_tcp_laddr_check (net/rds/tcp.c:370)
   rds_bind (net/rds/bind.c:248)
   __sys_bind (net/socket.c:1920)
   __x64_sys_bind (net/socket.c:1956)
   do_syscall_64 (arch/x86/entry/syscall_64.c:63)
   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)

Changes since v1:
  Use rcu_read_locks instead of dev_hold/put
  Rebased on [PATCH net v2] rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled

Changes since v2:
  Add change log

Fixes: eee2fa6ab322 ("rds: Changing IP address internal representation to struct in6_addr")
Reported-by: Weiming Shi <bestswngs@gmail.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Allison Henderson <achender@kernel.org>
---
v2: Use rcu_read_locks and rebase on rds: Fix inet6_addr_lst NULL 
    dereference when IPv6 is disabled
v3: Add change log to commit message as Allison suggested


 net/rds/tcp.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 955d92277d5a..30cfb0087f2c 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -355,23 +355,25 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
 	/* If the scope_id is specified, check only those addresses
 	 * hosted on the specified interface.
 	 */
+	rcu_read_lock();
 	if (scope_id != 0) {
-		rcu_read_lock();
 		dev = dev_get_by_index_rcu(net, scope_id);
 		/* scope_id is not valid... */
 		if (!dev) {
 			rcu_read_unlock();
 			return -EADDRNOTAVAIL;
 		}
-		rcu_read_unlock();
 	}
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6_mod_enabled()) {
 		ret = ipv6_chk_addr(net, addr, dev, 0);
-		if (ret)
+		if (ret) {
+			rcu_read_unlock();
 			return 0;
+		}
 	}
 #endif
+	rcu_read_unlock();
 	return -EADDRNOTAVAIL;
 }
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net v2] rds: tcp: hold the RCU lock across ipv6_chk_addr() in rds_tcp_laddr_check()
From: Xiang Mei @ 2026-07-14 21:24 UTC (permalink / raw)
  To: Allison Henderson
  Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-rdma, rds-devel, linux-kernel,
	Santosh Shilimkar, Ka-Cheong Poon, bestswngs
In-Reply-To: <f69ec0975481ad04dc7403834bbb6b93d1092ecb.camel@kernel.org>

On Fri, Jul 10, 2026 at 8:53 PM Allison Henderson <achender@kernel.org> wrote:
>
> On Fri, 2026-07-10 at 15:30 -0700, Xiang Mei wrote:
> > rds_tcp_laddr_check() looks up a scoped IPv6 interface with
> > dev_get_by_index_rcu(), drops the RCU read-side lock, and only then
> > passes the bare struct net_device * into ipv6_chk_addr().
> >
> > dev_get_by_index_rcu() only keeps the device alive within the same RCU
> > read-side section. After rcu_read_unlock(), a concurrent RTM_DELLINK can
> > free the net_device; ipv6_chk_addr() then dereferences the stale pointer
> > in __ipv6_chk_addr_and_flags() (e.g. l3mdev_master_dev_rcu(dev)), reading
> > freed memory.
> >
> > Keep the RCU read-side lock held across the ipv6_chk_addr() call instead
> > of dropping it right after the lookup, so the device cannot be freed
> > while it is in use.
> >
> >   BUG: KASAN: slab-use-after-free in __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
> >   Read of size 8 at addr ffff8880106ec000 by task exploit/153
> >   Call Trace:
> >    ...
> >    kasan_report (mm/kasan/report.c:595)
> >    __ipv6_chk_addr_and_flags (... net/ipv6/addrconf.c:1998)
> >    ipv6_chk_addr (net/ipv6/addrconf.c:2031 net/ipv6/addrconf.c:1972)
> >    rds_tcp_laddr_check (net/rds/tcp.c:370)
> >    rds_bind (net/rds/bind.c:248)
> >    __sys_bind (net/socket.c:1920)
> >    __x64_sys_bind (net/socket.c:1956)
> >    do_syscall_64 (arch/x86/entry/syscall_64.c:63)
> >    entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
> >
>
>
>
> Thanks Xiang!  Just more thing to make sure your patches gets through. Add a change log here like this:
>
> Changes since v1:
>   Use rcu_read_locks instead of dev_hold/put
>   Rebased on [PATCH net v2] rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled
>
> Changes since v2:
>   Add change log
>
>
> Otherwise, it might get bounced if they happen to try your patch first.
> With that fixed:
> Reviewed-by: Allison Henderson <achender@kernel.org>
>
> Thanks!
> Allison
>
Thanks for the tips; I learned it!

v3 is ready:
https://lore.kernel.org/netdev/20260714212239.1511269-1-xmei5@asu.edu/T/#u

Xiang
> > Thanks Xiang!  Just more thing to make sure your patches gets through. Add a change log here like this:
> >
> > Changes since v1:
> >   Use rcu_read_locks instead of dev_hold/put
> >   Rebased on [PATCH net v2] rds: Fix inet6_addr_lst NULL dereference when IPv6 is disabled
> >
> > Changes since v2:
> >   Add change log
> >
> > Reviewed-by: Allison Henderson <achender@kernel.org>
> > Fixes: eee2fa6ab322 ("rds: Changing IP address internal representation to struct in6_addr")
> > Reported-by: Weiming Shi <bestswngs@gmail.com>
> > Assisted-by: Claude:claude-opus-4-8
> > Signed-off-by: Xiang Mei <xmei5@asu.edu>
> > ---
> >  net/rds/tcp.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/net/rds/tcp.c b/net/rds/tcp.c
> > index 955d92277d5a..30cfb0087f2c 100644
> > --- a/net/rds/tcp.c
> > +++ b/net/rds/tcp.c
> > @@ -355,23 +355,25 @@ int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
> >       /* If the scope_id is specified, check only those addresses
> >        * hosted on the specified interface.
> >        */
> > +     rcu_read_lock();
> >       if (scope_id != 0) {
> > -             rcu_read_lock();
> >               dev = dev_get_by_index_rcu(net, scope_id);
> >               /* scope_id is not valid... */
> >               if (!dev) {
> >                       rcu_read_unlock();
> >                       return -EADDRNOTAVAIL;
> >               }
> > -             rcu_read_unlock();
> >       }
> >  #if IS_ENABLED(CONFIG_IPV6)
> >       if (ipv6_mod_enabled()) {
> >               ret = ipv6_chk_addr(net, addr, dev, 0);
> > -             if (ret)
> > +             if (ret) {
> > +                     rcu_read_unlock();
> >                       return 0;
> > +             }
> >       }
> >  #endif
> > +     rcu_read_unlock();
> >       return -EADDRNOTAVAIL;
> >  }
> >
>

^ permalink raw reply

* Re: [PATCH net-next 2/2] net: phy: add DAPU Telecom DAP8210R(I) Gigabit Ethernet PHY driver
From: Andrew Lunn @ 2026-07-14 21:25 UTC (permalink / raw)
  To: Artem Shimko
  Cc: netdev, Heiner Kallweit, Russell King, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-kernel, devicetree
In-Reply-To: <20260713131223.279555-3-a.shimko.dev@gmail.com>

> The driver also exports a debugfs interface for diagnostics,
> exposing PHY status registers and providing runtime control over the
> internal packet generator, CRC corruption, and loopback functionality.

Please drop all this. Many PHYs have this sort of facility. We want
one generic API, probably via ethtool, which all PHYs can follow, not
N different incompatible APIs.

> +static u32 dap8211r_get_rgmii_delay(struct phy_device *phydev, const char *prop_name)
> +{
> +	struct device_node *np = phydev->mdio.dev.of_node;
> +	int ret;
> +	u32 ps = 0;
> +
> +	ret = of_property_read_u32(np, prop_name, &ps);
> +	if (ret) {
> +		phydev_dbg(phydev, "Using default delay (%ups)\n", DAP8211R_DEFAULT_DELAY_PS);
> +		ps = DAP8211R_DEFAULT_DELAY_PS;
> +	}

This can be simplified.

First off, there probably too many phydev_dbg() messages, specially
for normal case things, using defaults, etc. 

of_property_read_u32_array() is documented as not touching the results
value, if it does not find the property. So you can do:

	u32 ps = DAP8211R_DEFAULT_DELAY_PS;
	of_property_read_u32(np, prop_name, &ps);
  
	return dap8211r_delay_ps_to_sel(phydev, ps);

> +static int dap8211r_config_init(struct phy_device *phydev)
> +{
> +	struct device_node *phydev_node = phydev->mdio.dev.of_node;
> +	u16 mask = 0, set = 0;
> +	int ret;
> +
> +	switch (phydev->interface) {
> +	case PHY_INTERFACE_MODE_RGMII:
> +		break;

This is one of the less well defined areas. PHY_INTERFACE_MODE_RGMII
would mean either the PCB is adding the delay, or the MAC. There is no
reason however why the PHY cannot perform fine tuning, adding a small
delay, say 150ps. So you should respect the rx-internal-delay-ps and
tx-internal-delay-ps delays here. 

	Andrew

^ permalink raw reply

* [PATCH net] pds_core: check for workqueue allocation failure
From: Nikhil P. Rao @ 2026-07-14 21:27 UTC (permalink / raw)
  To: netdev
  Cc: kuba, brett.creeley, eric.joyner, andrew+netdev, davem, edumazet,
	pabeni, Nikhil P. Rao

pdsc_init_pf() does not check whether create_singlethread_workqueue()
succeeded.

Fail probe on failure. The workqueue is set up before the timer and
mutexes, so its failure path must unwind only the earlier setup.

Fixes: c2dbb0904310 ("pds_core: health timer and workqueue")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260629200358.2626129-1-nikhil.rao%40amd.com?part=2
Signed-off-by: Nikhil P. Rao <nikhil.rao@amd.com>
Reviewed-by: Brett Creeley <brett.creeley@amd.com>
---
 drivers/net/ethernet/amd/pds_core/main.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
index 22db78343eb0..f37e5fefa264 100644
--- a/drivers/net/ethernet/amd/pds_core/main.c
+++ b/drivers/net/ethernet/amd/pds_core/main.c
@@ -238,6 +238,10 @@ static int pdsc_init_pf(struct pdsc *pdsc)
 	/* General workqueue and timer, but don't start timer yet */
 	snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid);
 	pdsc->wq = create_singlethread_workqueue(wq_name);
+	if (!pdsc->wq) {
+		err = -ENOMEM;
+		goto err_out_unmap_bars;
+	}
 	INIT_WORK(&pdsc->health_work, pdsc_health_thread);
 	INIT_WORK(&pdsc->pci_reset_work, pdsc_pci_reset_thread);
 	timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
@@ -253,7 +257,7 @@ static int pdsc_init_pf(struct pdsc *pdsc)
 	err = pdsc_setup(pdsc, PDSC_SETUP_INIT);
 	if (err) {
 		mutex_unlock(&pdsc->config_lock);
-		goto err_out_unmap_bars;
+		goto err_out_shutdown_timer;
 	}
 
 	err = pdsc_start(pdsc);
@@ -305,13 +309,14 @@ static int pdsc_init_pf(struct pdsc *pdsc)
 	pdsc_stop(pdsc);
 err_out_teardown:
 	pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
-err_out_unmap_bars:
+err_out_shutdown_timer:
 	timer_shutdown_sync(&pdsc->wdtimer);
 	if (pdsc->wq)
 		destroy_workqueue(pdsc->wq);
 	mutex_destroy(&pdsc->config_lock);
 	mutex_destroy(&pdsc->devcmd_lock);
 	pci_free_irq_vectors(pdsc->pdev);
+err_out_unmap_bars:
 	pdsc_unmap_bars(pdsc);
 err_out_release_regions:
 	pci_release_regions(pdsc->pdev);
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net-next 0/2] net: phy: Add Maxio MAE0621A support
From: Andrew Lunn @ 2026-07-14 21:29 UTC (permalink / raw)
  To: Liu Changjie
  Cc: Heiner Kallweit, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, Russell King, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel
In-Reply-To: <MN0PR19MB6091CD5A84D2DA5DACF434DAACF92@MN0PR19MB6091.namprd19.prod.outlook.com>

> Hardware tests with the 125 MHz setting:
> - 1 Gbit/s, full duplex link negotiation

What happens when 100Mbps or 10Mbps is negotiated? Has that been
tested?

	Andrew

^ permalink raw reply

* Re: [PATCH] net: phy: Add driver for Motorcomm Quad 2.5GbE phy
From: Andrew Lunn @ 2026-07-14 21:43 UTC (permalink / raw)
  To: Kyle Switch
  Cc: Frank.Sae, hkallweit1, linux, davem, edumazet, kuba, pabeni,
	netdev, linux-kernel, jianmin.wang, ming.xu, xiaolin.xu, jie.han
In-Reply-To: <20260714111203.3852126-1-kyle.switch@motor-comm.com>

On Tue, Jul 14, 2026 at 07:12:03PM +0800, Kyle Switch wrote:
> Add a driver for motorcomm yt8824 quad 2.5G ethernet phy, supports
> 2.5G/1000M/100M/10M speed.

Please take a read of:

https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html

and set the Subject line correctly.

> +#define REG_MII_MMD_CTRL			0x0D
> +#define REG_MII_MMD_DATA			0x0E

include/uapi/linux/mii.h

#define	MII_MMD_CTRL		0x0d	/* MMD Access Control Register */
#define	MII_MMD_DATA		0x0e	/* MMD Access Data Register */

Please don't repeat something which already exists. But i also wounder
why you need these.

> +static int ytphy_write_mmd(struct phy_device *phydev,
> +			   u16 device, u16 reg,
> +			   u16 value)
> +{
> +	int ret;
> +
> +	ret = __phy_write(phydev, REG_MII_MMD_CTRL, device);
> +	if (ret)
> +		return ret;
> +	ret = __phy_write(phydev, REG_MII_MMD_DATA, reg);
> +	if (ret)
> +		return ret;
> +	ret = __phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
> +	if (ret)
> +		return ret;
> +	ret = __phy_write(phydev, REG_MII_MMD_DATA, value);
> +
> +	return ret;
> +}

Why are you reinventing these functions when they already exist?

> +
>  /**
>   * ytphy_get_wol() - report whether wake-on-lan is enabled
>   * @phydev: a pointer to a &struct phy_device
> @@ -3059,99 +3187,1620 @@ static int yt8821_resume(struct phy_device *phydev)
>  	return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
>  }
>  
> -static struct phy_driver motorcomm_phy_drvs[] = {
> -	{
> -		PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
> -		.name		= "YT8511 Gigabit Ethernet",
> -		.config_init	= yt8511_config_init,
> -		.suspend	= genphy_suspend,
> -		.resume		= genphy_resume,
> -		.read_page	= yt8511_read_page,
> -		.write_page	= yt8511_write_page,
> -	},
> -	{
> -		PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
> -		.name		= "YT8521 Gigabit Ethernet",
> -		.get_features	= yt8521_get_features,
> -		.probe		= yt8521_probe,

Why are these all stoppering? diff would not remove them unless
something is changing.


    Andrew

---
pw-bot: cr

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox