* Re: [PATCH bpf v3 1/2] bpf, sockmap: fix use-after-free when the stream parser resizes the skb
From: John Fastabend @ 2026-06-18 18:01 UTC (permalink / raw)
To: Jiayuan Chen; +Cc: netdev, bpf, linux-kernel, Jakub Kicinski, Sechang Lim
In-Reply-To: <34f330b8-60d2-4647-a6b4-a5b001c3715d@linux.dev>
On Thu, Jun 18, 2026 at 07:56:34PM +0800, Jiayuan Chen wrote:
>
>On 6/18/26 6:27 PM, Sechang Lim wrote:
>>sk_psock_strp_parse() runs the BPF_PROG_TYPE_SK_SKB stream-parser program
>>to find the length of the next message. strparser assembles a message out
>>of several received skbs by chaining them onto the head's frag_list and
>>recording where to append the next one in strp->skb_nextp:
>>
>> *strp->skb_nextp = skb;
>> strp->skb_nextp = &skb->next;
>>
>>and then calls the parser on the head:
>>
>> len = (*strp->cb.parse_msg)(strp, head);
>
>[...]
>
>>unaffected and may still modify the skb.
>>
>>Fixes: 8a31db561566 ("bpf: add access to sock fields and pkt data from sk_skb programs")
>
>Is the Fixes tag correct ?
>
>Anyway, I don't think this patch is a fix; it's more of a hardening.
>So no Fixes tag needed, IMO.
>
>
>>Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com>
>>---
[...]
>
>
>CI failed:
>https://github.com/kernel-patches/bpf/actions/runs/27754218839/job/82113319982
> Failed stream parser bpf prog attach
>
>Hi John
>I noticed that bpf_skb_pull_data was added to the skmsg test:
>https://github.com/torvalds/linux/commit/82a8616889d506cb690cfc0afb2ccadda120461d
>
>Can we drop bpf_skb_pull_data in parser prog(sockmap_parse_prog.c) ?
>And are there any scenarios where we need to modify skb len when using
>strparser ?
We should never modify the skb from strparser. Just remove any tests
that do this and state its not safe. We haven't used strparser progs
for a long time anyways.
^ permalink raw reply
* Re: [PATCH net] igb: only strip Rx timestamp header on the first buffer of a frame
From: Tony Nguyen @ 2026-06-18 17:38 UTC (permalink / raw)
To: Kurt Kanzenbach, Tjerk Kusters, netdev@vger.kernel.org
Cc: intel-wired-lan@lists.osuosl.org, przemyslaw.kitszel@intel.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, richardcochran@gmail.com,
hawk@kernel.org, stable@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <8733yojljf.fsf@jax.kurt.home>
On 6/15/2026 12:43 AM, Kurt Kanzenbach wrote:
> Hi,
>
> On Fri Jun 12 2026, Tjerk Kusters wrote:
>> Hi,
>>
>> The patch is attached (0001-igb-only-strip-Rx-timestamp-header-on-the-first-buff.patch)
>> as my mail setup cannot send it inline via git send-email; apologies for the
>> attachment.
>
> b4 has a web submission endpoint. Maybe you can use that one:
>
> https://b4.docs.kernel.org/en/latest/contributor/send.html
Hi Tjerk,
It would be great if you could get this setup as it makes patch handling
easier.
> [snip]
>
>> From fee3e3452dfcd7e109332369672a3e0090cadeb3 Mon Sep 17 00:00:00 2001
>> From: T Kusters <tkusters@aweta.nl>
>> Date: Tue, 9 Jun 2026 14:06:24 +0200
>> Subject: [PATCH net] igb: only strip Rx timestamp header on the first buffer
>> of a frame
>>
>> When Rx hardware timestamping is enabled (e.g. ptp4l, which configures
>> HWTSTAMP_FILTER_ALL), the NIC prepends a 16-byte timestamp header to the
>> first Rx buffer of every received frame. igb_clean_rx_irq() strips this
>> header inside its per-buffer loop:
>>
>> if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
>> ts_hdr_len = igb_ptp_rx_pktstamp(rx_ring->q_vector,
>> pktbuf, ×tamp);
>> pkt_offset += ts_hdr_len;
>> size -= ts_hdr_len;
>> }
>>
>> For a frame that spans more than one Rx buffer (e.g. a jumbo frame), this
>> block runs once per buffer. The timestamp header only exists at the start
>> of the first buffer, but igb_ptp_rx_pktstamp() is called for every buffer.
>>
>> On a continuation buffer the data is packet payload, not a timestamp
>> header. igb_ptp_rx_pktstamp() already has two guards against acting on a
>> non-header buffer: it returns 0 if PTP is disabled, and returns 0 if the
>> reserved dwords (the first 8 bytes) are non-zero. Neither is sufficient
>> here: PTP is enabled, and a continuation buffer whose payload happens to
>> begin with 8 zero bytes passes the reserved-dword check. In that case the
>> payload is mistaken for a valid timestamp header and igb_ptp_rx_pktstamp()
>> returns IGB_TS_HDR_LEN, so the caller strips 16 bytes of real data from
>> that buffer. A frame spanning N buffers whose continuation buffers start
>> with zero bytes therefore loses 16 * (N - 1) bytes from its tail.
>>
>> This is easily triggered by a GigE Vision camera streaming dark frames
>> (mostly 0x00 pixel data) over jumbo UDP with PTP active on the receiver:
>> the all-zero frames arrive truncated while frames with non-zero content
>> are fine. There is no error indication.
>>
>> No content-based check can reliably tell a continuation buffer that begins
>> with zero bytes from a real timestamp header, because both are all zero.
>> Fix it structurally instead: only attempt the strip on the first buffer of
>> a frame, which is the only buffer that can contain a timestamp header. In
>> igb_clean_rx_irq() skb is NULL until the first buffer has been processed,
>> so guarding the strip with !skb restricts it to the first buffer
>> regardless of payload content.
>>
>> Fixes: 5379260852b0 ("igb: Fix XDP with PTP enabled")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: T Kusters <tkusters@aweta.nl>
Sign off should be your full name.
Thanks,
Tony
> Great explanation! igb_clean_rx_irq_zc() does not need the same
> treatment, correct?
>
> Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
>
>> ---
>> drivers/net/ethernet/intel/igb/igb_main.c | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
>> index ce91dda00ec0..abb55cd589a9 100644
>> --- a/drivers/net/ethernet/intel/igb/igb_main.c
>> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
>> @@ -9061,7 +9061,8 @@ static int igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
>> pktbuf = page_address(rx_buffer->page) + rx_buffer->page_offset;
>>
>> /* pull rx packet timestamp if available and valid */
>> - if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
>> + if (!skb &&
>> + igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
>> int ts_hdr_len;
>>
>> ts_hdr_len = igb_ptp_rx_pktstamp(rx_ring->q_vector,
>> --
>> 2.27.0
>>
^ permalink raw reply
* [PATCH v28 5/5] sfc: support pio mapping based on cxl
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero
In-Reply-To: <20260618181806.118745-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
A PIO buffer is a region of device memory to which the driver can write a
packet for TX, with the device handling the transmit doorbell without
requiring a DMA for getting the packet data, which helps reducing latency
in certain exchanges. With CXL mem protocol this latency can be lowered
further.
With a device supporting CXL and successfully initialised, use the cxl
region to map the memory range and use this mapping for PIO buffers.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
---
drivers/net/ethernet/sfc/ef10.c | 41 ++++++++++++++++++++++-----
drivers/net/ethernet/sfc/efx.h | 1 -
drivers/net/ethernet/sfc/efx_cxl.c | 1 +
drivers/net/ethernet/sfc/net_driver.h | 1 +
drivers/net/ethernet/sfc/nic.h | 3 ++
5 files changed, 39 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 7e04f115bbaa..73bc064929f6 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <net/udp_tunnel.h>
+#include "efx_cxl.h"
/* Hardware control for EF10 architecture including 'Huntington'. */
@@ -106,7 +107,7 @@ static int efx_ef10_get_vf_index(struct efx_nic *efx)
static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
- MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V4_OUT_LEN);
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V7_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
@@ -177,6 +178,12 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
efx->num_mac_stats);
}
+ if (outlen < MC_CMD_GET_CAPABILITIES_V7_OUT_LEN)
+ nic_data->datapath_caps3 = 0;
+ else
+ nic_data->datapath_caps3 = MCDI_DWORD(outbuf,
+ GET_CAPABILITIES_V7_OUT_FLAGS3);
+
return 0;
}
@@ -1140,6 +1147,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
unsigned int channel_vis, pio_write_vi_base, max_vis;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
unsigned int uc_mem_map_size, wc_mem_map_size;
+#ifdef CONFIG_SFC_CXL
+ struct efx_probe_data *probe_data;
+#endif
void __iomem *membase;
int rc;
@@ -1263,8 +1273,23 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
iounmap(efx->membase);
efx->membase = membase;
- /* Set up the WC mapping if needed */
- if (wc_mem_map_size) {
+ if (!wc_mem_map_size)
+ goto skip_pio;
+
+ /* Set up the WC mapping */
+
+#ifdef CONFIG_SFC_CXL
+ probe_data = container_of(efx, struct efx_probe_data, efx);
+ if ((nic_data->datapath_caps3 &
+ (1 << MC_CMD_GET_CAPABILITIES_V7_OUT_CXL_CONFIG_ENABLE_LBN)) &&
+ probe_data->cxl_pio_initialised) {
+ /* Using PIO through CXL mapping */
+ nic_data->pio_write_base = probe_data->cxl->ctpio_cxl;
+ nic_data->pio_write_vi_base = pio_write_vi_base;
+ } else
+#endif
+ {
+ /* Using legacy PIO BAR mapping */
nic_data->wc_membase = ioremap_wc(efx->membase_phys +
uc_mem_map_size,
wc_mem_map_size);
@@ -1279,12 +1304,14 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
nic_data->wc_membase +
(pio_write_vi_base * efx->vi_stride + ER_DZ_TX_PIOBUF -
uc_mem_map_size);
-
- rc = efx_ef10_link_piobufs(efx);
- if (rc)
- efx_ef10_free_piobufs(efx);
}
+ rc = efx_ef10_link_piobufs(efx);
+ if (rc)
+ efx_ef10_free_piobufs(efx);
+
+skip_pio:
+
netif_dbg(efx, probe, efx->net_dev,
"memory BAR at %pa (virtual %p+%x UC, %p+%x WC)\n",
&efx->membase_phys, efx->membase, uc_mem_map_size,
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 45e191686625..057d30090894 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -236,5 +236,4 @@ static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
int efx_xdp_tx_buffers(struct efx_nic *efx, int n, struct xdp_frame **xdpfs,
bool flush);
-
#endif /* EFX_EFX_H */
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 3e7c950f83e9..348d7404cd7a 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -88,6 +88,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
return -ENOMEM;
}
+ probe_data->cxl_pio_initialised = true;
probe_data->cxl = cxl;
return 0;
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index de3fc9537662..3964b2c56609 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1213,6 +1213,7 @@ struct efx_probe_data {
struct efx_nic efx;
#ifdef CONFIG_SFC_CXL
struct efx_cxl *cxl;
+ bool cxl_pio_initialised;
#endif
};
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index ec3b2df43b68..7480f9995dfb 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -152,6 +152,8 @@ enum {
* %MC_CMD_GET_CAPABILITIES response)
* @datapath_caps2: Further Capabilities of datapath firmware (FLAGS2 field of
* %MC_CMD_GET_CAPABILITIES response)
+ * @datapath_caps3: Further Capabilities of datapath firmware (FLAGS3 field of
+ * %MC_CMD_GET_CAPABILITIES response)
* @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU
* @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU
* @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot
@@ -187,6 +189,7 @@ struct efx_ef10_nic_data {
bool must_check_datapath_caps;
u32 datapath_caps;
u32 datapath_caps2;
+ u32 datapath_caps3;
unsigned int rx_dpcpu_fw_id;
unsigned int tx_dpcpu_fw_id;
bool must_probe_vswitching;
--
2.34.1
^ permalink raw reply related
* [PATCH v28 4/5] sfc: obtain and map cxl range using devm_cxl_probe_mem
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero
In-Reply-To: <20260618181806.118745-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Use core API for safely obtain the CXL range linked to an HDM committed
by the BIOS. Map such a range for being used as the ctpio buffer.
A potential user space action through sysfs unbinding or core cxl
modules remove will trigger sfc driver device detachment, with that case
not racing with this mapping as this is done during driver probe and
therefore protected with device lock against those user space actions.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
---
drivers/net/ethernet/sfc/efx.c | 2 ++
drivers/net/ethernet/sfc/efx_cxl.c | 23 +++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 3 +++
3 files changed, 28 insertions(+)
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index da008462096d..abfa0ce2b4d1 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -984,6 +984,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_fini_io(efx);
probe_data = container_of(efx, struct efx_probe_data, efx);
+ efx_cxl_exit(probe_data);
pci_dbg(efx->pci_dev, "shutdown successful\n");
@@ -1244,6 +1245,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
fail3:
efx_fini_io(efx);
fail2:
+ efx_cxl_exit(probe_data);
efx_fini_struct(efx);
fail1:
WARN_ON(rc > 0);
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 18b535b3ea40..3e7c950f83e9 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -18,6 +18,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
{
struct efx_nic *efx = &probe_data->efx;
struct pci_dev *pci_dev = efx->pci_dev;
+ struct range cxl_pio_range;
struct efx_cxl *cxl;
u16 dvsec;
int rc;
@@ -73,9 +74,31 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
return -ENODEV;
}
+ cxl->cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl_pio_range);
+ if (IS_ERR(cxl->cxlmd)) {
+ pci_err(pci_dev, "CXL accel memdev creation failed\n");
+ return PTR_ERR(cxl->cxlmd);
+ }
+
+ cxl->ctpio_cxl = ioremap_wc(cxl_pio_range.start,
+ range_len(&cxl_pio_range));
+ if (!cxl->ctpio_cxl) {
+ pci_err(pci_dev, "CXL ioremap region (%pra) failed\n",
+ &cxl_pio_range);
+ return -ENOMEM;
+ }
+
probe_data->cxl = cxl;
return 0;
}
+void efx_cxl_exit(struct efx_probe_data *probe_data)
+{
+ if (!probe_data->cxl)
+ return;
+
+ iounmap(probe_data->cxl->ctpio_cxl);
+}
+
MODULE_IMPORT_NS("CXL");
diff --git a/drivers/net/ethernet/sfc/efx_cxl.h b/drivers/net/ethernet/sfc/efx_cxl.h
index 04e46278464d..3e2705cb063f 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.h
+++ b/drivers/net/ethernet/sfc/efx_cxl.h
@@ -20,10 +20,13 @@ struct efx_probe_data;
struct efx_cxl {
struct cxl_dev_state cxlds;
struct cxl_memdev *cxlmd;
+ void __iomem *ctpio_cxl;
};
int efx_cxl_init(struct efx_probe_data *probe_data);
+void efx_cxl_exit(struct efx_probe_data *probe_data);
#else
static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
+static inline void efx_cxl_exit(struct efx_probe_data *probe_data) {}
#endif
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v28 3/5] cxl/sfc: Initialize dpa without a mailbox
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Ben Cheatham, Jonathan Cameron
In-Reply-To: <20260618181806.118745-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Type3 relies on mailbox CXL_MBOX_OP_IDENTIFY command for initializing
memdev state params which end up being used for DPA initialization.
Allow a Type2 driver to initialize DPA simply by giving the size of its
volatile hardware partition.
Move related functions to memdev.
Add sfc driver as the client.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
drivers/cxl/core/core.h | 2 +
drivers/cxl/core/mbox.c | 51 +----------------------
drivers/cxl/core/memdev.c | 67 ++++++++++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.c | 5 +++
include/cxl/cxl.h | 2 +
5 files changed, 77 insertions(+), 50 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 07555ae63859..f7cebb026552 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -101,6 +101,8 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
struct dentry *cxl_debugfs_create_dir(const char *dir);
int cxl_dpa_set_part(struct cxl_endpoint_decoder *cxled,
enum cxl_partition_mode mode);
+struct cxl_memdev_state;
+int cxl_mem_get_partition_info(struct cxl_memdev_state *mds);
int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size);
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 7c6c5b7450a5..97b1e61ad018 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1152,7 +1152,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL");
*
* See CXL @8.2.9.5.2.1 Get Partition Info
*/
-static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
+int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
struct cxl_mbox_get_partition_info pi;
@@ -1308,55 +1308,6 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
return -EBUSY;
}
-static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
-{
- int i = info->nr_partitions;
-
- if (size == 0)
- return;
-
- info->part[i].range = (struct range) {
- .start = start,
- .end = start + size - 1,
- };
- info->part[i].mode = mode;
- info->nr_partitions++;
-}
-
-int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
-{
- struct cxl_dev_state *cxlds = &mds->cxlds;
- struct device *dev = cxlds->dev;
- int rc;
-
- if (!cxlds->media_ready) {
- info->size = 0;
- return 0;
- }
-
- info->size = mds->total_bytes;
-
- if (mds->partition_align_bytes == 0) {
- add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
- add_part(info, mds->volatile_only_bytes,
- mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
- return 0;
- }
-
- rc = cxl_mem_get_partition_info(mds);
- if (rc) {
- dev_err(dev, "Failed to query partition information\n");
- return rc;
- }
-
- add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
- add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
- CXL_PARTMODE_PMEM);
-
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
-
int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 33a3d2e7b13a..500f077f935d 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -594,6 +594,73 @@ bool is_cxl_memdev(const struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL");
+static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
+{
+ int i = info->nr_partitions;
+
+ if (size == 0)
+ return;
+
+ info->part[i].range = (struct range) {
+ .start = start,
+ .end = start + size - 1,
+ };
+ info->part[i].mode = mode;
+ info->nr_partitions++;
+}
+
+int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
+{
+ struct cxl_dev_state *cxlds = &mds->cxlds;
+ struct device *dev = cxlds->dev;
+ int rc;
+
+ if (!cxlds->media_ready) {
+ info->size = 0;
+ return 0;
+ }
+
+ info->size = mds->total_bytes;
+
+ if (mds->partition_align_bytes == 0) {
+ add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
+ add_part(info, mds->volatile_only_bytes,
+ mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
+ return 0;
+ }
+
+ rc = cxl_mem_get_partition_info(mds);
+ if (rc) {
+ dev_err(dev, "Failed to query partition information\n");
+ return rc;
+ }
+
+ add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
+ add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
+ CXL_PARTMODE_PMEM);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
+
+
+/**
+ * cxl_set_capacity: initialize dpa by a driver without a mailbox.
+ *
++ * @cxlds: pointer to cxl_dev_state
+ * @capacity: device volatile memory size
+ */
+int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity)
+{
+ struct cxl_dpa_info range_info = {
+ .size = capacity,
+ };
+
+ add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM);
+ return cxl_dpa_setup(cxlds, &range_info);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_set_capacity, "CXL");
+
/**
* set_exclusive_cxl_commands() - atomically disable user cxl commands
* @mds: The device state to operate on
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index 704b0ebae937..18b535b3ea40 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -68,6 +68,11 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
*/
cxl->cxlds.media_ready = true;
+ if (cxl_set_capacity(&cxl->cxlds, EFX_CTPIO_BUFFER_SIZE)) {
+ pci_err(pci_dev, "dpa capacity setup failed\n");
+ return -ENODEV;
+ }
+
probe_data->cxl = cxl;
return 0;
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 016c74fb747c..802b143de83d 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -226,4 +226,6 @@ struct cxl_dev_state *_devm_cxl_dev_state_create(struct device *dev,
struct cxl_memdev *devm_cxl_probe_mem(struct cxl_dev_state *cxlds,
struct range *range);
+
+int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity);
#endif /* __CXL_CXL_H__ */
--
2.34.1
^ permalink raw reply related
* [PATCH v28 2/5] cxl/sfc: Map cxl regs
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero, Dan Williams, Jonathan Cameron, Ben Cheatham
In-Reply-To: <20260618181806.118745-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Export cxl core functions for a Type2 driver being able to discover and
map the device registers.
Use it in sfc driver cxl initialization.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
---
drivers/cxl/core/pci.c | 1 +
drivers/cxl/core/port.c | 1 +
drivers/cxl/core/regs.c | 1 +
drivers/cxl/cxlpci.h | 12 ------------
drivers/cxl/pci.c | 1 +
drivers/net/ethernet/sfc/efx_cxl.c | 26 ++++++++++++++++++++++++++
include/cxl/pci.h | 22 ++++++++++++++++++++++
7 files changed, 52 insertions(+), 12 deletions(-)
create mode 100644 include/cxl/pci.h
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index d1f487b3d809..2bcd683aa286 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
+#include <cxl/pci.h>
#include <linux/aer.h>
#include <cxlpci.h>
#include <cxlmem.h>
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 1215ee4f4035..cb633e19151b 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <linux/node.h>
#include <cxl/einj.h>
+#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <cxl.h>
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 93710cf4f0a6..20c2d9fbcfe7 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <pmu.h>
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index b826eb53cf7b..110ec9c44f09 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -13,16 +13,6 @@
*/
#define CXL_PCI_DEFAULT_MAX_VECTORS 16
-/* Register Block Identifier (RBI) */
-enum cxl_regloc_type {
- CXL_REGLOC_RBI_EMPTY = 0,
- CXL_REGLOC_RBI_COMPONENT,
- CXL_REGLOC_RBI_VIRT,
- CXL_REGLOC_RBI_MEMDEV,
- CXL_REGLOC_RBI_PMU,
- CXL_REGLOC_RBI_TYPES
-};
-
/*
* Table Access DOE, CDAT Read Entry Response
*
@@ -112,6 +102,4 @@ static inline void devm_cxl_port_ras_setup(struct cxl_port *port)
}
#endif
-int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
- struct cxl_register_map *map);
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 267c679b0b3c..bb892dbfdd6d 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/io.h>
+#include <cxl/pci.h>
#include <cxl/mailbox.h>
#include "cxlmem.h"
#include "cxlpci.h"
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
index be252af972ab..704b0ebae937 100644
--- a/drivers/net/ethernet/sfc/efx_cxl.c
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -7,6 +7,8 @@
#include <linux/pci.h>
+#include <cxl/cxl.h>
+#include <cxl/pci.h>
#include "net_driver.h"
#include "efx_cxl.h"
@@ -18,6 +20,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
struct pci_dev *pci_dev = efx->pci_dev;
struct efx_cxl *cxl;
u16 dvsec;
+ int rc;
/* Is the device configured with and using CXL? */
if (!pcie_is_cxl(pci_dev))
@@ -42,6 +45,29 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
if (!cxl)
return -ENOMEM;
+ rc = cxl_pci_setup_regs(pci_dev, CXL_REGLOC_RBI_COMPONENT,
+ &cxl->cxlds.reg_map);
+ if (rc) {
+ pci_err(pci_dev, "No component registers\n");
+ return rc;
+ }
+
+ if (!cxl->cxlds.reg_map.component_map.hdm_decoder.valid) {
+ pci_err(pci_dev, "Expected HDM component register not found\n");
+ return -ENODEV;
+ }
+
+ if (!cxl->cxlds.reg_map.component_map.ras.valid) {
+ pci_err(pci_dev, "Expected RAS component register not found\n");
+ return -ENODEV;
+ }
+
+ /* Set media ready explicitly as there are neither mailbox for checking
+ * this state nor the CXL register involved, both not mandatory for
+ * type2.
+ */
+ cxl->cxlds.media_ready = true;
+
probe_data->cxl = cxl;
return 0;
diff --git a/include/cxl/pci.h b/include/cxl/pci.h
new file mode 100644
index 000000000000..3e0000015871
--- /dev/null
+++ b/include/cxl/pci.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+
+#ifndef __CXL_CXL_PCI_H__
+#define __CXL_CXL_PCI_H__
+
+/* Register Block Identifier (RBI) */
+enum cxl_regloc_type {
+ CXL_REGLOC_RBI_EMPTY = 0,
+ CXL_REGLOC_RBI_COMPONENT,
+ CXL_REGLOC_RBI_VIRT,
+ CXL_REGLOC_RBI_MEMDEV,
+ CXL_REGLOC_RBI_PMU,
+ CXL_REGLOC_RBI_TYPES
+};
+
+struct cxl_register_map;
+struct pci_dev;
+
+int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
+ struct cxl_register_map *map);
+#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v28 1/5] sfc: add cxl support
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero, Jonathan Cameron, Edward Cree, Alison Schofield,
Dan Williams
In-Reply-To: <20260618181806.118745-1-alejandro.lucero-palau@amd.com>
From: Alejandro Lucero <alucerop@amd.com>
Add CXL initialization based on new CXL API for accel drivers and make
it dependent on kernel CXL configuration.
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Edward Cree <ecree.xilinx@gmail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
drivers/net/ethernet/sfc/Kconfig | 9 +++++
drivers/net/ethernet/sfc/Makefile | 1 +
drivers/net/ethernet/sfc/efx.c | 16 ++++++++-
drivers/net/ethernet/sfc/efx_cxl.c | 50 +++++++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 29 ++++++++++++++++
drivers/net/ethernet/sfc/net_driver.h | 9 +++++
6 files changed, 113 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.c
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.h
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index c4c43434f314..979f2801e2a8 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -66,6 +66,15 @@ config SFC_MCDI_LOGGING
Driver-Interface) commands and responses, allowing debugging of
driver/firmware interaction. The tracing is actually enabled by
a sysfs file 'mcdi_logging' under the PCI device.
+config SFC_CXL
+ bool "Solarflare SFC9100-family CXL support"
+ depends on SFC && CXL_BUS >= SFC
+ default SFC
+ help
+ This enables SFC CXL support if the kernel is configuring CXL for
+ using CTPIO with CXL.mem. The SFC device with CXL support and
+ with a CXL-aware firmware can be used for minimizing latencies
+ when sending through CTPIO.
source "drivers/net/ethernet/sfc/falcon/Kconfig"
source "drivers/net/ethernet/sfc/siena/Kconfig"
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index d99039ec468d..bb0f1891cde6 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -13,6 +13,7 @@ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
mae.o tc.o tc_bindings.o tc_counters.o \
tc_encap_actions.o tc_conntrack.o
+sfc-$(CONFIG_SFC_CXL) += efx_cxl.o
obj-$(CONFIG_SFC) += sfc.o
obj-$(CONFIG_SFC_FALCON) += falcon/
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 8f136a11d396..da008462096d 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -34,6 +34,7 @@
#include "selftest.h"
#include "sriov.h"
#include "efx_devlink.h"
+#include "efx_cxl.h"
#include "mcdi_port_common.h"
#include "mcdi_pcol.h"
@@ -981,12 +982,14 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_pci_remove_main(efx);
efx_fini_io(efx);
+
+ probe_data = container_of(efx, struct efx_probe_data, efx);
+
pci_dbg(efx->pci_dev, "shutdown successful\n");
efx_fini_devlink_and_unlock(efx);
efx_fini_struct(efx);
free_netdev(efx->net_dev);
- probe_data = container_of(efx, struct efx_probe_data, efx);
kfree(probe_data);
};
@@ -1190,6 +1193,17 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail2;
+ /* A successful cxl initialization implies a CXL region created to be
+ * used for PIO buffers. If there is no CXL support legacy PIO buffers
+ * defined at specific PCI BAR regions will be used. If there is CXL
+ * support and the cxl initialization fails, the driver probe fails.
+ */
+ rc = efx_cxl_init(probe_data);
+ if (rc) {
+ pci_err(pci_dev, "CXL initialization failed with error %d\n", rc);
+ goto fail2;
+ }
+
rc = efx_pci_probe_post_io(efx);
if (rc) {
/* On failure, retry once immediately.
diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
new file mode 100644
index 000000000000..be252af972ab
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_cxl.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ *
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2025, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/pci.h>
+
+#include "net_driver.h"
+#include "efx_cxl.h"
+
+#define EFX_CTPIO_BUFFER_SIZE SZ_256M
+
+int efx_cxl_init(struct efx_probe_data *probe_data)
+{
+ struct efx_nic *efx = &probe_data->efx;
+ struct pci_dev *pci_dev = efx->pci_dev;
+ struct efx_cxl *cxl;
+ u16 dvsec;
+
+ /* Is the device configured with and using CXL? */
+ if (!pcie_is_cxl(pci_dev))
+ return 0;
+
+ dvsec = pci_find_dvsec_capability(pci_dev, PCI_VENDOR_ID_CXL,
+ PCI_DVSEC_CXL_DEVICE);
+ if (!dvsec) {
+ pci_info(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability not found\n");
+ return 0;
+ }
+
+ pci_dbg(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability found\n");
+
+ /* Create a cxl_dev_state embedded in the cxl struct using cxl core api
+ * specifying no mbox available.
+ */
+ cxl = devm_cxl_dev_state_create(&pci_dev->dev, CXL_DEVTYPE_DEVMEM,
+ pci_get_dsn(pci_dev), dvsec,
+ struct efx_cxl, cxlds, false);
+
+ if (!cxl)
+ return -ENOMEM;
+
+ probe_data->cxl = cxl;
+
+ return 0;
+}
+
+MODULE_IMPORT_NS("CXL");
diff --git a/drivers/net/ethernet/sfc/efx_cxl.h b/drivers/net/ethernet/sfc/efx_cxl.h
new file mode 100644
index 000000000000..04e46278464d
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_cxl.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2025, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_CXL_H
+#define EFX_CXL_H
+
+#ifdef CONFIG_SFC_CXL
+
+#include <cxl/cxl.h>
+
+struct efx_probe_data;
+
+struct efx_cxl {
+ struct cxl_dev_state cxlds;
+ struct cxl_memdev *cxlmd;
+};
+
+int efx_cxl_init(struct efx_probe_data *probe_data);
+#else
+static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
+#endif
+#endif
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index b98c259f672d..de3fc9537662 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1197,14 +1197,23 @@ struct efx_nic {
atomic_t n_rx_noskb_drops;
};
+#ifdef CONFIG_SFC_CXL
+struct efx_cxl;
+#endif
+
/**
* struct efx_probe_data - State after hardware probe
* @pci_dev: The PCI device
* @efx: Efx NIC details
+ * @cxl: details of related cxl objects
+ * @cxl_pio_initialised: cxl initialization outcome.
*/
struct efx_probe_data {
struct pci_dev *pci_dev;
struct efx_nic efx;
+#ifdef CONFIG_SFC_CXL
+ struct efx_cxl *cxl;
+#endif
};
static inline struct efx_nic *efx_netdev_priv(struct net_device *dev)
--
2.34.1
^ permalink raw reply related
* [PATCH v28 0/5] Type2 device basic support
From: alejandro.lucero-palau @ 2026-06-18 18:18 UTC (permalink / raw)
To: linux-cxl, netdev, djbw, edward.cree, davem, kuba, pabeni,
edumazet, dave.jiang
Cc: Alejandro Lucero
From: Alejandro Lucero <alucerop@amd.com>
This series adds the last bits for allowing a CXL Type2 driver to obtain
a CXL region linked to the device HDM decoders committed by the BIOS,
with the driver being the sfc network driver.
Changes from v27:
- patch 1: make driver probe failing if error in efx_cxl_init (Dan)
- patch 4: add unmapping if error after efx_cxl_init (Dave)
- patch 4/5: move cxl_pio_initialised from patch 4 to patch 5 (Dave)
Tested in the cxl_for_7.3 branch.
Alejandro Lucero (5):
sfc: add cxl support
cxl/sfc: Map cxl regs
cxl/sfc: Initialize dpa without a mailbox
sfc: obtain and map cxl range using devm_cxl_probe_mem
sfc: support pio mapping based on cxl
drivers/cxl/core/core.h | 2 +
drivers/cxl/core/mbox.c | 51 +------------
drivers/cxl/core/memdev.c | 67 ++++++++++++++++
drivers/cxl/core/pci.c | 1 +
drivers/cxl/core/port.c | 1 +
drivers/cxl/core/regs.c | 1 +
drivers/cxl/cxlpci.h | 12 ---
drivers/cxl/pci.c | 1 +
drivers/net/ethernet/sfc/Kconfig | 9 +++
drivers/net/ethernet/sfc/Makefile | 1 +
drivers/net/ethernet/sfc/ef10.c | 41 ++++++++--
drivers/net/ethernet/sfc/efx.c | 18 ++++-
drivers/net/ethernet/sfc/efx.h | 1 -
drivers/net/ethernet/sfc/efx_cxl.c | 105 ++++++++++++++++++++++++++
drivers/net/ethernet/sfc/efx_cxl.h | 32 ++++++++
drivers/net/ethernet/sfc/net_driver.h | 10 +++
drivers/net/ethernet/sfc/nic.h | 3 +
include/cxl/cxl.h | 2 +
include/cxl/pci.h | 22 ++++++
19 files changed, 309 insertions(+), 71 deletions(-)
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.c
create mode 100644 drivers/net/ethernet/sfc/efx_cxl.h
create mode 100644 include/cxl/pci.h
base-commit: 9b1e70e8f9ec4b5c6ce7fa774a0023bb6894c686
--
2.34.1
^ permalink raw reply
* Re: [PATCH 1/1] xfrm: nat_keepalive: avoid double free on send error
From: Eyal Birger @ 2026-06-18 17:21 UTC (permalink / raw)
To: Ren Wei
Cc: netdev, steffen.klassert, herbert, davem, yuantan098, bird,
qianyuluo3
In-Reply-To: <46eb334399ce0e25e0897b42f21020541d159300.1781788385.git.qianyuluo3@gmail.com>
On Thu, Jun 18, 2026 at 9:36 AM Ren Wei <n05ec@lzu.edu.cn> wrote:
>
> From: Qianyu Luo <qianyuluo3@gmail.com>
>
> nat_keepalive_send() frees the keepalive skb whenever the IPv4 or IPv6
> send helper reports an error.
>
> That cleanup is only correct before the skb is handed to the output
> path. Once ip_build_and_send_pkt() or ip6_xmit() takes ownership, the
> networking stack may already have consumed the skb before returning an
> error, so freeing it again is unsafe.
>
> Handle the pre-handoff failure cases inside nat_keepalive_send_ipv4()
> and nat_keepalive_send_ipv6(), where the caller still owns the skb, and
> keep nat_keepalive_send() responsible only for family dispatch and the
> unsupported-family cleanup path.
Thanks for the fix!
>
> Fixes: f531d13bdfe3 ("xfrm: support sending NAT keepalives in ESP in UDP states")
> Cc: stable@vger.kernel.org
> Reported-by: Yuan Tan <yuantan098@gmail.com>
> Reported-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Qianyu Luo <qianyuluo3@gmail.com>
> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
> ---
> net/xfrm/xfrm_nat_keepalive.c | 15 +++++++++------
> 1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/net/xfrm/xfrm_nat_keepalive.c b/net/xfrm/xfrm_nat_keepalive.c
> index 458931062a04..f71328096f11 100644
> --- a/net/xfrm/xfrm_nat_keepalive.c
> +++ b/net/xfrm/xfrm_nat_keepalive.c
> @@ -55,8 +55,10 @@ static int nat_keepalive_send_ipv4(struct sk_buff *skb,
> ka->encap_sport, sock_net_uid(net, NULL));
>
> rt = ip_route_output_key(net, &fl4);
> - if (IS_ERR(rt))
> + if (IS_ERR(rt)) {
> + kfree_skb(skb);
> return PTR_ERR(rt);
> + }
>
> skb_dst_set(skb, &rt->dst);
>
> @@ -100,6 +102,7 @@ static int nat_keepalive_send_ipv6(struct sk_buff *skb,
> sock_net_set(sk, net);
> dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL);
> if (IS_ERR(dst)) {
> + kfree_skb(skb);
> local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
Any reason to do the kfree under lock?
Eyal
^ permalink raw reply
* [PATCH 10/10] RFC: rust: driver: support map-like syntax for ID table
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
The device ID table and its associated info is really just a map. Add a
syntax to `module_device_table` macro that reflects that.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/device_id.rs | 11 +++++++++++
samples/rust/rust_driver_pci.rs | 7 +++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 26618bcda276..7c61cdcc9427 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -183,6 +183,17 @@ macro_rules! module_device_table {
$table_type: literal, $device_id_ty: ty,
$table_name: ident, $id_info_type: ty,
[$(($id: expr, $info:expr $(,)?)),* $(,)?]
+ ) => {
+ $crate::module_device_table!(
+ $table_type, $device_id_ty, $table_name, $id_info_type,
+ {$($id=>$info,)*}
+ );
+ };
+
+ (
+ $table_type: literal, $device_id_ty: ty,
+ $table_name: ident, $id_info_type: ty,
+ {$($id: expr => $info:expr),* $(,)?}
) => {
#[export_name =
concat!("__mod_device_table__", line!(),
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 2282191e6292..652819dff082 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -75,10 +75,9 @@ struct SampleDriverData<'bound> {
kernel::pci_device_table!(
PCI_TABLE,
<SampleDriver as pci::Driver>::IdInfo,
- [(
- pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
- TestIndex::NO_EVENTFD
- )]
+ {
+ pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5) => TestIndex::NO_EVENTFD,
+ }
);
impl SampleDriverData<'_> {
--
2.54.0
^ permalink raw reply related
* [PATCH 09/10] rust: driver: remove duplicate ID table
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Previously, `IdArray` contains both device ID table and info table so we
keep a separate copy for MODULE_DEVICE_TABLE for hotplug (which needs to be
just the device ID table). With the info being changed to be carried via
pointers, `IdArray` is now layout compatible with raw ID table and hence
there is no longer a need to keep the distinction.
Deduplicate the code, and remove the redundant copy for hotplug purpose by
just giving the `IdArray` instance a proper symbol name.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/device_id.rs | 76 +++++++++++++++++-------------------------------
1 file changed, 27 insertions(+), 49 deletions(-)
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 59453588df0e..26618bcda276 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -86,28 +86,23 @@ unsafe fn info_unchecked_opt<U>(&self) -> Option<&'static U> {
}
}
-/// A zero-terminated device id array.
+/// A zero-terminated device id array, followed by context data.
#[repr(C)]
-pub struct RawIdArray<T: RawDeviceId, const N: usize> {
+pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
// This is `MaybeUninit<T::RawType>` so any bytes inside it can carry provenance in CTFE.
// If this were `T::RawType`, integer fields would not be able to contain pointers.
ids: [MaybeUninit<T::RawType>; N],
sentinel: MaybeUninit<T::RawType>,
+ phantom: PhantomData<&'static U>,
}
-impl<T: RawDeviceId, const N: usize> RawIdArray<T, N> {
- #[doc(hidden)]
- pub const fn size(&self) -> usize {
- core::mem::size_of::<Self>()
- }
-}
+// SAFETY: device ID is plain data plus a `&'static U` and can thus be sent between threads safely
+// if `&U` can.
+unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Send for IdArray<T, U, N> {}
-/// A zero-terminated device id array, followed by context data.
-#[repr(C)]
-pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
- raw_ids: RawIdArray<T, N>,
- phantom: PhantomData<&'static U>,
-}
+// SAFETY: device ID is plain data plus a `&'static U` and can thus be shared between threads safely
+// if `&U` can.
+unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Sync for IdArray<T, U, N> {}
impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U, N> {
/// Creates a new instance of the array.
@@ -137,22 +132,13 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U
core::mem::forget(ids);
Self {
- raw_ids: RawIdArray {
- ids: raw_ids,
- sentinel: MaybeUninit::zeroed(),
- },
+ ids: raw_ids,
+ sentinel: MaybeUninit::zeroed(),
phantom: PhantomData,
}
}
}
-impl<T: RawDeviceId, U: 'static, const N: usize> IdArray<T, U, N> {
- /// Reference to the contained [`RawIdArray`].
- pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
- &self.raw_ids
- }
-}
-
impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
/// Creates a new instance of the array without writing index values.
///
@@ -164,10 +150,8 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
core::mem::forget(ids);
Self {
- raw_ids: RawIdArray {
- ids: raw_ids,
- sentinel: MaybeUninit::zeroed(),
- },
+ ids: raw_ids,
+ sentinel: MaybeUninit::zeroed(),
phantom: PhantomData,
}
}
@@ -200,13 +184,17 @@ macro_rules! module_device_table {
$table_name: ident, $id_info_type: ty,
[$(($id: expr, $info:expr $(,)?)),* $(,)?]
) => {
- const $table_name: $crate::device_id::IdArray<
+ #[export_name =
+ concat!("__mod_device_table__", line!(),
+ "__kmod_", module_path!(),
+ "__", $table_type,
+ "__", stringify!($table_name))
+ ]
+ static $table_name: $crate::device_id::IdArray<
$device_id_ty,
$id_info_type,
{ <[$device_id_ty]>::len(&[$($id,)*]) },
> = $crate::device_id::IdArray::new([$(($id, &$info),)*]);
-
- $crate::module_device_table!($table_type, $table_name);
};
// Case for no ID info.
@@ -215,26 +203,16 @@ macro_rules! module_device_table {
$table_name: ident, @none,
[$($id: expr),* $(,)?]
) => {
- const $table_name: $crate::device_id::IdArray<
+ #[export_name =
+ concat!("__mod_device_table__", line!(),
+ "__kmod_", module_path!(),
+ "__", $table_type,
+ "__", stringify!($table_name))
+ ]
+ static $table_name: $crate::device_id::IdArray<
$device_id_ty,
(),
{ <[$device_id_ty]>::len(&[$($id,)*]) },
> = $crate::device_id::IdArray::new_without_index([$($id),*]);
-
- $crate::module_device_table!($table_type, $table_name);
- };
-
- ($table_type: literal, $table_name:ident) => {
- const _: () = {
- #[rustfmt::skip]
- #[export_name =
- concat!("__mod_device_table__", line!(),
- "__kmod_", module_path!(),
- "__", $table_type,
- "__", stringify!($table_name))
- ]
- static TABLE: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
- unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
- };
};
}
--
2.54.0
^ permalink raw reply related
* [PATCH 08/10] rust: driver: remove open-coded matching logic
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
With device ID info now including pointers instead of indices, the
open-coded ACPI/OF matching is no longer needed and can be replaced with
`device_get_match_data`.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/driver.rs | 114 ++++--------------------------------------------
rust/kernel/i2c.rs | 6 ++-
rust/kernel/platform.rs | 3 +-
3 files changed, 15 insertions(+), 108 deletions(-)
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index 824899d76fed..a881f5ef99ec 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -107,7 +107,6 @@
use crate::{
acpi,
device,
- device_id::RawDeviceIdIndex,
of,
prelude::*,
types::Opaque,
@@ -325,117 +324,22 @@ pub trait Adapter {
/// The [`acpi::IdTable`] of the corresponding driver
fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>>;
- /// Returns the driver's private data from the matching entry in the [`acpi::IdTable`], if any.
- ///
- /// If this returns `None`, it means there is no match with an entry in the [`acpi::IdTable`].
- fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
- #[cfg(not(CONFIG_ACPI))]
- {
- let _ = dev;
- None
- }
-
- #[cfg(CONFIG_ACPI)]
- {
- let table = Self::acpi_id_table()?;
-
- // SAFETY:
- // - `table` has static lifetime, hence it's valid for read,
- // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
- let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) };
-
- if raw_id.is_null() {
- None
- } else {
- // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct acpi_device_id`
- // and does not add additional invariants, so it's safe to transmute.
- let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
-
- // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
- Some(unsafe { id.info_unchecked::<Self::IdInfo>() })
- }
- }
- }
-
/// The [`of::IdTable`] of the corresponding driver.
fn of_id_table() -> Option<of::IdTable<Self::IdInfo>>;
- /// Returns the driver's private data from the matching entry in the [`of::IdTable`], if any.
- ///
- /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`].
- fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
- let table = Self::of_id_table()?;
-
- #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))]
- {
- let _ = (dev, table);
- }
-
- #[cfg(CONFIG_OF)]
- {
- // SAFETY:
- // - `table` has static lifetime, hence it's valid for read,
- // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
- let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) };
-
- if !raw_id.is_null() {
- // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id`
- // and does not add additional invariants, so it's safe to transmute.
- let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
-
- // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
- return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
- }
- }
-
- #[cfg(CONFIG_ACPI)]
- {
- use core::ptr;
- use device::property::FwNode;
-
- let mut raw_id = ptr::null();
-
- let fwnode = dev.fwnode().map_or(ptr::null_mut(), FwNode::as_raw);
-
- // SAFETY: `fwnode` is a pointer to a valid `fwnode_handle`. A null pointer will be
- // passed through the function.
- let adev = unsafe { bindings::to_acpi_device_node(fwnode) };
-
- // SAFETY:
- // - `adev` is a valid pointer to `acpi_device` or is null. It is guaranteed to be
- // valid as long as `dev` is alive.
- // - `table` has static lifetime, hence it's valid for read.
- if unsafe { acpi_of_match_device(adev, table.as_ptr(), &raw mut raw_id) } {
- // SAFETY:
- // - the function returns true, therefore `raw_id` has been set to a pointer to a
- // valid `of_device_id`.
- // - `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id`
- // and does not add additional invariants, so it's safe to transmute.
- let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
-
- // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
- return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
- }
- }
-
- None
- }
-
/// Returns the driver's private data from the matching entry of any of the ID tables, if any.
///
/// If this returns `None`, it means that there is no match in any of the ID tables directly
/// associated with a [`device::Device`].
- fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
- let id = Self::acpi_id_info(dev);
- if id.is_some() {
- return id;
- }
-
- let id = Self::of_id_info(dev);
- if id.is_some() {
- return id;
- }
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `dev` matched data is of type `Self::IdInfo`.
+ unsafe fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
+ // SAFETY: `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
+ let data = unsafe { bindings::device_get_match_data(dev.as_raw()) };
- None
+ // SAFETY: Per safety requirement, `data` is of type `Self::IdInfo`.
+ unsafe { data.cast::<Self::IdInfo>().as_ref() }
}
}
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 9e551c7e8e41..07680fd2f3fc 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -149,8 +149,10 @@ extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_
// INVARIANT: `idev` is valid for the duration of `probe_callback()`.
let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() };
- let info =
- Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref()));
+ let info = Self::i2c_id_info(idev).or_else(|| {
+ // SAFETY: `idev` matched data is of type `Self::IdInfo`.
+ unsafe { <Self as driver::Adapter>::id_info(idev.as_ref()) }
+ });
from_result(|| {
let data = T::probe(idev, info);
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 210a815925ce..e12e88113ca5 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -100,7 +100,8 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff
//
// INVARIANT: `pdev` is valid for the duration of `probe_callback()`.
let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() };
- let info = <Self as driver::Adapter>::id_info(pdev.as_ref());
+ // SAFETY: `pdev` matched data is of type `Self::IdInfo`.
+ let info = unsafe { <Self as driver::Adapter>::id_info(pdev.as_ref()) };
from_result(|| {
let data = T::probe(pdev, info);
--
2.54.0
^ permalink raw reply related
* [PATCH 07/10] rust: driver: store pointers in `DeviceId`
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
The common practice in C drivers is to store pointers into `driver_data`
field of device IDs. The Rust code is however currently storing indices
into the fields and then carry a side table that maps the index to
pointers.
It is much simpler to just have `DeviceId` carry the pointer like C code
does. However, just doing so naively would cause a "pointers cannot be cast
to integers during const eval" error, as kernel_ulong_t does not have
provenance while pointers do, and Rust forbids `expose_provenance` during
consteval.
Work around this limitation by wrapping raw IDs in `MaybeUninit`.
`MaybeUninit` is allowed to host arbitrary bytes with or without
provenance, so we can just then use `unsafe` to store a pointer with
provenance there. This has the same effect as changing the C-side
definition to use `void*` instead of `kernel_ulong_t`, but without actually
changing the C side.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/acpi.rs | 4 ---
rust/kernel/auxiliary.rs | 8 ++---
rust/kernel/device_id.rs | 88 +++++++++++++++++++++++++++++-------------------
rust/kernel/driver.rs | 14 ++++----
rust/kernel/i2c.rs | 7 ++--
rust/kernel/of.rs | 4 ---
rust/kernel/pci.rs | 11 +++---
rust/kernel/usb.rs | 7 ++--
8 files changed, 73 insertions(+), 70 deletions(-)
diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs
index 315f2f2af446..ea2ce61ee393 100644
--- a/rust/kernel/acpi.rs
+++ b/rust/kernel/acpi.rs
@@ -25,10 +25,6 @@ unsafe impl RawDeviceId for DeviceId {
// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data);
-
- fn index(&self) -> usize {
- self.0.driver_data
- }
}
impl DeviceId {
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 59787c9bff26..aa13d8866a19 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -93,7 +93,9 @@ extern "C" fn probe_callback(
// SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id`
// and does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*id.cast::<DeviceId>() };
- let info = T::ID_TABLE.info(id.index());
+
+ // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>`.
+ let info = unsafe { id.info_unchecked::<T::IdInfo>() };
from_result(|| {
let data = T::probe(adev, info);
@@ -169,10 +171,6 @@ unsafe impl RawDeviceId for DeviceId {
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize =
core::mem::offset_of!(bindings::auxiliary_device_id, driver_data);
-
- fn index(&self) -> usize {
- self.0.driver_data
- }
}
/// IdTable type for auxiliary drivers.
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 84852a2d9ad7..59453588df0e 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -5,7 +5,10 @@
//! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is
//! expected to implement [`RawDeviceId`].
-use core::mem::MaybeUninit;
+use core::{
+ marker::PhantomData,
+ mem::MaybeUninit, //
+};
/// Marker trait to indicate a Rust device ID type represents a corresponding C device ID type.
///
@@ -47,15 +50,48 @@ pub unsafe trait RawDeviceIdIndex: RawDeviceId {
/// The offset (in bytes) to the context/data field in the raw device ID.
const DRIVER_DATA_OFFSET: usize;
- /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceIdIndex`]
- /// trait.
- fn index(&self) -> usize;
+ /// Obtain the data pointer stored inside the device ID.
+ ///
+ /// # Safety
+ ///
+ /// `&Self` must be stored inside a `IdArray<Self, U>`.
+ unsafe fn info_unchecked<U>(&self) -> &'static U {
+ // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by
+ // the safety requirement of the function, this is stored in `IdArray<Self, U>` so is
+ // convertible to `&'static U`.
+ unsafe {
+ core::ptr::from_ref(self)
+ .byte_add(Self::DRIVER_DATA_OFFSET)
+ .cast::<&U>()
+ .read()
+ }
+ }
+
+ /// Obtain the data pointer stored inside the device ID.
+ ///
+ /// # Safety
+ ///
+ /// `&Self` must be stored inside a `IdArray<Self, U>`, or has NULL (or 0) as driver data.
+ unsafe fn info_unchecked_opt<U>(&self) -> Option<&'static U> {
+ // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by
+ // the safety requirement of the function, if this is stored in `IdArray<Self, U>`, this is
+ // convertible to `Option<&'static U>`. Otherwise it is NULL which is `None` as
+ // `Option<&U>`.
+ unsafe {
+ core::ptr::from_ref(self)
+ .byte_add(Self::DRIVER_DATA_OFFSET)
+ .cast::<Option<&U>>()
+ .read()
+ }
+ }
}
/// A zero-terminated device id array.
#[repr(C)]
pub struct RawIdArray<T: RawDeviceId, const N: usize> {
- ids: [T::RawType; N],
+ // This is `MaybeUninit<T::RawType>` so any bytes inside it can carry provenance in CTFE.
+ // If this were `T::RawType`, integer fields would not be able to contain pointers.
+ ids: [MaybeUninit<T::RawType>; N],
sentinel: MaybeUninit<T::RawType>,
}
@@ -68,18 +104,17 @@ pub const fn size(&self) -> usize {
/// A zero-terminated device id array, followed by context data.
#[repr(C)]
-pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
raw_ids: RawIdArray<T, N>,
- id_infos: [U; N],
+ phantom: PhantomData<&'static U>,
}
-impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U, N> {
/// Creates a new instance of the array.
///
/// The contents are derived from the given identifiers and context information.
- pub const fn new(ids: [(T, U); N]) -> Self {
+ pub const fn new(ids: [(T, &'static U); N]) -> Self {
let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N];
- let mut infos = [const { MaybeUninit::uninit() }; N];
let mut i = 0usize;
while i < N {
@@ -87,18 +122,15 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
// layout-wise compatible with `RawType`.
raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) };
// SAFETY: by the safety requirement of `RawDeviceIdIndex`, this would be effectively
- // `raw_ids[i].driver_data = i;`.
+ // `raw_ids[i].driver_data = ids[i].1;`.
unsafe {
raw_ids[i]
.as_mut_ptr()
.byte_add(T::DRIVER_DATA_OFFSET)
- .cast::<usize>()
- .write(i);
+ .cast::<&U>()
+ .write(ids[i].1);
}
- // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
- // later forget `ids`.
- infos[i] = MaybeUninit::new(unsafe { core::ptr::read(&ids[i].1) });
i += 1;
}
@@ -106,20 +138,15 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
Self {
raw_ids: RawIdArray {
- // SAFETY: this is effectively `array_assume_init`, which is unstable, so we use
- // `transmute_copy` instead. We have initialized all elements of `raw_ids` so this
- // `array_assume_init` is safe.
- ids: unsafe { core::mem::transmute_copy(&raw_ids) },
+ ids: raw_ids,
sentinel: MaybeUninit::zeroed(),
},
- // SAFETY: We have initialized all elements of `infos` so this `array_assume_init` is
- // safe.
- id_infos: unsafe { core::mem::transmute_copy(&infos) },
+ phantom: PhantomData,
}
}
}
-impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId, U: 'static, const N: usize> IdArray<T, U, N> {
/// Reference to the contained [`RawIdArray`].
pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
&self.raw_ids
@@ -133,7 +160,7 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
/// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
pub const fn new_without_index(ids: [T; N]) -> Self {
// SAFETY: `T` is layout-wise compatible with `T::RawType`, so is the array of them.
- let raw_ids: [T::RawType; N] = unsafe { core::mem::transmute_copy(&ids) };
+ let raw_ids: [MaybeUninit<T::RawType>; N] = unsafe { core::mem::transmute_copy(&ids) };
core::mem::forget(ids);
Self {
@@ -141,7 +168,7 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
ids: raw_ids,
sentinel: MaybeUninit::zeroed(),
},
- id_infos: [(); N],
+ phantom: PhantomData,
}
}
}
@@ -155,9 +182,6 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
pub trait IdTable<T: RawDeviceId, U> {
/// Obtain the pointer to the ID table.
fn as_ptr(&self) -> *const T::RawType;
-
- /// Obtain the pointer to the driver-specific information from an index.
- fn info(&self, index: usize) -> &U;
}
impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> {
@@ -166,10 +190,6 @@ fn as_ptr(&self) -> *const T::RawType {
// to access the sentinel.
core::ptr::from_ref(self).cast()
}
-
- fn info(&self, index: usize) -> &U {
- &self.id_infos[index]
- }
}
/// Create device table alias for modpost.
@@ -184,7 +204,7 @@ macro_rules! module_device_table {
$device_id_ty,
$id_info_type,
{ <[$device_id_ty]>::len(&[$($id,)*]) },
- > = $crate::device_id::IdArray::new([$(($id, $info),)*]);
+ > = $crate::device_id::IdArray::new([$(($id, &$info),)*]);
$crate::module_device_table!($table_type, $table_name);
};
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index bf5ba0d27553..824899d76fed 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -107,6 +107,7 @@
use crate::{
acpi,
device,
+ device_id::RawDeviceIdIndex,
of,
prelude::*,
types::Opaque,
@@ -350,7 +351,8 @@ fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
// and does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
- Some(table.info(<acpi::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id)))
+ // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+ Some(unsafe { id.info_unchecked::<Self::IdInfo>() })
}
}
}
@@ -381,9 +383,8 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
// and does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
- return Some(table.info(
- <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id),
- ));
+ // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+ return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
}
}
@@ -412,9 +413,8 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
// and does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
- return Some(table.info(
- <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id),
- ));
+ // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+ return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
}
}
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 55c89ba3a82a..9e551c7e8e41 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -65,10 +65,6 @@ unsafe impl RawDeviceId for DeviceId {
// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::i2c_device_id, driver_data);
-
- fn index(&self) -> usize {
- self.0.driver_data
- }
}
/// IdTable type for I2C
@@ -212,7 +208,8 @@ fn i2c_id_info(dev: &I2cClient) -> Option<&'static <Self as driver::Adapter>::Id
// does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*raw_id.cast::<DeviceId>() };
- Some(table.info(<DeviceId as RawDeviceIdIndex>::index(id)))
+ // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+ Some(unsafe { id.info_unchecked::<T::IdInfo>() })
}
}
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 35aa6d36d309..d0318f62afd7 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -25,10 +25,6 @@ unsafe impl RawDeviceId for DeviceId {
// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `data` field.
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data);
-
- fn index(&self) -> usize {
- self.0.data as usize
- }
}
impl DeviceId {
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index a3dd48f76353..a630c7fc6a85 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -110,10 +110,13 @@ extern "C" fn probe_callback(
// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and
// does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*id.cast::<DeviceId>() };
- let info = T::ID_TABLE.info(id.index());
+
+ // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>` or
+ // `pci_device_id_any` which has 0 as driver_data.
+ let info = unsafe { id.info_unchecked_opt::<T::IdInfo>() };
from_result(|| {
- let data = T::probe(pdev, Some(info));
+ let data = T::probe(pdev, info);
pdev.as_ref().set_drvdata(data)?;
Ok(0)
@@ -233,10 +236,6 @@ unsafe impl RawDeviceId for DeviceId {
// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data);
-
- fn index(&self) -> usize {
- self.0.driver_data
- }
}
/// `IdTable` type for PCI.
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 500b5e0ba4ea..8aeff5011755 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -89,7 +89,8 @@ extern "C" fn probe_callback(
// does not add additional invariants, so it's safe to transmute.
let id = unsafe { &*id.cast::<DeviceId>() };
- let info = T::ID_TABLE.info(id.index());
+ // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>`.
+ let info = unsafe { id.info_unchecked::<T::IdInfo>() };
let data = T::probe(intf, id, info);
let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref();
@@ -242,10 +243,6 @@ unsafe impl RawDeviceId for DeviceId {
// SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_info` field.
unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::usb_device_id, driver_info);
-
- fn index(&self) -> usize {
- self.0.driver_info
- }
}
/// [`IdTable`](kernel::device_id::IdTable) type for USB.
--
2.54.0
^ permalink raw reply related
* [PATCH 06/10] rust: driver: remove `$module_table_name` from `module_device_table`
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Wrap the generated code in a `const _: ()` block to avoid symbol conflict.
This removes the need of creating a new identifier.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/cpufreq/rcpufreq_dt.rs | 1 -
drivers/gpu/drm/nova/driver.rs | 1 -
drivers/gpu/drm/tyr/driver.rs | 1 -
drivers/gpu/nova-core/driver.rs | 1 -
drivers/pwm/pwm_th1520.rs | 1 -
rust/kernel/device_id.rs | 30 ++++++++++++++++--------------
rust/kernel/i2c.rs | 3 ---
rust/kernel/net/phy.rs | 2 +-
rust/kernel/pci.rs | 1 -
rust/kernel/platform.rs | 2 --
rust/kernel/usb.rs | 1 -
samples/rust/rust_debugfs.rs | 1 -
samples/rust/rust_dma.rs | 1 -
samples/rust/rust_driver_auxiliary.rs | 2 --
samples/rust/rust_driver_i2c.rs | 3 ---
samples/rust/rust_driver_pci.rs | 1 -
samples/rust/rust_driver_platform.rs | 2 --
samples/rust/rust_driver_usb.rs | 1 -
samples/rust/rust_i2c_client.rs | 2 --
samples/rust/rust_soc.rs | 2 --
20 files changed, 17 insertions(+), 42 deletions(-)
diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
index 10106fa13095..145daa12072f 100644
--- a/drivers/cpufreq/rcpufreq_dt.rs
+++ b/drivers/cpufreq/rcpufreq_dt.rs
@@ -194,7 +194,6 @@ fn register_em(policy: &mut cpufreq::Policy) {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<CPUFreqDTDriver as platform::Driver>::IdInfo,
[(of::DeviceId::new(c"operating-points-v2"), ())]
);
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 48933d86ddda..43f15cdfeb09 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -43,7 +43,6 @@ pub(crate) struct NovaData {
kernel::auxiliary_device_table!(
AUX_TABLE,
- MODULE_AUX_TABLE,
<NovaDriver as auxiliary::Driver>::IdInfo,
[(
auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME),
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index d063bc664cc1..218e9af899c7 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -87,7 +87,6 @@ fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<TyrPlatformDriver as platform::Driver>::IdInfo,
[
(of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5a5f0b63e0f3..0c53b7239ac9 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -40,7 +40,6 @@ pub(crate) struct NovaCore<'bound> {
kernel::pci_device_table!(
PCI_TABLE,
- MODULE_PCI_TABLE,
<NovaCoreDriver as pci::Driver>::IdInfo,
[
// Modern NVIDIA GPUs will show up as either VGA or 3D controllers.
diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index 3e3fa51ccef9..1df752330e8f 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -303,7 +303,6 @@ fn drop(self: Pin<&mut Self>) {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<Th1520PwmPlatformDriver as platform::Driver>::IdInfo,
[(of::DeviceId::new(c"thead,th1520-pwm"), ())]
);
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 0239f89d5f69..84852a2d9ad7 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -177,7 +177,7 @@ fn info(&self, index: usize) -> &U {
macro_rules! module_device_table {
(
$table_type: literal, $device_id_ty: ty,
- $table_name: ident, $module_table_name: ident, $id_info_type: ty,
+ $table_name: ident, $id_info_type: ty,
[$(($id: expr, $info:expr $(,)?)),* $(,)?]
) => {
const $table_name: $crate::device_id::IdArray<
@@ -186,13 +186,13 @@ macro_rules! module_device_table {
{ <[$device_id_ty]>::len(&[$($id,)*]) },
> = $crate::device_id::IdArray::new([$(($id, $info),)*]);
- $crate::module_device_table!($table_type, $module_table_name, $table_name);
+ $crate::module_device_table!($table_type, $table_name);
};
// Case for no ID info.
(
$table_type: literal, $device_id_ty: ty,
- $table_name: ident, $module_table_name: ident, @none,
+ $table_name: ident, @none,
[$($id: expr),* $(,)?]
) => {
const $table_name: $crate::device_id::IdArray<
@@ -201,18 +201,20 @@ macro_rules! module_device_table {
{ <[$device_id_ty]>::len(&[$($id,)*]) },
> = $crate::device_id::IdArray::new_without_index([$($id),*]);
- $crate::module_device_table!($table_type, $module_table_name, $table_name);
+ $crate::module_device_table!($table_type, $table_name);
};
- ($table_type: literal, $module_table_name: ident, $table_name:ident) => {
- #[rustfmt::skip]
- #[export_name =
- concat!("__mod_device_table__", line!(),
- "__kmod_", module_path!(),
- "__", $table_type,
- "__", stringify!($table_name))
- ]
- static $module_table_name: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
- unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
+ ($table_type: literal, $table_name:ident) => {
+ const _: () = {
+ #[rustfmt::skip]
+ #[export_name =
+ concat!("__mod_device_table__", line!(),
+ "__kmod_", module_path!(),
+ "__", $table_type,
+ "__", stringify!($table_name))
+ ]
+ static TABLE: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
+ unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
+ };
};
}
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index a7d9b88ae616..55c89ba3a82a 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -261,7 +261,6 @@ macro_rules! module_i2c_driver {
///
/// kernel::acpi_device_table!(
/// ACPI_TABLE,
-/// MODULE_ACPI_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
/// (acpi::DeviceId::new(c"LNUXBEEF"), ())
@@ -270,7 +269,6 @@ macro_rules! module_i2c_driver {
///
/// kernel::i2c_device_table!(
/// I2C_TABLE,
-/// MODULE_I2C_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
/// (i2c::DeviceId::new(c"rust_driver_i2c"), ())
@@ -279,7 +277,6 @@ macro_rules! module_i2c_driver {
///
/// kernel::of_device_table!(
/// OF_TABLE,
-/// MODULE_OF_TABLE,
/// <MyDriver as i2c::Driver>::IdInfo,
/// [
/// (of::DeviceId::new(c"test,device"), ())
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 166572861e61..1e86b901c391 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -811,7 +811,7 @@ macro_rules! module_phy_driver {
(@device_table [$($dev:expr),+]) => {
$crate::module_device_table!(
"mdio", $crate::net::phy::DeviceId,
- phydev, TABLE, @none, [$($dev),+]
+ TABLE, @none, [$($dev),+]
);
};
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 34e07a53244d..a3dd48f76353 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -261,7 +261,6 @@ macro_rules! pci_device_table {
///
/// kernel::pci_device_table!(
/// PCI_TABLE,
-/// MODULE_PCI_TABLE,
/// <MyDriver as pci::Driver>::IdInfo,
/// [
/// (
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 9b362e0495d3..210a815925ce 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -176,7 +176,6 @@ macro_rules! module_platform_driver {
///
/// kernel::of_device_table!(
/// OF_TABLE,
-/// MODULE_OF_TABLE,
/// <MyDriver as platform::Driver>::IdInfo,
/// [
/// (of::DeviceId::new(c"test,device"), ())
@@ -185,7 +184,6 @@ macro_rules! module_platform_driver {
///
/// kernel::acpi_device_table!(
/// ACPI_TABLE,
-/// MODULE_ACPI_TABLE,
/// <MyDriver as platform::Driver>::IdInfo,
/// [
/// (acpi::DeviceId::new(c"LNUXBEEF"), ())
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 154919ee1e19..500b5e0ba4ea 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -271,7 +271,6 @@ macro_rules! usb_device_table {
///
/// kernel::usb_device_table!(
/// USB_TABLE,
-/// MODULE_USB_TABLE,
/// <MyDriver as usb::Driver>::IdInfo,
/// [
/// (usb::DeviceId::from_id(0x1234, 0x5678), ()),
diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
index 1f59e08aaa4b..181fd98ae5b6 100644
--- a/samples/rust/rust_debugfs.rs
+++ b/samples/rust/rust_debugfs.rs
@@ -110,7 +110,6 @@ fn from_str(s: &str) -> Result<Self> {
kernel::acpi_device_table!(
ACPI_TABLE,
- MODULE_ACPI_TABLE,
<RustDebugFs as platform::Driver>::IdInfo,
[(acpi::DeviceId::new(c"LNUXBEEF"), ())]
);
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 9beb37275e0d..80c309ce07e9 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -51,7 +51,6 @@ unsafe impl kernel::transmute::FromBytes for MyStruct {}
kernel::pci_device_table!(
PCI_TABLE,
- MODULE_PCI_TABLE,
<DmaSampleDriver as pci::Driver>::IdInfo,
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 73c63afc046a..704567a072ba 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -24,7 +24,6 @@
kernel::auxiliary_device_table!(
AUX_TABLE,
- MODULE_AUX_TABLE,
<AuxiliaryDriver as auxiliary::Driver>::IdInfo,
[(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())]
);
@@ -66,7 +65,6 @@ struct ParentData<'bound> {
kernel::pci_device_table!(
PCI_TABLE,
- MODULE_PCI_TABLE,
<ParentDriver as pci::Driver>::IdInfo,
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs
index ead8263a7d48..a0df0c6097c4 100644
--- a/samples/rust/rust_driver_i2c.rs
+++ b/samples/rust/rust_driver_i2c.rs
@@ -14,21 +14,18 @@
kernel::acpi_device_table! {
ACPI_TABLE,
- MODULE_ACPI_TABLE,
<SampleDriver as i2c::Driver>::IdInfo,
[(acpi::DeviceId::new(c"LNUXBEEF"), 0)]
}
kernel::i2c_device_table! {
I2C_TABLE,
- MODULE_I2C_TABLE,
<SampleDriver as i2c::Driver>::IdInfo,
[(i2c::DeviceId::new(c"rust_driver_i2c"), 0)]
}
kernel::of_device_table! {
OF_TABLE,
- MODULE_OF_TABLE,
<SampleDriver as i2c::Driver>::IdInfo,
[(of::DeviceId::new(c"test,rust_driver_i2c"), 0)]
}
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 5547dd704a1b..2282191e6292 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -74,7 +74,6 @@ struct SampleDriverData<'bound> {
kernel::pci_device_table!(
PCI_TABLE,
- MODULE_PCI_TABLE,
<SampleDriver as pci::Driver>::IdInfo,
[(
pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index ec0d6cac4f57..710145b3605a 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -87,14 +87,12 @@ struct SampleDriver {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<SampleDriver as platform::Driver>::IdInfo,
[(of::DeviceId::new(c"test,rust-device"), Info(42))]
);
kernel::acpi_device_table!(
ACPI_TABLE,
- MODULE_ACPI_TABLE,
<SampleDriver as platform::Driver>::IdInfo,
[(acpi::DeviceId::new(c"LNUXBEEF"), Info(0))]
);
diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs
index 02bd5085f9bc..284042c5969b 100644
--- a/samples/rust/rust_driver_usb.rs
+++ b/samples/rust/rust_driver_usb.rs
@@ -19,7 +19,6 @@ struct SampleDriver {
kernel::usb_device_table!(
USB_TABLE,
- MODULE_USB_TABLE,
<SampleDriver as usb::Driver>::IdInfo,
[(usb::DeviceId::from_id(0x1234, 0x5678), ()),]
);
diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs
index 2d876f4e3ee0..c8a23875ef5b 100644
--- a/samples/rust/rust_i2c_client.rs
+++ b/samples/rust/rust_i2c_client.rs
@@ -87,14 +87,12 @@ struct SampleDriver {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<SampleDriver as platform::Driver>::IdInfo,
[(of::DeviceId::new(c"test,rust-device"), ())]
);
kernel::acpi_device_table!(
ACPI_TABLE,
- MODULE_ACPI_TABLE,
<SampleDriver as platform::Driver>::IdInfo,
[(acpi::DeviceId::new(c"LNUXBEEF"), ())]
);
diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs
index 808d58200eb6..f5e5f2f9adf7 100644
--- a/samples/rust/rust_soc.rs
+++ b/samples/rust/rust_soc.rs
@@ -23,14 +23,12 @@ struct SampleSocDriver {
kernel::of_device_table!(
OF_TABLE,
- MODULE_OF_TABLE,
<SampleSocDriver as platform::Driver>::IdInfo,
[(of::DeviceId::new(c"test,rust-device"), ())]
);
kernel::acpi_device_table!(
ACPI_TABLE,
- MODULE_ACPI_TABLE,
<SampleSocDriver as platform::Driver>::IdInfo,
[(acpi::DeviceId::new(c"LNUXBEEF"), ())]
);
--
2.54.0
^ permalink raw reply related
* [PATCH 05/10] rust: driver: centralize device ID handling
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Move the `IdArray` creation from individual buses to be handled by shared
code in `device_id.rs`.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/acpi.rs | 10 ++--------
rust/kernel/auxiliary.rs | 10 ++--------
rust/kernel/device_id.rs | 31 ++++++++++++++++++++++++++++++-
rust/kernel/i2c.rs | 10 ++--------
rust/kernel/net/phy.rs | 10 ++++------
rust/kernel/of.rs | 10 ++--------
rust/kernel/pci.rs | 10 ++--------
rust/kernel/usb.rs | 10 ++--------
8 files changed, 46 insertions(+), 55 deletions(-)
diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs
index 9b8efa623130..315f2f2af446 100644
--- a/rust/kernel/acpi.rs
+++ b/rust/kernel/acpi.rs
@@ -53,13 +53,7 @@ pub const fn new(id: &'static CStr) -> Self {
/// Create an ACPI `IdTable` with an "alias" for modpost.
#[macro_export]
macro_rules! acpi_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::acpi::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("acpi", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("acpi", $crate::acpi::DeviceId, $($tt)*);
};
}
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index c42928d5a239..59787c9bff26 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -181,14 +181,8 @@ fn index(&self) -> usize {
/// Create a auxiliary `IdTable` with its alias for modpost.
#[macro_export]
macro_rules! auxiliary_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::auxiliary::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("auxiliary", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("auxiliary", $crate::auxiliary::DeviceId, $($tt)*);
};
}
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index eeef3f5e7b63..0239f89d5f69 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -175,7 +175,36 @@ fn info(&self, index: usize) -> &U {
/// Create device table alias for modpost.
#[macro_export]
macro_rules! module_device_table {
- ($table_type: literal, $module_table_name:ident, $table_name:ident) => {
+ (
+ $table_type: literal, $device_id_ty: ty,
+ $table_name: ident, $module_table_name: ident, $id_info_type: ty,
+ [$(($id: expr, $info:expr $(,)?)),* $(,)?]
+ ) => {
+ const $table_name: $crate::device_id::IdArray<
+ $device_id_ty,
+ $id_info_type,
+ { <[$device_id_ty]>::len(&[$($id,)*]) },
+ > = $crate::device_id::IdArray::new([$(($id, $info),)*]);
+
+ $crate::module_device_table!($table_type, $module_table_name, $table_name);
+ };
+
+ // Case for no ID info.
+ (
+ $table_type: literal, $device_id_ty: ty,
+ $table_name: ident, $module_table_name: ident, @none,
+ [$($id: expr),* $(,)?]
+ ) => {
+ const $table_name: $crate::device_id::IdArray<
+ $device_id_ty,
+ (),
+ { <[$device_id_ty]>::len(&[$($id,)*]) },
+ > = $crate::device_id::IdArray::new_without_index([$($id),*]);
+
+ $crate::module_device_table!($table_type, $module_table_name, $table_name);
+ };
+
+ ($table_type: literal, $module_table_name: ident, $table_name:ident) => {
#[rustfmt::skip]
#[export_name =
concat!("__mod_device_table__", line!(),
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 7655d61daac8..a7d9b88ae616 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -77,14 +77,8 @@ fn index(&self) -> usize {
/// Create a I2C `IdTable` with its alias for modpost.
#[macro_export]
macro_rules! i2c_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::i2c::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("i2c", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("i2c", $crate::i2c::DeviceId, $($tt)*);
};
}
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 965ecca7d55f..166572861e61 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -809,12 +809,10 @@ macro_rules! module_phy_driver {
};
(@device_table [$($dev:expr),+]) => {
- const N: usize = $crate::module_phy_driver!(@count_devices $($dev),+);
-
- const TABLE: $crate::device_id::IdArray<$crate::net::phy::DeviceId, (), N> =
- $crate::device_id::IdArray::new_without_index([ $($dev),+, ]);
-
- $crate::module_device_table!("mdio", phydev, TABLE);
+ $crate::module_device_table!(
+ "mdio", $crate::net::phy::DeviceId,
+ phydev, TABLE, @none, [$($dev),+]
+ );
};
(drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 58b20c367f99..35aa6d36d309 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -53,13 +53,7 @@ pub const fn new(compatible: &'static CStr) -> Self {
/// Create an OF `IdTable` with an "alias" for modpost.
#[macro_export]
macro_rules! of_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::of::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("of", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("of", $crate::of::DeviceId, $($tt)*);
};
}
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 0e055e4df99e..34e07a53244d 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -245,14 +245,8 @@ fn index(&self) -> usize {
/// Create a PCI `IdTable` with its alias for modpost.
#[macro_export]
macro_rules! pci_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::pci::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("pci", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("pci", $crate::pci::DeviceId, $($tt)*);
};
}
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 7aff0c82d0af..154919ee1e19 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -254,14 +254,8 @@ fn index(&self) -> usize {
/// Create a USB `IdTable` with its alias for modpost.
#[macro_export]
macro_rules! usb_device_table {
- ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
- const $table_name: $crate::device_id::IdArray<
- $crate::usb::DeviceId,
- $id_info_type,
- { $table_data.len() },
- > = $crate::device_id::IdArray::new($table_data);
-
- $crate::module_device_table!("usb", $module_table_name, $table_name);
+ ($($tt:tt)*) => {
+ $crate::module_device_table!("usb", $crate::usb::DeviceId, $($tt)*);
};
}
--
2.54.0
^ permalink raw reply related
* [PATCH 04/10] rust: net/phy: remove expansion from doc
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
The expansion serves little purpose and it can easily diverge.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/net/phy.rs | 56 --------------------------------------------------
1 file changed, 56 deletions(-)
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 2868e3a9e02c..965ecca7d55f 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -800,62 +800,6 @@ const fn as_int(&self) -> u32 {
/// }
/// # }
/// ```
-///
-/// This expands to the following code:
-///
-/// ```ignore
-/// use kernel::net::phy::{self, DeviceId};
-/// use kernel::prelude::*;
-///
-/// struct Module {
-/// _reg: ::kernel::net::phy::Registration,
-/// }
-///
-/// module! {
-/// type: Module,
-/// name: "rust_sample_phy",
-/// authors: ["Rust for Linux Contributors"],
-/// description: "Rust sample PHYs driver",
-/// license: "GPL",
-/// }
-///
-/// struct PhySample;
-///
-/// #[vtable]
-/// impl phy::Driver for PhySample {
-/// const NAME: &'static CStr = c"PhySample";
-/// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
-/// }
-///
-/// const _: () = {
-/// static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =
-/// [::kernel::net::phy::create_phy_driver::<PhySample>()];
-///
-/// impl ::kernel::Module for Module {
-/// fn init(module: &'static ::kernel::ThisModule) -> Result<Self> {
-/// let drivers = unsafe { &mut DRIVERS };
-/// let mut reg = ::kernel::net::phy::Registration::register(
-/// module,
-/// ::core::pin::Pin::static_mut(drivers),
-/// )?;
-/// Ok(Module { _reg: reg })
-/// }
-/// }
-/// };
-///
-/// const N: usize = 1;
-///
-/// const TABLE: ::kernel::device_id::IdArray<::kernel::net::phy::DeviceId, (), N> =
-/// ::kernel::device_id::IdArray::new_without_index([
-/// ::kernel::net::phy::DeviceId(
-/// ::kernel::bindings::mdio_device_id {
-/// phy_id: 0x00000001,
-/// phy_id_mask: 0xffffffff,
-/// }),
-/// ]);
-///
-/// ::kernel::module_device_table!("mdio", phydev, TABLE);
-/// ```
#[macro_export]
macro_rules! module_phy_driver {
(@replace_expr $_t:tt $sub:expr) => {$sub};
--
2.54.0
^ permalink raw reply related
* [PATCH 03/10] rust: pci: use `Option<&IdInfo>` for device ID info
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
It is possible that `pci_device_id_any` will be passed to the driver, e.g.
`driver_override` is used on the device. Therefore, the driver must be able
to handle the case where `driver_data` is 0. Thus, update the `probe`
functions to get `Option`.
The current code cannot tell if the info does not exist or is the first
entry; however this will be achievable once the code is updated to use a
`&'static IdInfo` pointer instead of indices.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
drivers/gpu/nova-core/driver.rs | 2 +-
rust/kernel/pci.rs | 6 +++---
samples/rust/rust_dma.rs | 2 +-
samples/rust/rust_driver_auxiliary.rs | 2 +-
samples/rust/rust_driver_pci.rs | 3 ++-
5 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5738d4ac521b..5a5f0b63e0f3 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -70,7 +70,7 @@ impl pci::Driver for NovaCoreDriver {
fn probe<'bound>(
pdev: &'bound pci::Device<Core<'_>>,
- _info: &'bound Self::IdInfo,
+ _info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
pin_init::pin_init_scope(move || {
dev_dbg!(pdev, "Probe Nova Core GPU driver.\n");
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 5071cae6543f..0e055e4df99e 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -113,7 +113,7 @@ extern "C" fn probe_callback(
let info = T::ID_TABLE.info(id.index());
from_result(|| {
- let data = T::probe(pdev, info);
+ let data = T::probe(pdev, Some(info));
pdev.as_ref().set_drvdata(data)?;
Ok(0)
@@ -284,7 +284,7 @@ macro_rules! pci_device_table {
///
/// fn probe<'bound>(
/// _pdev: &'bound pci::Device<Core<'_>>,
-/// _id_info: &'bound Self::IdInfo,
+/// _id_info: Option<&'bound Self::IdInfo>,
/// ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
/// Err(ENODEV)
/// }
@@ -313,7 +313,7 @@ pub trait Driver {
/// attempt to initialize the device here.
fn probe<'bound>(
dev: &'bound Device<device::Core<'_>>,
- id_info: &'bound Self::IdInfo,
+ id_info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
/// PCI driver unbind.
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 5046b4628d0e..9beb37275e0d 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -63,7 +63,7 @@ impl pci::Driver for DmaSampleDriver {
fn probe<'bound>(
pdev: &'bound pci::Device<Core<'_>>,
- _info: &'bound Self::IdInfo,
+ _info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self, Error> + 'bound {
pin_init::pin_init_scope(move || {
dev_info!(pdev, "Probe DMA test driver.\n");
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 2c1351040e45..73c63afc046a 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -79,7 +79,7 @@ impl pci::Driver for ParentDriver {
fn probe<'bound>(
pdev: &'bound pci::Device<Core<'_>>,
- _info: &'bound Self::IdInfo,
+ _info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
Ok(ParentData {
// SAFETY: `ParentData` is the driver's private data, which is dropped when the
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 1aa8197d8698..5547dd704a1b 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -144,7 +144,7 @@ impl pci::Driver for SampleDriver {
fn probe<'bound>(
pdev: &'bound pci::Device<Core<'_>>,
- info: &'bound Self::IdInfo,
+ info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
let vendor = pdev.vendor_id();
dev_dbg!(
@@ -153,6 +153,7 @@ fn probe<'bound>(
vendor,
pdev.device_id()
);
+ let info = info.ok_or(ENODEV)?;
pdev.enable_device_mem()?;
pdev.set_master();
--
2.54.0
^ permalink raw reply related
* [PATCH 01/10] rust: driver: remove `IdTable::id`
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
This is unused.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/device_id.rs | 7 -------
1 file changed, 7 deletions(-)
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 8e9721446014..fbf6d8e6afb9 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -166,9 +166,6 @@ pub trait IdTable<T: RawDeviceId, U> {
/// Obtain the pointer to the ID table.
fn as_ptr(&self) -> *const T::RawType;
- /// Obtain the pointer to the bus specific device ID from an index.
- fn id(&self, index: usize) -> &T::RawType;
-
/// Obtain the pointer to the driver-specific information from an index.
fn info(&self, index: usize) -> &U;
}
@@ -180,10 +177,6 @@ fn as_ptr(&self) -> *const T::RawType {
core::ptr::from_ref(self).cast()
}
- fn id(&self, index: usize) -> &T::RawType {
- &self.raw_ids.ids[index]
- }
-
fn info(&self, index: usize) -> &U {
&self.id_infos[index]
}
--
2.54.0
^ permalink raw reply related
* [PATCH 02/10] rust: driver: simplify `IdArray::new_without_index`
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
This method can very easily construct the `IdArray` on its own without
delegating to `Self::build`. Doing so also simplifies the phy device table
macro because it does not need to construct tuples anymore.
This also allows simplification of `new` and `build` which removes the
`unsafe`.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/device_id.rs | 64 ++++++++++++++++++++----------------------------
rust/kernel/net/phy.rs | 2 +-
2 files changed, 28 insertions(+), 38 deletions(-)
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index fbf6d8e6afb9..eeef3f5e7b63 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -73,19 +73,11 @@ pub struct IdArray<T: RawDeviceId, U, const N: usize> {
id_infos: [U; N],
}
-impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
/// Creates a new instance of the array.
///
/// The contents are derived from the given identifiers and context information.
- ///
- /// # Safety
- ///
- /// `data_offset` as `None` is always safe.
- /// If `data_offset` is `Some(data_offset)`, then:
- /// - `data_offset` must be the correct offset (in bytes) to the context/data field
- /// (e.g., the `driver_data` field) within the raw device ID structure.
- /// - The field at `data_offset` must be correctly sized to hold a `usize`.
- const unsafe fn build(ids: [(T, U); N], data_offset: Option<usize>) -> Self {
+ pub const fn new(ids: [(T, U); N]) -> Self {
let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N];
let mut infos = [const { MaybeUninit::uninit() }; N];
@@ -94,16 +86,14 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
// SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is
// layout-wise compatible with `RawType`.
raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) };
- if let Some(data_offset) = data_offset {
- // SAFETY: by the safety requirement of this function, this would be effectively
- // `raw_ids[i].driver_data = i;`.
- unsafe {
- raw_ids[i]
- .as_mut_ptr()
- .byte_add(data_offset)
- .cast::<usize>()
- .write(i);
- }
+ // SAFETY: by the safety requirement of `RawDeviceIdIndex`, this would be effectively
+ // `raw_ids[i].driver_data = i;`.
+ unsafe {
+ raw_ids[i]
+ .as_mut_ptr()
+ .byte_add(T::DRIVER_DATA_OFFSET)
+ .cast::<usize>()
+ .write(i);
}
// SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
@@ -127,32 +117,32 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
id_infos: unsafe { core::mem::transmute_copy(&infos) },
}
}
+}
- /// Creates a new instance of the array without writing index values.
- ///
- /// The contents are derived from the given identifiers and context information.
- /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
- pub const fn new_without_index(ids: [(T, U); N]) -> Self {
- // SAFETY: Calling `Self::build` with `offset = None` is always safe,
- // because no raw memory writes are performed in this case.
- unsafe { Self::build(ids, None) }
- }
-
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
/// Reference to the contained [`RawIdArray`].
pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
&self.raw_ids
}
}
-impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
- /// Creates a new instance of the array.
+impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
+ /// Creates a new instance of the array without writing index values.
///
/// The contents are derived from the given identifiers and context information.
- pub const fn new(ids: [(T, U); N]) -> Self {
- // SAFETY: by the safety requirement of `RawDeviceIdIndex`,
- // `T::DRIVER_DATA_OFFSET` is guaranteed to be the correct offset (in bytes) to
- // a field within `T::RawType`.
- unsafe { Self::build(ids, Some(T::DRIVER_DATA_OFFSET)) }
+ /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
+ pub const fn new_without_index(ids: [T; N]) -> Self {
+ // SAFETY: `T` is layout-wise compatible with `T::RawType`, so is the array of them.
+ let raw_ids: [T::RawType; N] = unsafe { core::mem::transmute_copy(&ids) };
+ core::mem::forget(ids);
+
+ Self {
+ raw_ids: RawIdArray {
+ ids: raw_ids,
+ sentinel: MaybeUninit::zeroed(),
+ },
+ id_infos: [(); N],
+ }
}
}
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 3ca99db5cccf..2868e3a9e02c 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -868,7 +868,7 @@ macro_rules! module_phy_driver {
const N: usize = $crate::module_phy_driver!(@count_devices $($dev),+);
const TABLE: $crate::device_id::IdArray<$crate::net::phy::DeviceId, (), N> =
- $crate::device_id::IdArray::new_without_index([ $(($dev,())),+, ]);
+ $crate::device_id::IdArray::new_without_index([ $($dev),+, ]);
$crate::module_device_table!("mdio", phydev, TABLE);
};
--
2.54.0
^ permalink raw reply related
* [PATCH 00/10] rust: driver: use pointers instead of indices for ID info
From: Gary Guo @ 2026-06-18 17:03 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Miguel Ojeda, Boqun Feng, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Daniel Almeida,
Tamir Duberstein, Alexandre Courbot, Onur Özkan,
FUJITA Tomonori, David Airlie, Simona Vetter, Bjorn Helgaas,
Krzysztof Wilczyński, Abdiel Janulgue, Robin Murphy,
Dave Ertman, Ira Weiny, Leon Romanovsky, Len Brown, Igor Korotin,
Rob Herring, Saravana Kannan, Viresh Kumar, Michal Wilczynski,
Drew Fustini, Guo Ren, Fu Wei, Uwe Kleine-König
Cc: driver-core, rust-for-linux, linux-kernel, netdev, nova-gpu,
dri-devel, linux-pci, linux-acpi, devicetree, linux-pm,
linux-riscv, linux-pwm, Gary Guo
Most C drivers use a pointer (and cast to kernel_ulong_t) for driver_data
fields in device_id. Rust code currently does not do this, but rather use
indices. These indices then needs to be translated to `&IdInfo` separately
and this is by a side table.
This leads to open-coded ACPI/OF handling in driver.rs, which is not
desirable. Convert the code to use pointers (or rather, static references)
instead.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
Gary Guo (10):
rust: driver: remove `IdTable::id`
rust: driver: simplify `IdArray::new_without_index`
rust: pci: use `Option<&IdInfo>` for device ID info
rust: net/phy: remove expansion from doc
rust: driver: centralize device ID handling
rust: driver: remove `$module_table_name` from `module_device_table`
rust: driver: store pointers in `DeviceId`
rust: driver: remove open-coded matching logic
rust: driver: remove duplicate ID table
RFC: rust: driver: support map-like syntax for ID table
drivers/cpufreq/rcpufreq_dt.rs | 1 -
drivers/gpu/drm/nova/driver.rs | 1 -
drivers/gpu/drm/tyr/driver.rs | 1 -
drivers/gpu/nova-core/driver.rs | 3 +-
drivers/pwm/pwm_th1520.rs | 1 -
rust/kernel/acpi.rs | 14 +--
rust/kernel/auxiliary.rs | 18 +--
rust/kernel/device_id.rs | 205 +++++++++++++++++++---------------
rust/kernel/driver.rs | 114 ++-----------------
rust/kernel/i2c.rs | 26 ++---
rust/kernel/net/phy.rs | 66 +----------
rust/kernel/of.rs | 14 +--
rust/kernel/pci.rs | 24 ++--
rust/kernel/platform.rs | 5 +-
rust/kernel/usb.rs | 18 +--
samples/rust/rust_debugfs.rs | 1 -
samples/rust/rust_dma.rs | 3 +-
samples/rust/rust_driver_auxiliary.rs | 4 +-
samples/rust/rust_driver_i2c.rs | 3 -
samples/rust/rust_driver_pci.rs | 11 +-
samples/rust/rust_driver_platform.rs | 2 -
samples/rust/rust_driver_usb.rs | 1 -
samples/rust/rust_i2c_client.rs | 2 -
samples/rust/rust_soc.rs | 2 -
24 files changed, 166 insertions(+), 374 deletions(-)
---
base-commit: 4fa3f5fabb30bf00d7475d5a33459ea83d639bf9
change-id: 20260612-id_info-23eca472ccd8
Best regards,
--
Gary Guo <gary@garyguo.net>
^ permalink raw reply
* [PATCH 1/1] xfrm: nat_keepalive: avoid double free on send error
From: Ren Wei @ 2026-06-18 16:36 UTC (permalink / raw)
To: netdev
Cc: steffen.klassert, herbert, davem, eyal.birger, yuantan098, bird,
qianyuluo3, n05ec
In-Reply-To: <cover.1781788385.git.qianyuluo3@gmail.com>
From: Qianyu Luo <qianyuluo3@gmail.com>
nat_keepalive_send() frees the keepalive skb whenever the IPv4 or IPv6
send helper reports an error.
That cleanup is only correct before the skb is handed to the output
path. Once ip_build_and_send_pkt() or ip6_xmit() takes ownership, the
networking stack may already have consumed the skb before returning an
error, so freeing it again is unsafe.
Handle the pre-handoff failure cases inside nat_keepalive_send_ipv4()
and nat_keepalive_send_ipv6(), where the caller still owns the skb, and
keep nat_keepalive_send() responsible only for family dispatch and the
unsupported-family cleanup path.
Fixes: f531d13bdfe3 ("xfrm: support sending NAT keepalives in ESP in UDP states")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Qianyu Luo <qianyuluo3@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
net/xfrm/xfrm_nat_keepalive.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/net/xfrm/xfrm_nat_keepalive.c b/net/xfrm/xfrm_nat_keepalive.c
index 458931062a04..f71328096f11 100644
--- a/net/xfrm/xfrm_nat_keepalive.c
+++ b/net/xfrm/xfrm_nat_keepalive.c
@@ -55,8 +55,10 @@ static int nat_keepalive_send_ipv4(struct sk_buff *skb,
ka->encap_sport, sock_net_uid(net, NULL));
rt = ip_route_output_key(net, &fl4);
- if (IS_ERR(rt))
+ if (IS_ERR(rt)) {
+ kfree_skb(skb);
return PTR_ERR(rt);
+ }
skb_dst_set(skb, &rt->dst);
@@ -100,6 +102,7 @@ static int nat_keepalive_send_ipv6(struct sk_buff *skb,
sock_net_set(sk, net);
dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL);
if (IS_ERR(dst)) {
+ kfree_skb(skb);
local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
return PTR_ERR(dst);
}
@@ -118,7 +121,6 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
sizeof(struct ipv6hdr)) +
sizeof(struct udphdr);
const u8 nat_ka_payload = 0xFF;
- int err = -EAFNOSUPPORT;
struct sk_buff *skb;
struct udphdr *uh;
@@ -140,16 +142,17 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
switch (ka->family) {
case AF_INET:
- err = nat_keepalive_send_ipv4(skb, ka);
+ nat_keepalive_send_ipv4(skb, ka);
break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
- err = nat_keepalive_send_ipv6(skb, ka, uh);
+ nat_keepalive_send_ipv6(skb, ka, uh);
break;
#endif
- }
- if (err)
+ default:
kfree_skb(skb);
+ break;
+ }
}
struct nat_keepalive_work_ctx {
--
2.43.7
^ permalink raw reply related
* [PATCH net 6/6] ipv6: fix missing notification for ignore_routes_with_linkdown
From: Fernando Fernandez Mancera @ 2026-06-18 16:22 UTC (permalink / raw)
To: netdev
Cc: nicolas.dichtel, shemminger, dforster, gospo, ddutt, brian.haley,
horms, pabeni, kuba, edumazet, davem, idosch, dsahern,
Fernando Fernandez Mancera
In-Reply-To: <20260618162225.4588-1-fmancera@suse.de>
When changing the ignore_routes_with_linkdown sysctl for a specific
interface, the RTM_NEWNETCONF netlink notification was not being emitted
to userspace. Fix this by emitting the notification when needed.
In addition, fix bogus return value for successful "all" and specific
interface write operation leading to a wrong reset of the position
pointer.
Fixes: 35103d11173b ("net: ipv6 sysctl option to ignore routes when nexthop link is down")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
net/ipv6/addrconf.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1cfb223476bd..2d81569b692b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -955,11 +955,7 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
NETCONFA_IFINDEX_DEFAULT,
net->ipv6.devconf_dflt);
- rtnl_net_unlock(net);
- return 0;
- }
-
- if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) {
+ } else if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) {
WRITE_ONCE(net->ipv6.devconf_dflt->ignore_routes_with_linkdown, newf);
addrconf_linkdown_change(net, newf);
if ((!newf) ^ (!old))
@@ -968,11 +964,21 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
+ } else {
+ if (!newf ^ !old) {
+ struct inet6_dev *idev = table->extra1;
+
+ inet6_netconf_notify_devconf(net,
+ RTM_NEWNETCONF,
+ NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+ idev->dev->ifindex,
+ &idev->cnf);
+ }
}
rtnl_net_unlock(net);
- return 1;
+ return 0;
}
#endif
--
2.54.0
^ permalink raw reply related
* [PATCH net 5/6] ipv6: reset value and position for proxy_ndp sysctl restart
From: Fernando Fernandez Mancera @ 2026-06-18 16:22 UTC (permalink / raw)
To: netdev
Cc: nicolas.dichtel, shemminger, dforster, gospo, ddutt, brian.haley,
horms, pabeni, kuba, edumazet, davem, idosch, dsahern,
Fernando Fernandez Mancera
In-Reply-To: <20260618162225.4588-1-fmancera@suse.de>
When handling proxy_ndp, if rtnl_net_trylock() fails, the operation is
retried but as the value was already modified by the initial
proc_dointvec() call, the restarted syscall will read the newly modified
value as the 'old' state.
Fix this by restoring the original value and position pointer before
restarting the syscall.
Fixes: c92d5491a6d9 ("netconf: add support for IPv6 proxy_ndp")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
net/ipv6/addrconf.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8ff015975e27..1cfb223476bd 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6483,8 +6483,9 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = ctl->data;
- int ret;
+ loff_t pos = *ppos;
int old, new;
+ int ret;
old = *valp;
ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
@@ -6493,8 +6494,12 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
if (write && old != new) {
struct net *net = ctl->extra2;
- if (!rtnl_net_trylock(net))
+ if (!rtnl_net_trylock(net)) {
+ /* Restore the original values before restarting */
+ *valp = old;
+ *ppos = pos;
return restart_syscall();
+ }
if (valp == &net->ipv6.devconf_dflt->proxy_ndp) {
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
--
2.54.0
^ permalink raw reply related
* [PATCH net 3/6] ipv6: fix error handling in forwarding sysctl
From: Fernando Fernandez Mancera @ 2026-06-18 16:22 UTC (permalink / raw)
To: netdev
Cc: nicolas.dichtel, shemminger, dforster, gospo, ddutt, brian.haley,
horms, pabeni, kuba, edumazet, davem, idosch, dsahern,
Fernando Fernandez Mancera
In-Reply-To: <20260618162225.4588-1-fmancera@suse.de>
When writing to the forwarding sysctl, if proc_dointvec() fails to parse
the input, it returns a negative error code. The current implementation
is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although
the configuration was not modified at all. When modifying the "all"
variant it can also modify the configuration of existing interfaces to
the wrong value.
Fix this by checking the return value of proc_dointvec() and returning
early on failure.
Fixes: b325fddb7f86 ("ipv6: Fix sysctl unregistration deadlock")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
net/ipv6/addrconf.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 70058d971205..0b128b6cff60 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6370,6 +6370,8 @@ static int addrconf_sysctl_forward(const struct ctl_table *ctl, int write,
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
+ if (ret)
+ return ret;
if (write)
ret = addrconf_fixup_forwarding(ctl, valp, val);
--
2.54.0
^ permalink raw reply related
* [PATCH net 2/6] ipv6: fix error handling in ignore_routes_with_linkdown sysctl
From: Fernando Fernandez Mancera @ 2026-06-18 16:22 UTC (permalink / raw)
To: netdev
Cc: nicolas.dichtel, shemminger, dforster, gospo, ddutt, brian.haley,
horms, pabeni, kuba, edumazet, davem, idosch, dsahern,
Fernando Fernandez Mancera
In-Reply-To: <20260618162225.4588-1-fmancera@suse.de>
When writing to the ignore_routes_with_linkdown sysctl, if
proc_dointvec() fails to parse the input, it returns a negative error
code. The current implementation is overwriting that error for write
operations.
This results in a silent failure, it returns a successful write although
the configuration was not modified at all. When modifying the "all"
variant it can also modify the configuration of existing interfaces to
the wrong value.
Fix this by checking the return value of proc_dointvec() and returning
early on failure.
Fixes: 35103d11173b ("net: ipv6 sysctl option to ignore routes when nexthop link is down")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
net/ipv6/addrconf.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c901b444a995..70058d971205 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6671,6 +6671,8 @@ int addrconf_sysctl_ignore_routes_with_linkdown(const struct ctl_table *ctl,
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
+ if (ret)
+ return ret;
if (write)
ret = addrconf_fixup_linkdown(ctl, valp, val);
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox