Skip to content

Commit 849e149

Browse files
committed
RDMA/core: Do not allow alloc_commit to fail
This is a left over from an earlier version that creates a lot of complexity for error unwind, particularly for FD uobjects. The only reason this was done is so that anon_inode_get_file() could be called with the final fops and a fully setup uobject. Both need to be setup since unwinding anon_inode_get_file() via fput will call the driver's release(). Now that the driver does not provide release, we no longer need to worry about this complicated sequence, simply create the struct file at the start and allow the core code's release function to deal with the abort case. This allows all the confusing error paths around commit to be removed. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Yishai Hadas <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 93887e6 commit 849e149

File tree

6 files changed

+99
-141
lines changed

6 files changed

+99
-141
lines changed

drivers/infiniband/core/rdma_core.c

Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,11 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
130130
lockdep_assert_held(&ufile->hw_destroy_rwsem);
131131
assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE);
132132

133-
if (uobj->object) {
133+
if (reason == RDMA_REMOVE_ABORT) {
134+
WARN_ON(!list_empty(&uobj->list));
135+
WARN_ON(!uobj->context);
136+
uobj->uapi_object->type_class->alloc_abort(uobj);
137+
} else if (uobj->object) {
134138
ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason,
135139
attrs);
136140
if (ret) {
@@ -146,12 +150,6 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
146150
uobj->object = NULL;
147151
}
148152

149-
if (reason == RDMA_REMOVE_ABORT) {
150-
WARN_ON(!list_empty(&uobj->list));
151-
WARN_ON(!uobj->context);
152-
uobj->uapi_object->type_class->alloc_abort(uobj);
153-
}
154-
155153
uobj->context = NULL;
156154

157155
/*
@@ -450,22 +448,40 @@ static struct ib_uobject *
450448
alloc_begin_fd_uobject(const struct uverbs_api_object *obj,
451449
struct ib_uverbs_file *ufile)
452450
{
451+
const struct uverbs_obj_fd_type *fd_type =
452+
container_of(obj->type_attrs, struct uverbs_obj_fd_type, type);
453453
int new_fd;
454454
struct ib_uobject *uobj;
455+
struct file *filp;
456+
457+
if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release))
458+
return ERR_PTR(-EINVAL);
455459

456460
new_fd = get_unused_fd_flags(O_CLOEXEC);
457461
if (new_fd < 0)
458462
return ERR_PTR(new_fd);
459463

460464
uobj = alloc_uobj(ufile, obj);
461-
if (IS_ERR(uobj)) {
462-
put_unused_fd(new_fd);
463-
return uobj;
465+
if (IS_ERR(uobj))
466+
goto err_fd;
467+
468+
/* Note that uverbs_uobject_fd_release() is called during abort */
469+
filp = anon_inode_getfile(fd_type->name, fd_type->fops, NULL,
470+
fd_type->flags);
471+
if (IS_ERR(filp)) {
472+
uobj = ERR_CAST(filp);
473+
goto err_uobj;
464474
}
475+
uobj->object = filp;
465476

466477
uobj->id = new_fd;
467478
uobj->ufile = ufile;
479+
return uobj;
468480

481+
err_uobj:
482+
uverbs_uobject_put(uobj);
483+
err_fd:
484+
put_unused_fd(new_fd);
469485
return uobj;
470486
}
471487

@@ -539,6 +555,9 @@ static void remove_handle_idr_uobject(struct ib_uobject *uobj)
539555

540556
static void alloc_abort_fd_uobject(struct ib_uobject *uobj)
541557
{
558+
struct file *filp = uobj->object;
559+
560+
fput(filp);
542561
put_unused_fd(uobj->id);
543562
}
544563

@@ -560,7 +579,7 @@ static void remove_handle_fd_uobject(struct ib_uobject *uobj)
560579
{
561580
}
562581

