mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Zhi Wang <zhiw@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>
Cc: <rust-for-linux@vger.kernel.org>, <linux-pci@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <aliceryhl@google.com>,
	<bhelgaas@google.com>, <kwilczynski@kernel.org>,
	<ojeda@kernel.org>, <boqun@kernel.org>, <gary@garyguo.net>,
	<bjorn3_gh@protonmail.com>, <lossin@kernel.org>,
	<a.hindborg@kernel.org>, <tmgross@umich.edu>,
	<markus.probst@posteo.de>, <cjia@nvidia.com>, <smitra@nvidia.com>,
	<ankita@nvidia.com>, <aniketa@nvidia.com>, <kwankhede@nvidia.com>,
	<targupta@nvidia.com>, <kjaju@nvidia.com>, <alkumar@nvidia.com>,
	<acourbot@nvidia.com>, <jhubbard@nvidia.com>,
	<zhiwang@kernel.org>, <jgg@nvidia.com>, <alex@shazbot.org>
Subject: Re: [PATCH v2 7/8] rust: pci: add typed SR-IOV PF registration data
Date: Tue, 29 Sep 2026 10:27:33 +0300	[thread overview]
Message-ID: <20260929102733.3e0429b8@inno-dell> (raw)
In-Reply-To: <DLR7ZIHFTUWF.160C4AKB6W3II@kernel.org>

On Mon, 28 Sep 2026 22:08:46 +0200
"Danilo Krummrich" <dakr@kernel.org> wrote:

> On Thu Sep 24, 2026 at 9:05 PM CEST, Zhi Wang wrote:

snip

