On Tue, Jun 18, 2019 at 08:26:14PM +0300, Leon Romanovsky wrote:

> +/**
> + * rdma_counter_bind_qp_auto - Check and bind the QP to a counter base on
> + *   the auto-mode rule
> + */
> +int rdma_counter_bind_qp_auto(struct ib_qp *qp, u8 port)
> +{
> +     struct rdma_port_counter *port_counter;
> +     struct ib_device *dev = qp->device;
> +     struct rdma_counter *counter;
> +     int ret;
> +
> +     if (!rdma_is_port_valid(dev, port))
> +             return -EINVAL;
> +
> +     port_counter = &dev->port_data[port].port_counter;
> +     if (port_counter->mode.mode != RDMA_COUNTER_MODE_AUTO)
> +             return 0;
> +
> +     counter = rdma_get_counter_auto_mode(qp, port);
> +     if (counter) {
> +             ret = __rdma_counter_bind_qp(counter, qp);
> +             if (ret) {
> +                     rdma_restrack_put(&counter->res);
> +                     return ret;
> +             }
> +             kref_get(&counter->kref);

The counter is left in the xarray while the kref is zero, this
kref_get is wrong..

Using two kref like things at the same time is a bad idea, the
'rdma_get_counter_auto_mode' should return the kref held, not the
restrack get. The restrack_del doesn't happen as long as the kref is
positive, so we don't need the retrack thing here..

> +     } else {
> +             counter = rdma_counter_alloc(dev, port, RDMA_COUNTER_MODE_AUTO);
> +             if (!counter)
> +                     return -ENOMEM;
> +
> +             auto_mode_init_counter(counter, qp, port_counter->mode.mask);
> +
> +             ret = __rdma_counter_bind_qp(counter, qp);
> +             if (ret)
> +                     goto err_bind;
> +
> +             rdma_counter_res_add(counter, qp);
> +             if (!rdma_restrack_get(&counter->res)) {
> +                     ret = -EINVAL;
> +                     goto err_get;
> +             }

and this shouldn't be needed as the kref is inited to 1 by the
rdma_counter_alloc..

> +     }
> +
> +     return 0;
> +
> +err_get:
> +      __rdma_counter_unbind_qp(qp);
> +     __rdma_counter_dealloc(counter);
> +err_bind:
> +     rdma_counter_free(counter);
> +     return ret;
> +}

And then all this error unwind and all the twisty __ functions should
just be a single kref_put and the release should handle everything.

Jason

Reply via email to