563-
static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
582+
static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
564583
{
565584
struct ib_uverbs_file *ufile = uobj->ufile;
566585
void *old;
@@ -574,31 +593,12 @@ static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
574593
*/
575594
old = xa_store(&ufile->idr, uobj->id, uobj, GFP_KERNEL);
576595
WARN_ON(old != NULL);
577-
578-
return 0;
579596
}
580597

581-
static int alloc_commit_fd_uobject(struct ib_uobject *uobj)
598+
static void alloc_commit_fd_uobject(struct ib_uobject *uobj)
582599
{
583-
const struct uverbs_obj_fd_type *fd_type = container_of(
584-
uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type);
585600
int fd = uobj->id;
586-
struct file *filp;
587-
588-
/*
589-
* The kref for uobj is moved into filp->private data and put in
590-
* uverbs_close_fd(). Once alloc_commit() succeeds
591-
* uverbs_uobject_fd_release() must be guaranteed to be called from
592-
* the provided fops release callback.
593-
*/
594-
filp = anon_inode_getfile(fd_type->name,
595-
fd_type->fops,
596-
uobj,
597-
fd_type->flags);
598-
if (IS_ERR(filp))
599-
return PTR_ERR(filp);
600-
601-
uobj->object = filp;
601+
struct file *filp = uobj->object;
602602

603603
/* Matching put will be done in uverbs_uobject_fd_release() */
604604
kref_get(&uobj->ufile->ref);
@@ -610,29 +610,22 @@ static int alloc_commit_fd_uobject(struct ib_uobject *uobj)
610610
* NOTE: Once we install the file we loose ownership of our kref on
611611
* uobj. It will be put by uverbs_uobject_fd_release()
612612
*/
613+
filp->private_data = uobj;
613614
fd_install(fd, filp);
614-
615-
return 0;
616615
}
617616

618617
/*
619618
* In all cases rdma_alloc_commit_uobject() consumes the kref to uobj and the
620619
* caller can no longer assume uobj is valid. If this function fails it
621620
* destroys the uboject, including the attached HW object.
622621
*/
623-
int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj,
624-
struct uverbs_attr_bundle *attrs)
622+
void rdma_alloc_commit_uobject(struct ib_uobject *uobj,
623+
struct uverbs_attr_bundle *attrs)
625624
{
626625
struct ib_uverbs_file *ufile = attrs->ufile;
627-
int ret;
628626

629627
/* alloc_commit consumes the uobj kref */
630-
ret = uobj->uapi_object->type_class->alloc_commit(uobj);
631-
if (ret) {
632-
uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT, attrs);
633-
up_read(&ufile->hw_destroy_rwsem);
634-
return ret;
635-
}
628+
uobj->uapi_object->type_class->alloc_commit(uobj);
636629

637630
/* kref is held so long as the uobj is on the uobj list. */
638631
uverbs_uobject_get(uobj);
@@ -645,8 +638,6 @@ int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj,
645638

646639
/* Matches the down_read in rdma_alloc_begin_uobject */
647640
up_read(&ufile->hw_destroy_rwsem);
648-
649-
return 0;
650641
}
651642

