From: Arun Kaimalettu Date: Mon, 18 Jul 2011 12:21:34 +0000 (+0300) Subject: ib/core: init shared-pd ref count to 1, and add cleanup X-Git-Tag: v4.1.12-92~281^2^2~6 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=557de4896556e7e228330143457b6f626db2b844;p=users%2Fjedix%2Flinux-maple.git ib/core: init shared-pd ref count to 1, and add cleanup When shpd is created it is already referred to by parent 'pd', so shpd->shared should be '1' initially (and not '0'); otherwise, the 'shpd' memory may get freed/reallocated while it is still being referred to by one last pd. Additionally, add shared-pd cleanup to ucontext cleanup flow. Orabug: 21496696 Signed-off-by: Arun Kaimalettu Signed-off-by: Jack Morgenstein (Ported from UEK2/OFED 1.5.5) Signed-off-by: Mukesh Kacker --- diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 2f5d5441f7673..ccb9270f0557a 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -663,6 +663,8 @@ ssize_t ib_uverbs_alloc_shpd(struct ib_uverbs_file *file, shpd->device = file->device->ib_dev; shpd->uobject = shuobj; shpd->share_key = cmd.share_key; + /* initialize shared count for this shpd */ + atomic_set(&shpd->shared, 1); shuobj->object = shpd; @@ -848,10 +850,9 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, if (!ret && shpd) { down_write(&shuobj->mutex); - atomic_dec(&shpd->shared); /* if this shpd is no longer shared */ - if (!atomic_read(&shpd->shared)) { + if (atomic_dec_and_test(&shpd->shared)) { /* free the shpd info from device driver */ file->device->ib_dev->remove_shpd(file->device->ib_dev, shpd, 0); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 32c654abfc2f5..ca4e0cc234dea 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -137,6 +137,16 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); +static void release_uobj(struct kref *kref) +{ + kfree(container_of(kref, struct ib_uobject, ref)); +} + +static void put_uobj(struct ib_uobject *uobj) +{ + kref_put(&uobj->ref, release_uobj); +} + static void ib_uverbs_release_dev(struct kref *ref) { struct ib_uverbs_device *dev = @@ -304,9 +314,39 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { struct ib_pd *pd = uobj->object; + struct ib_uobject *shuobj = NULL; + struct ib_shpd *shpd = NULL; idr_remove_uobj(&ib_uverbs_pd_idr, uobj); + + /* is pd shared ?*/ + if (pd->shpd) { + shpd = pd->shpd; + shuobj = shpd->uobject; + } + ib_dealloc_pd(pd); + + if (shpd) { + + down_write(&shuobj->mutex); + + /* if this shpd is no longer shared */ + if (atomic_dec_and_test(&shpd->shared)) { + /* free the shpd info from device driver */ + file->device->ib_dev->remove_shpd( + file->device->ib_dev, shpd, 0); + shuobj->live = 0; + up_write(&shuobj->mutex); + idr_remove_uobj(&ib_uverbs_shpd_idr, shuobj); + /* + * there could some one waiting to + * lock this shared object + */ + put_uobj(shuobj); + } else + up_write(&shuobj->mutex); + } kfree(uobj); }