Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iommufd/device: Replace device_list with device_array

igroup->attach->device_list is used to track attached device of a group
in the RID path. Such tracking is also needed in the PASID path in order
to share path with the RID path.

While there is only one list_head in the iommufd_device. It cannot work
if the device has been attached in both RID path and PASID path. To solve
it, replacing the device_list with an xarray. The attached iommufd_device
is stored in the entry indexed by the idev->obj.id.

Link: https://patch.msgid.link/r/20250321171940.7213-9-yi.l.liu@intel.com
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

authored by

Yi Liu and committed by
Jason Gunthorpe
831b40f8 75f990ae

+39 -19
+39 -19
drivers/iommu/iommufd/device.c
··· 19 19 20 20 struct iommufd_attach { 21 21 struct iommufd_hw_pagetable *hwpt; 22 - struct list_head device_list; 22 + struct xarray device_array; 23 23 }; 24 24 25 25 static void iommufd_group_release(struct kref *kref) ··· 297 297 } 298 298 EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, "IOMMUFD"); 299 299 300 + static unsigned int iommufd_group_device_num(struct iommufd_group *igroup) 301 + { 302 + struct iommufd_device *idev; 303 + unsigned int count = 0; 304 + unsigned long index; 305 + 306 + lockdep_assert_held(&igroup->lock); 307 + 308 + if (igroup->attach) 309 + xa_for_each(&igroup->attach->device_array, index, idev) 310 + count++; 311 + return count; 312 + } 313 + 300 314 #ifdef CONFIG_IRQ_MSI_IOMMU 301 315 static int iommufd_group_setup_msi(struct iommufd_group *igroup, 302 316 struct iommufd_hwpt_paging *hwpt_paging) ··· 385 371 /* Check if idev is attached to igroup->hwpt */ 386 372 static bool iommufd_device_is_attached(struct iommufd_device *idev) 387 373 { 388 - struct iommufd_device *cur; 389 - 390 - list_for_each_entry(cur, &idev->igroup->attach->device_list, group_item) 391 - if (cur == idev) 392 - return true; 393 - return false; 374 + return xa_load(&idev->igroup->attach->device_array, idev->obj.id); 394 375 } 395 376 396 377 static int iommufd_hwpt_attach_device(struct iommufd_hw_pagetable *hwpt, ··· 519 510 rc = -ENOMEM; 520 511 goto err_unlock; 521 512 } 522 - INIT_LIST_HEAD(&attach->device_list); 513 + xa_init(&attach->device_array); 523 514 } 524 515 525 516 old_hwpt = attach->hwpt; 526 517 518 + rc = xa_insert(&attach->device_array, idev->obj.id, XA_ZERO_ENTRY, 519 + GFP_KERNEL); 520 + if (rc) { 521 + WARN_ON(rc == -EBUSY && !old_hwpt); 522 + goto err_free_attach; 523 + } 524 + 527 525 if (old_hwpt && old_hwpt != hwpt) { 528 526 rc = -EINVAL; 529 - goto err_free_attach; 527 + goto err_release_devid; 530 528 } 531 529 532 530 if (attach_resv) { 533 531 rc = iommufd_device_attach_reserved_iova(idev, hwpt_paging); 534 532 if (rc) 535 - goto err_free_attach; 533 + goto err_release_devid; 536 534 } 537 535 538 536 /* ··· 557 541 igroup->attach = attach; 558 542 } 559 543 refcount_inc(&hwpt->obj.users); 560 - list_add_tail(&idev->group_item, &attach->device_list); 544 + WARN_ON(xa_is_err(xa_store(&attach->device_array, idev->obj.id, 545 + idev, GFP_KERNEL))); 561 546 mutex_unlock(&igroup->lock); 562 547 return 0; 563 548 err_unresv: 564 549 if (attach_resv) 565 550 iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, idev->dev); 551 + err_release_devid: 552 + xa_release(&attach->device_array, idev->obj.id); 566 553 err_free_attach: 567 554 if (iommufd_group_first_attach(igroup, pasid)) 568 555 kfree(attach); ··· 587 568 hwpt = attach->hwpt; 588 569 hwpt_paging = find_hwpt_paging(hwpt); 589 570 590 - list_del(&idev->group_item); 591 - if (list_empty(&attach->device_list)) { 571 + xa_erase(&attach->device_array, idev->obj.id); 572 + if (xa_empty(&attach->device_array)) { 592 573 iommufd_hwpt_detach_device(hwpt, idev, pasid); 593 574 igroup->attach = NULL; 594 575 kfree(attach); ··· 618 599 struct iommufd_hwpt_paging *hwpt_paging) 619 600 { 620 601 struct iommufd_device *cur; 602 + unsigned long index; 621 603 622 604 lockdep_assert_held(&igroup->lock); 623 605 624 - list_for_each_entry(cur, &igroup->attach->device_list, group_item) 606 + xa_for_each(&igroup->attach->device_array, index, cur) 625 607 iopt_remove_reserved_iova(&hwpt_paging->ioas->iopt, cur->dev); 626 608 } 627 609 ··· 632 612 { 633 613 struct iommufd_hwpt_paging *old_hwpt_paging; 634 614 struct iommufd_device *cur; 615 + unsigned long index; 635 616 int rc; 636 617 637 618 lockdep_assert_held(&igroup->lock); 638 619 639 620 old_hwpt_paging = find_hwpt_paging(igroup->attach->hwpt); 640 621 if (!old_hwpt_paging || hwpt_paging->ioas != old_hwpt_paging->ioas) { 641 - list_for_each_entry(cur, 642 - &igroup->attach->device_list, group_item) { 622 + xa_for_each(&igroup->attach->device_array, index, cur) { 643 623 rc = iopt_table_enforce_dev_resv_regions( 644 624 &hwpt_paging->ioas->iopt, cur->dev, NULL); 645 625 if (rc) ··· 680 660 681 661 old_hwpt = attach->hwpt; 682 662 683 - WARN_ON(!old_hwpt || list_empty(&attach->device_list)); 663 + WARN_ON(!old_hwpt || xa_empty(&attach->device_array)); 684 664 685 665 if (!iommufd_device_is_attached(idev)) { 686 666 rc = -EINVAL; ··· 709 689 710 690 attach->hwpt = hwpt; 711 691 712 - num_devices = list_count_nodes(&attach->device_list); 692 + num_devices = iommufd_group_device_num(igroup); 713 693 /* 714 - * Move the refcounts held by the device_list to the new hwpt. Retain a 694 + * Move the refcounts held by the device_array to the new hwpt. Retain a 715 695 * refcount for this thread as the caller will free it. 716 696 */ 717 697 refcount_add(num_devices, &hwpt->obj.users);