652643
/*
@@ -658,7 +649,6 @@ void rdma_alloc_abort_uobject(struct ib_uobject *uobj,
658649
{
659650
struct ib_uverbs_file *ufile = uobj->ufile;
660651

661-
uobj->object = NULL;
662652
uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT, attrs);
663653

664654
/* Matches the down_read in rdma_alloc_begin_uobject */
@@ -751,14 +741,23 @@ EXPORT_SYMBOL(uverbs_idr_class);
751741
*/
752742
int uverbs_uobject_fd_release(struct inode *inode, struct file *filp)
753743
{
754-
struct ib_uobject *uobj = filp->private_data;
755-
struct ib_uverbs_file *ufile = uobj->ufile;
756-
struct uverbs_attr_bundle attrs = {
757-
.context = uobj->context,
758-
.ufile = ufile,
759-
};
744+
struct ib_uverbs_file *ufile;
745+
struct ib_uobject *uobj;
746+
747+
/*
748+
* This can only happen if the fput came from alloc_abort_fd_uobject()
749+
*/
750+
if (!filp->private_data)
751+
return 0;
752+
uobj = filp->private_data;
753+
ufile = uobj->ufile;
760754

761755
if (down_read_trylock(&ufile->hw_destroy_rwsem)) {
756+
struct uverbs_attr_bundle attrs = {
757+
.context = uobj->context,
758+
.ufile = ufile,
759+
};
760+
762761
/*
763762
* lookup_get_fd_uobject holds the kref on the struct file any
764763
* time a FD uobj is locked, which prevents this release
@@ -770,7 +769,7 @@ int uverbs_uobject_fd_release(struct inode *inode, struct file *filp)
770769
up_read(&ufile->hw_destroy_rwsem);
771770
}
772771

773-
/* Matches the get in alloc_begin_fd_uobject */
772+
/* Matches the get in alloc_commit_fd_uobject() */
774773
kref_put(&ufile->ref, ib_uverbs_release_file);
775774

776775
/* Pairs with filp->private_data in alloc_begin_fd_uobject */
@@ -938,12 +937,10 @@ uverbs_get_uobject_from_file(u16 object_id, enum uverbs_obj_access access,
938937
}
939938
}
940939

941-
int uverbs_finalize_object(struct ib_uobject *uobj,
942-
enum uverbs_obj_access access, bool commit,
943-
struct uverbs_attr_bundle *attrs)
940+
void uverbs_finalize_object(struct ib_uobject *uobj,
941+
enum uverbs_obj_access access, bool commit,
942+
struct uverbs_attr_bundle *attrs)
944943
{
945-
int ret = 0;
946-
947944
/*
948945
* refcounts should be handled at the object level and not at the
949946
* uobject level. Refcounts of the objects themselves are done in
@@ -963,14 +960,11 @@ int uverbs_finalize_object(struct ib_uobject *uobj,
963960
break;
964961
case UVERBS_ACCESS_NEW:
965962
if (commit)
966-
ret = rdma_alloc_commit_uobject(uobj, attrs);
963+
rdma_alloc_commit_uobject(uobj, attrs);
967964
else
968965
rdma_alloc_abort_uobject(uobj, attrs);
969966
break;
970967
default:
971968
WARN_ON(true);
972-
ret = -EOPNOTSUPP;
973969
}
974-
975-
return ret;
976970
}

drivers/infiniband/core/rdma_core.h

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,24 +63,9 @@ struct ib_uobject *
6363
uverbs_get_uobject_from_file(u16 object_id, enum uverbs_obj_access access,
6464
s64 id, struct uverbs_attr_bundle *attrs);
6565

66-
/*
67-
* Note that certain finalize stages could return a status:
68-
* (a) alloc_commit could return a failure if the object is committed at the
69-
* same time when the context is destroyed.
70-
* (b) remove_commit could fail if the object wasn't destroyed successfully.
71-
* Since multiple objects could be finalized in one transaction, it is very NOT
72-
* recommended to have several finalize actions which have side effects.
73-
* For example, it's NOT recommended to have a certain action which has both
74-
* a commit action and a destroy action or two destroy objects in the same
75-
* action. The rule of thumb is to have one destroy or commit action with
76-
* multiple lookups.
77-
* The first non zero return value of finalize_object is returned from this
78-
* function. For example, this could happen when we couldn't destroy an
79-
* object.
80-
*/
81-
int uverbs_finalize_object(struct ib_uobject *uobj,
82-
enum uverbs_obj_access access, bool commit,
83-
struct uverbs_attr_bundle *attrs);
66+
void uverbs_finalize_object(struct ib_uobject *uobj,
67+
enum uverbs_obj_access access, bool commit,
68+
struct uverbs_attr_bundle *attrs);
8469

8570
int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx);
8671

0 commit comments

Comments
 (0)