> > +            if pdev.is_virtfn() {
> > +                return Err(ENODEV);
> > +            }
> > +
> > +            let published = pdev.is_physfn();
> > +            if published {  
> 
> The published thing seems unnecessary, am I missing something?
> 

I was thinking of PF drivers that only need to enable SR-IOV and do
not need to share any data or services with their VF drivers.

If we rely on VfRegistration to disable SR-IOV on PF removal, would
those drivers also need to keep a VfRegistration with () as its data,
solely for the teardown guarantee?

Z.

> > +                if pdev.num_vf() != 0 {
> > +                    return Err(EBUSY);
> > +                }
> > +
> > +                if !pdev.vf_registration_data_rust().is_null() {
> > +                    return Err(EBUSY);
> > +                }
> > +            }
> > +
> > +            Ok(try_pin_init!(Self {
> > +                pdev,
> > +                inner <- VfRegistrationData::new(data),
> > +                published,
> > +                _pin: PhantomPinned,
> > +                _: {
> > +                    if *published {
> > +                        // Store the pointer to the pinned
> > `VfRegistrationData`
> > +                        // on the PCI device so VF drivers can
> > find it.
> > +                        pdev.set_vf_registration_data_rust(
> > +
> > core::ptr::from_ref(inner.as_ref().get_ref()).cast_mut().cast(),
> > +                        );
> > +                    }
> > +                },
> > +            }))
> > +        })
> > +    }
> > +}
> > +
> > +#[pinned_drop]
> > +impl<F: ForLt + 'static> PinnedDrop for VfRegistration<'_, F> {
> > +    fn drop(self: Pin<&mut Self>) {
> > +        if !self.published {
> > +            return;
> > +        }  
> 
> How can this ever happen?
> 
> > +
> > +        // SAFETY: `pci_disable_sriov()` is safe to call on any
> > `pci_dev`; it
> > +        // is a no-op if the device has no VFs enabled. When VFs
> > are enabled,
> > +        // this blocks until all VF `remove()` callbacks complete.
> > +        unsafe { bindings::pci_disable_sriov(self.pdev.as_raw()) };
> > +
> > +        // After `pci_disable_sriov()` all VFs are gone, so no one
> > can read
> > +        // the pointer anymore.
> > +        self.pdev
> > +            .set_vf_registration_data_rust(core::ptr::null_mut());
> > +
> > +        // The pinned `inner` field is dropped automatically after
> > this returns.
> > +    }
> > +}
> > +
> > +// SAFETY: The inner data is `Send` (enforced by the bound), and
> > `&PciDevice` is `Send + Sync`. +unsafe impl<F: ForLt> Send for
> > VfRegistration<'_, F> where for<'a> F::Of<'a>: Send {} +
> > +// SAFETY: The inner data is `Send + Sync`. `VfRegistration`
> > doesn't expose mutable access; +// VF drivers only read the data
> > through an immutable pinned reference. +unsafe impl<F: ForLt> Sync
> > for VfRegistration<'_, F> where for<'a> F::Of<'a>: Send + Sync {} +
> > +impl<Ctx: device::DeviceContext> PciDevice<Ctx> {
> > +    /// Returns the raw `vf_registration_data_rust` pointer from
> > this device.
> > +    fn vf_registration_data_rust(&self) -> *mut core::ffi::c_void {
> > +        // SAFETY: `self.as_raw()` is valid.
> > +        unsafe { (*self.as_raw()).vf_registration_data_rust }
> > +    }
> > +
> > +    /// Sets the `vf_registration_data_rust` pointer on this
> > device.
> > +    fn set_vf_registration_data_rust(&self, ptr: *mut
> > core::ffi::c_void) {
> > +        // SAFETY: `self.as_raw()` is valid. PCI probe publishes
> > the data before enabling VFs;
> > +        // teardown removes all VFs before withdrawing it.
> > +        unsafe { (*self.as_raw()).vf_registration_data_rust = ptr
> > };
> > +    }
> > +}  
> 
> Those can't be safe functions, but I'd just drop those helpers anyway
> and just inline the accesses. It should only be three places after
> all.
> 
> > +
> > +impl PciDevice<device::Bound> {
> > +    /// Returns the PF for this VF, or [`ENODEV`] if this is not a
> > VF.
> > +    fn physfn(&self) -> Result<&PciDevice> {
> > +        if !self.is_virtfn() {
> > +            return Err(ENODEV);
> > +        }
> > +
> > +        // SAFETY: `self.as_raw()` is valid and this VF uses the
> > `physfn` union field.
> > +        let pf = unsafe { (*self.as_raw()).__bindgen_anon_1.physfn
> > };
> > +        if pf.is_null() {
> > +            return Err(ENODEV);
> > +        }
> > +
> > +        // SAFETY: PCI holds a PF reference until VF removal
> > completes. The returned borrow
> > +        // cannot outlive this bound VF, and `PciDevice` is a
> > transparent wrapper of `pci_dev`.
> > +        Ok(unsafe { &*pf.cast() })
> > +    }  
> 
> I don't think we need this, the PF's pci::Device<Bound> can be part
> of the data stored in the VfRegistrationData if needed.
> 
> > +
> > +    /// Internal helper: reads the `vf_registration_data_rust`
> > pointer from the
> > +    /// PF, checks the `TypeId`, and returns a pinned reference.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// The returned borrow must be confined by a closure
> > higher-ranked independently over its
> > +    /// borrow and data lifetimes, or `F` must be covariant in its
> > encoded lifetime.
> > +    unsafe fn vf_registration_data_pinned<F: ForLt +
> > 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
> > +        let pf = self.physfn()?;
> > +
> > +        let ptr = pf.vf_registration_data_rust();
> > +        if ptr.is_null() {
> > +            return Err(ENOENT);
> > +        }
> > +
> > +        // SAFETY: The Rust PCI adapter keeps the PF data
> > installed until VF removal completes.
> > +        // `ptr` points to a `VfRegistrationData` whose first
> > field is a `TypeId`.
> > +        let type_id = unsafe { ptr.cast::<TypeId>().read() };
> > +        if type_id != TypeId::of::<F>() {
> > +            return Err(EINVAL);
> > +        }
> > +
> > +        // SAFETY: TypeId check confirms the stored type matches
> > `F`. The data
> > +        // is pinned inside the PF's driver data struct. Lifetime
> > shortening
> > +        // from the PF's binding scope to `'_` is
> > layout-compatible.
> > +        let data_ptr = unsafe {
> > +            let vfrd = ptr.cast::<VfRegistrationData<'_, F>>();
> > +            &raw const (*vfrd).data
> > +        };
> > +
> > +        // SAFETY: `data` is structurally pinned inside
> > `VfRegistrationData`.
> > +        Ok(unsafe { Pin::new_unchecked(&*data_ptr) })
> > +    }
> > +
> > +    /// Access the VF registration data through a closure with an
> > HRTB lifetime.
> > +    ///
> > +    /// `F` is the [`ForLt`](trait@ForLt) encoding of the data
> > type. Returns
> > +    /// [`ENODEV`] if this is not a VF, [`ENOENT`] if no data was
> > registered,
> > +    /// or [`EINVAL`] if `F` does not match the type registered by
> > the PF.
> > +    ///
> > +    /// The closure's borrow and the registration data's lifetime
> > are independent, so a borrow of
> > +    /// the context cannot be stored in invariant registration
> > data.
> > +    pub fn vf_registration_data_with<F: ForLt + 'static, R>(
> > +        &self,
> > +        f: impl for<'borrow, 'data> FnOnce(Pin<&'borrow
> > F::Of<'data>>) -> R,
> > +    ) -> Result<R> {
> > +        // SAFETY: The higher-ranked closure prevents the borrow
> > from escaping or being stored in
> > +        // invariant data by keeping its lifetime independent of
> > the erased data lifetime.
> > +        let pinned = unsafe {
> > self.vf_registration_data_pinned::<F>()? };
> > +        Ok(f(pinned))
> > +    }  
> 
> Just like in auxiliary, the signature should be:
> 
> 	pub fn registration_data_with<'this, F: ForLt + 'static, R>(
> 	    &'this self,
> 	    f: impl for<'a> FnOnce(Pin<&'this F::Of<'a>>) -> R,
> 	) -> Result<R> {
> 
> > +
> > +    /// Returns a pinned reference to the VF registration data.
> > +    ///
> > +    /// Available only when `F` implements
> > [`CovariantForLt`](trait@crate::types::CovariantForLt),
> > +    /// guaranteeing that shortening the PF data lifetime is sound.
> > +    ///
> > +    /// For non-covariant types, use
> > [`Self::vf_registration_data_with()`].
> > +    ///
> > +    /// It returns the same errors as
> > [`Self::vf_registration_data_with()`].
> > +    pub fn vf_registration_data<F: CovariantForLt +
> > 'static>(&self) -> Result<Pin<&F::Of<'_>>> {
> > +        // SAFETY: `CovariantForLt` permits shortening the encoded
> > lifetime to this borrow.
> > +        unsafe { self.vf_registration_data_pinned::<F>() }
> > +    }
> > +}
> > -- 
> > 2.53.0  
> 


  reply	other threads:[~2026-09-29  7:28 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-24 19:05 [PATCH v2 0/8] Add Rust PCI SR-IOV support Zhi Wang
2026-09-24 19:05 ` [PATCH v2 1/8] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability Zhi Wang
2026-09-25 20:43   ` Peter Colberg
2026-09-28 19:32     ` Zhi Wang
2026-09-27 16:37   ` Danilo Krummrich
2026-09-28 19:45     ` Zhi Wang
2026-09-24 19:05 ` [PATCH v2 2/8] rust: pci: add vtable attribute to pci::Driver trait Zhi Wang
2026-09-24 19:05 ` [PATCH v2 3/8] rust: pci: add is_virtfn(), to check for VFs Zhi Wang
2026-09-24 19:05 ` [PATCH v2 4/8] rust: pci: add is_physfn(), to check for PFs Zhi Wang
2026-09-24 19:05 ` [PATCH v2 5/8] rust: pci: add num_vf(), to return number of VFs Zhi Wang
2026-09-24 19:05 ` [PATCH v2 6/8] rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs Zhi Wang
2026-09-24 19:05 ` [PATCH v2 7/8] rust: pci: add typed SR-IOV PF registration data Zhi Wang
2026-09-28 20:08   ` Danilo Krummrich
2026-09-29  7:27     ` Zhi Wang [this message]
2026-09-29  8:35       ` Danilo Krummrich
2026-09-24 19:05 ` [PATCH v2 8/8] samples: rust: add Rust SR-IOV VF driver sample Zhi Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260929102733.3e0429b8@inno-dell \
    --to=zhiw@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=alex@shazbot.org \
    --cc=aliceryhl@google.com \
    --cc=alkumar@nvidia.com \
    --cc=aniketa@nvidia.com \
    --cc=ankita@nvidia.com \
    --cc=bhelgaas@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=cjia@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=gary@garyguo.net \
    --cc=jgg@nvidia.com \
    --cc=jhubbard@nvidia.com \
    --cc=kjaju@nvidia.com \
    --cc=kwankhede@nvidia.com \
    --cc=kwilczynski@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=markus.probst@posteo.de \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=smitra@nvidia.com \
    --cc=targupta@nvidia.com \
    --cc=tmgross@umich.edu \
    --cc=zhiwang@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®