Commit f553246f authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

RDMA/core: Change how failing destroy is handled during uobj abort

Currently it triggers a WARN_ON and then goes ahead and destroys the
uobject anyhow, leaking any driver memory.

The only place that leaks driver memory should be during FD close() in
uverbs_destroy_ufile_hw().

Drivers are only allowed to fail destroy uobjects if they guarantee
destroy will eventually succeed. uverbs_destroy_ufile_hw() provides the
loop to give the driver that chance.

Link: https://lore.kernel.org/r/20200902081708.746631-1-leon@kernel.org


Signed-off-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 00b3c118
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -130,17 +130,6 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
	lockdep_assert_held(&ufile->hw_destroy_rwsem);
	assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE);

	if (reason == RDMA_REMOVE_ABORT_HWOBJ) {
		reason = RDMA_REMOVE_ABORT;
		ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason,
								attrs);
		/*
		 * Drivers are not permitted to ignore RDMA_REMOVE_ABORT, see
		 * ib_is_destroy_retryable, cleanup_retryable == false here.
		 */
		WARN_ON(ret);
	}

	if (reason == RDMA_REMOVE_ABORT) {
		WARN_ON(!list_empty(&uobj->list));
		WARN_ON(!uobj->context);
@@ -674,11 +663,22 @@ void rdma_alloc_abort_uobject(struct ib_uobject *uobj,
			      bool hw_obj_valid)
{
	struct ib_uverbs_file *ufile = uobj->ufile;
	int ret;

	uverbs_destroy_uobject(uobj,
			       hw_obj_valid ? RDMA_REMOVE_ABORT_HWOBJ :
					      RDMA_REMOVE_ABORT,
			       attrs);
	if (hw_obj_valid) {
		ret = uobj->uapi_object->type_class->destroy_hw(
			uobj, RDMA_REMOVE_ABORT, attrs);
		/*
		 * If the driver couldn't destroy the object then go ahead and
		 * commit it. Leaking objects that can't be destroyed is only
		 * done during FD close after the driver has a few more tries to
		 * destroy it.
		 */
		if (WARN_ON(ret))
			return rdma_alloc_commit_uobject(uobj, attrs);
	}

	uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT, attrs);

	/* Matches the down_read in rdma_alloc_begin_uobject */
	up_read(&ufile->hw_destroy_rwsem);
+0 −5
Original line number Diff line number Diff line
@@ -1463,11 +1463,6 @@ enum rdma_remove_reason {
	RDMA_REMOVE_DRIVER_REMOVE,
	/* uobj is being cleaned-up before being committed */
	RDMA_REMOVE_ABORT,
	/*
	 * uobj has been fully created, with the uobj->object set, but is being
	 * cleaned up before being comitted
	 */
	RDMA_REMOVE_ABORT_HWOBJ,
};

struct ib_rdmacg_object {