|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v9 01/16] pci: introduce per-domain PCI rwlock
Hello Roger,
Roger Pau Monné <roger.pau@xxxxxxxxxx> writes:
> On Tue, Aug 29, 2023 at 11:19:42PM +0000, Volodymyr Babchuk wrote:
>> Add per-domain d->pci_lock that protects access to
>> d->pdev_list. Purpose of this lock is to give guarantees to VPCI code
>> that underlying pdev will not disappear under feet. This is a rw-lock,
>> but this patch adds only write_lock()s. There will be read_lock()
>> users in the next patches.
>>
>> This lock should be taken in write mode every time d->pdev_list is
>> altered. This covers both accesses to d->pdev_list and accesses to
>> pdev->domain_list fields.
>
> Why do you mention pdev->domain_list here? I don't think the lock
> covers accesses to pdev->domain_list, unless that domain_list field
> happens to be part of the linked list in d->pdev_list. I find it kind
> of odd to mention here.
You are correct. I was referring very specific case in reassign_device()
IOMMU functions. It seemed important for me when I wrote this. But you
are correct, no need to mention pdev->domain_list explicitly.
>
>> All write accesses also should be protected
>> by pcidevs_lock() as well. Idea is that any user that wants read
>> access to the list or to the devices stored in the list should use
>> either this new d->pci_lock or old pcidevs_lock(). Usage of any of
>> this two locks will ensure only that pdev of interest will not
>> disappear from under feet and that the pdev still will be assigned to
>> the same domain. Of course, any new users should use pcidevs_lock()
>> when it is appropriate (e.g. when accessing any other state that is
>> protected by the said lock). In case both the newly introduced
>> per-domain rwlock and the pcidevs lock is taken, the later must be
>> acquired first.
>>
>> Any write access to pdev->domain_list should be protected by both
>> pcidevs_lock() and d->pci_lock in the write mode.
>>
>> Suggested-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
>> Suggested-by: Jan Beulich <jbeulich@xxxxxxxx>
>> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
>>
>> ---
>>
>> Changes in v9:
>> - returned back "pdev->domain = target;" in AMD IOMMU code
>> - used "source" instead of pdev->domain in IOMMU functions
>> - added comment about lock ordering in the commit message
>> - reduced locked regions
>> - minor changes non-functional changes in various places
>>
>> Changes in v8:
>> - New patch
>>
>> Changes in v8 vs RFC:
>> - Removed all read_locks after discussion with Roger in #xendevel
>> - pci_release_devices() now returns the first error code
>> - extended commit message
>> - added missing lock in pci_remove_device()
>> - extended locked region in pci_add_device() to protect list_del() calls
>> ---
>> xen/common/domain.c | 1 +
>> xen/drivers/passthrough/amd/pci_amd_iommu.c | 9 ++-
>> xen/drivers/passthrough/pci.c | 71 +++++++++++++++++----
>> xen/drivers/passthrough/vtd/iommu.c | 9 ++-
>> xen/include/xen/sched.h | 1 +
>> 5 files changed, 78 insertions(+), 13 deletions(-)
>>
>> diff --git a/xen/common/domain.c b/xen/common/domain.c
>> index 304aa04fa6..9b04a20160 100644
>> --- a/xen/common/domain.c
>> +++ b/xen/common/domain.c
>> @@ -651,6 +651,7 @@ struct domain *domain_create(domid_t domid,
>>
>> #ifdef CONFIG_HAS_PCI
>> INIT_LIST_HEAD(&d->pdev_list);
>> + rwlock_init(&d->pci_lock);
>> #endif
>>
>> /* All error paths can depend on the above setup. */
>> diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c
>> b/xen/drivers/passthrough/amd/pci_amd_iommu.c
>> index bea70db4b7..d219bd9453 100644
>> --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
>> +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
>> @@ -476,7 +476,14 @@ static int cf_check reassign_device(
>>
>> if ( devfn == pdev->devfn && pdev->domain != target )
>> {
>> - list_move(&pdev->domain_list, &target->pdev_list);
>> + write_lock(&source->pci_lock);
>> + list_del(&pdev->domain_list);
>> + write_unlock(&source->pci_lock);
>> +
>> + write_lock(&target->pci_lock);
>> + list_add(&pdev->domain_list, &target->pdev_list);
>> + write_unlock(&target->pci_lock);
>> +
>> pdev->domain = target;
>
> While I don't think this is strictly an issue right now, it would be
> better to set pdev->domain before the device is added to domain_list.
> A pattern like:
>
> read_lock(d->pci_lock);
> for_each_pdev(d, pdev)
> foo(pdev->domain);
> read_unlock(d->pci_lock);
>
> Wouldn't work currently if the pdev is added to domain_list before the
> pdev->domain field is updated to reflect the new owner.
Agree. I moved `pdev->domain = target` so it sits between list_del() and
list_add() calls
--
WBR, Volodymyr
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |