Skip to content

Commit aba9454

Browse files
committed
IB/uverbs: Move the FD uobj type struct file allocation to alloc_commit
Allocating the struct file during alloc_begin creates this strange asymmetry with IDR, where the FD has two krefs pointing at it during the pre-commit phase. In particular this makes the abort process for FD very strange and confusing. For instance abort currently calls the type's destroy_object twice, and the fops release once if abort is done. This is very counter intuitive. No fops should be called until alloc_commit succeeds, and destroy_object should only ever be called once. Moving the struct file allocation to the alloc_commit is now simple, as we already support failure of rdma_alloc_commit_uobject, with all the required rollback pieces. This creates an understandable symmetry with IDR and simplifies/fixes the abort handling for FD types. Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 2c96eb7 commit aba9454

File tree

2 files changed

+47
-38
lines changed

2 files changed

+47
-38
lines changed

drivers/infiniband/core/rdma_core.c

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,8 @@ static struct ib_uobject *alloc_begin_idr_uobject(const struct uverbs_obj_type *
328328
static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *type,
329329
struct ib_uverbs_file *ufile)
330330
{
331-
const struct uverbs_obj_fd_type *fd_type =
332-
container_of(type, struct uverbs_obj_fd_type, type);
333331
int new_fd;
334332
struct ib_uobject *uobj;
335-
struct file *filp;
336333

337334
new_fd = get_unused_fd_flags(O_CLOEXEC);
338335
if (new_fd < 0)
@@ -344,28 +341,8 @@ static struct ib_uobject *alloc_begin_fd_uobject(const struct uverbs_obj_type *t
344341
return uobj;
345342
}
346343

347-
/*
348-
* The kref for uobj is moved into filp->private data and put in
349-
* uverbs_close_fd(). Once anon_inode_getfile() succeeds
350-
* uverbs_close_fd() must be guaranteed to be called from the provided
351-
* fops release callback. We piggyback our kref of uobj on the stack
352-
* with the lifetime of the struct file.
353-
*/
354-
filp = anon_inode_getfile(fd_type->name,
355-
fd_type->fops,
356-
uobj,
357-
fd_type->flags);
358-
if (IS_ERR(filp)) {
359-
put_unused_fd(new_fd);
360-
uverbs_uobject_put(uobj);
361-
return (void *)filp;
362-
}
363-
364344
uobj->id = new_fd;
365-
uobj->object = filp;
366345
uobj->ufile = ufile;
367-
/* Matching put will be done in uverbs_close_fd() */
368-
kref_get(&ufile->ref);
369346

370347
return uobj;
371348
}
@@ -407,12 +384,10 @@ static int __must_check remove_commit_idr_uobject(struct ib_uobject *uobj,
407384

408385
static void alloc_abort_fd_uobject(struct ib_uobject *uobj)
409386
{
410-
struct file *filp = uobj->object;
411-
int id = uobj->id;
387+
put_unused_fd(uobj->id);
412388

413-
/* Unsuccessful NEW */
414-
fput(filp);
415-
put_unused_fd(id);
389+
/* Pairs with the kref from alloc_begin_idr_uobject */
390+
uverbs_uobject_put(uobj);
416391
}
417392

418393
static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj,
@@ -500,7 +475,7 @@ int rdma_explicit_destroy(struct ib_uobject *uobject)
500475
return ret;
501476
}
502477

503-
static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
478+
static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
504479
{
505480
struct ib_uverbs_file *ufile = uobj->ufile;
506481

@@ -514,11 +489,34 @@ static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
514489
*/
515490
WARN_ON(idr_replace(&ufile->idr, uobj, uobj->id));
516491
spin_unlock(&ufile->idr_lock);
492+
493+
return 0;
517494
}
518495

519-
static void alloc_commit_fd_uobject(struct ib_uobject *uobj)
496+
static int alloc_commit_fd_uobject(struct ib_uobject *uobj)
520497
{
498+
const struct uverbs_obj_fd_type *fd_type =
499+
container_of(uobj->type, struct uverbs_obj_fd_type, type);
521500
int fd = uobj->id;
501+
struct file *filp;
502+
503+
/*
504+
* The kref for uobj is moved into filp->private data and put in
505+
* uverbs_close_fd(). Once alloc_commit() succeeds uverbs_close_fd()
506+
* must be guaranteed to be called from the provided fops release
507+
* callback.
508+
*/
509+
filp = anon_inode_getfile(fd_type->name,
510+
fd_type->fops,
511+
uobj,
512+
fd_type->flags);
513+
if (IS_ERR(filp))
514+
return PTR_ERR(filp);
515+
516+
uobj->object = filp;
517+
518+
/* Matching put will be done in uverbs_close_fd() */
519+
kref_get(&uobj->ufile->ref);
522520

523521
/* This shouldn't be used anymore. Use the file object instead */
524522
uobj->id = 0;
@@ -527,7 +525,9 @@ static void alloc_commit_fd_uobject(struct ib_uobject *uobj)
527525
* NOTE: Once we install the file we loose ownership of our kref on
528526
* uobj. It will be put by uverbs_close_fd()
529527
*/
530-
fd_install(fd, uobj->object);
528+
fd_install(fd, filp);
529+
530+
return 0;
531531
}
532532

533533
/*
@@ -538,11 +538,10 @@ static void alloc_commit_fd_uobject(struct ib_uobject *uobj)
538538
int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj)
539539
{
540540
struct ib_uverbs_file *ufile = uobj->ufile;
541+
int ret;
541542

542543
/* Cleanup is running. Calling this should have been impossible */
543544
if (!down_read_trylock(&ufile->hw_destroy_rwsem)) {
544-
int ret;
545-
546545
WARN(true, "ib_uverbs: Cleanup is running while allocating an uobject\n");
547546
ret = uobj->type->type_class->remove_commit(uobj,
548547
RDMA_REMOVE_DURING_CLEANUP);
@@ -552,18 +551,28 @@ int __must_check rdma_alloc_commit_uobject(struct ib_uobject *uobj)
552551
return ret;
553552
}
554553

555-
/* matches atomic_set(-1) in alloc_uobj */
556554
assert_uverbs_usecnt(uobj, true);
557-
atomic_set(&uobj->usecnt, 0);
555+
556+
/* alloc_commit consumes the uobj kref */
557+
ret = uobj->type->type_class->alloc_commit(uobj);
558+
if (ret) {
559+
if (uobj->type->type_class->remove_commit(
560+
uobj, RDMA_REMOVE_DURING_CLEANUP))
561+
pr_warn("ib_uverbs: cleanup of idr object %d failed\n",
562+
uobj->id);
563+
up_read(&ufile->hw_destroy_rwsem);
564+
return ret;
565+
}
558566

559567
/* kref is held so long as the uobj is on the uobj list. */
560568
uverbs_uobject_get(uobj);
561569
spin_lock_irq(&ufile->uobjects_lock);
562570
list_add(&uobj->list, &ufile->uobjects);
563571
spin_unlock_irq(&ufile->uobjects_lock);
564572

565-
/* alloc_commit consumes the uobj kref */
566-
uobj->type->type_class->alloc_commit(uobj);
573+
/* matches atomic_set(-1) in alloc_uobj */
574+
atomic_set(&uobj->usecnt, 0);
575+
567576
up_read(&ufile->hw_destroy_rwsem);
568577

569578
return 0;

include/rdma/uverbs_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ struct uverbs_obj_type_class {
7373
*/
7474
struct ib_uobject *(*alloc_begin)(const struct uverbs_obj_type *type,
7575
struct ib_uverbs_file *ufile);
76-
void (*alloc_commit)(struct ib_uobject *uobj);
76+
int (*alloc_commit)(struct ib_uobject *uobj);
7777
void (*alloc_abort)(struct ib_uobject *uobj);
7878

7979
struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type,

0 commit comments

Comments
 (0)