Skip to content

Commit 9227da7

Browse files
nicolincjgunthorpe
authored andcommitted
iommufd: Add iommufd_access_change_ioas(_id) helpers
The complication of the mutex and refcount will be amplified after we introduce the replace support for accesses. So, add a preparatory change of a constitutive helper iommufd_access_change_ioas() and its wrapper iommufd_access_change_ioas_id(). They can simply take care of existing iommufd_access_attach() and iommufd_access_detach(), properly sequencing the refcount puts so that they are truely at the end of the sequence after we know the IOAS pointer is not required any more. Link: https://lore.kernel.org/r/da0c462532193b447329c4eb975a596f47e49b70.1690523699.git.nicolinc@nvidia.com Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent 5d5c85f commit 9227da7

File tree

1 file changed

+71
-38
lines changed

1 file changed

+71
-38
lines changed

drivers/iommu/iommufd/device.c

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,70 @@ void iommufd_device_detach(struct iommufd_device *idev)
684684
}
685685
EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, IOMMUFD);
686686

687+
/*
688+
* On success, it will refcount_inc() at a valid new_ioas and refcount_dec() at
689+
* a valid cur_ioas (access->ioas). A caller passing in a valid new_ioas should
690+
* call iommufd_put_object() if it does an iommufd_get_object() for a new_ioas.
691+
*/
692+
static int iommufd_access_change_ioas(struct iommufd_access *access,
693+
struct iommufd_ioas *new_ioas)
694+
{
695+
u32 iopt_access_list_id = access->iopt_access_list_id;
696+
struct iommufd_ioas *cur_ioas = access->ioas;
697+
int rc;
698+
699+
lockdep_assert_held(&access->ioas_lock);
700+
701+
/* We are racing with a concurrent detach, bail */
702+
if (cur_ioas != access->ioas_unpin)
703+
return -EBUSY;
704+
705+
if (cur_ioas == new_ioas)
706+
return 0;
707+
708+
/*
709+
* Set ioas to NULL to block any further iommufd_access_pin_pages().
710+
* iommufd_access_unpin_pages() can continue using access->ioas_unpin.
711+
*/
712+
access->ioas = NULL;
713+
714+
if (new_ioas) {
715+
rc = iopt_add_access(&new_ioas->iopt, access);
716+
if (rc) {
717+
access->ioas = cur_ioas;
718+
return rc;
719+
}
720+
refcount_inc(&new_ioas->obj.users);
721+
}
722+
723+
if (cur_ioas) {
724+
if (access->ops->unmap) {
725+
mutex_unlock(&access->ioas_lock);
726+
access->ops->unmap(access->data, 0, ULONG_MAX);
727+
mutex_lock(&access->ioas_lock);
728+
}
729+
iopt_remove_access(&cur_ioas->iopt, access, iopt_access_list_id);
730+
refcount_dec(&cur_ioas->obj.users);
731+
}
732+
733+
access->ioas = new_ioas;
734+
access->ioas_unpin = new_ioas;
735+
736+
return 0;
737+
}
738+
739+
static int iommufd_access_change_ioas_id(struct iommufd_access *access, u32 id)
740+
{
741+
struct iommufd_ioas *ioas = iommufd_get_ioas(access->ictx, id);
742+
int rc;
743+
744+
if (IS_ERR(ioas))
745+
return PTR_ERR(ioas);
746+
rc = iommufd_access_change_ioas(access, ioas);
747+
iommufd_put_object(&ioas->obj);
748+
return rc;
749+
}
750+
687751
void iommufd_access_destroy_object(struct iommufd_object *obj)
688752
{
689753
struct iommufd_access *access =
@@ -761,60 +825,29 @@ EXPORT_SYMBOL_NS_GPL(iommufd_access_destroy, IOMMUFD);
761825

762826
void iommufd_access_detach(struct iommufd_access *access)
763827
{
764-
struct iommufd_ioas *cur_ioas = access->ioas;
765-
766828
mutex_lock(&access->ioas_lock);
767-
if (WARN_ON(!access->ioas))
768-
goto out;
769-
/*
770-
* Set ioas to NULL to block any further iommufd_access_pin_pages().
771-
* iommufd_access_unpin_pages() can continue using access->ioas_unpin.
772-
*/
773-
access->ioas = NULL;
774-
775-
if (access->ops->unmap) {
829+
if (WARN_ON(!access->ioas)) {
776830
mutex_unlock(&access->ioas_lock);
777-
access->ops->unmap(access->data, 0, ULONG_MAX);
778-
mutex_lock(&access->ioas_lock);
831+
return;
779832
}
780-
iopt_remove_access(&cur_ioas->iopt, access,
781-
access->iopt_access_list_id);
782-
refcount_dec(&cur_ioas->obj.users);
783-
out:
784-
access->ioas_unpin = NULL;
833+
WARN_ON(iommufd_access_change_ioas(access, NULL));
785834
mutex_unlock(&access->ioas_lock);
786835
}
787836
EXPORT_SYMBOL_NS_GPL(iommufd_access_detach, IOMMUFD);
788837

789838
int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id)
790839
{
791-
struct iommufd_ioas *new_ioas;
792-
int rc = 0;
840+
int rc;
793841

794842
mutex_lock(&access->ioas_lock);
795-
if (WARN_ON(access->ioas || access->ioas_unpin)) {
843+
if (WARN_ON(access->ioas)) {
796844
mutex_unlock(&access->ioas_lock);
797845
return -EINVAL;
798846
}
799847

800-
new_ioas = iommufd_get_ioas(access->ictx, ioas_id);
801-
if (IS_ERR(new_ioas)) {
802-
mutex_unlock(&access->ioas_lock);
803-
return PTR_ERR(new_ioas);
804-
}
805-
806-
rc = iopt_add_access(&new_ioas->iopt, access);
807-
if (rc) {
808-
mutex_unlock(&access->ioas_lock);
809-
iommufd_put_object(&new_ioas->obj);
810-
return rc;
811-
}
812-
iommufd_ref_to_users(&new_ioas->obj);
813-
814-
access->ioas = new_ioas;
815-
access->ioas_unpin = new_ioas;
848+
rc = iommufd_access_change_ioas_id(access, ioas_id);
816849
mutex_unlock(&access->ioas_lock);
817-
return 0;
850+
return rc;
818851
}
819852
EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, IOMMUFD);
820853

0 commit comments

Comments
 (0)