IB: refcount race fixes
[powerpc.git] / drivers / infiniband / core / uverbs_cmd.c
index 12d6cc0..9f69bd4 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
+ * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -67,7 +68,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
 
        if (file->ucontext) {
                ret = -EINVAL;
@@ -119,7 +120,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 
        fd_install(resp.async_fd, filp);
 
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        return in_len;
 
@@ -131,7 +132,7 @@ err_free:
        ibdev->dealloc_ucontext(ucontext);
 
 err:
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
        return ret;
 }
 
@@ -157,7 +158,7 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
        memset(&resp, 0, sizeof resp);
 
        resp.fw_ver                    = attr.fw_ver;
-       resp.node_guid                 = attr.node_guid;
+       resp.node_guid                 = file->device->ib_dev->node_guid;
        resp.sys_image_guid            = attr.sys_image_guid;
        resp.max_mr_size               = attr.max_mr_size;
        resp.page_size_cap             = attr.page_size_cap;
@@ -290,7 +291,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
        pd->uobject = uobj;
        atomic_set(&pd->usecnt, 0);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
        if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
@@ -314,11 +315,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->list, &file->ucontext->pd_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -326,7 +327,7 @@ err_idr:
        idr_remove(&ib_uverbs_pd_idr, uobj->id);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        ib_dealloc_pd(pd);
 
 err:
@@ -346,7 +347,7 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext)
@@ -360,14 +361,14 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        kfree(uobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -426,7 +427,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 
        obj->umem.virt_base = cmd.hca_va;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext) {
@@ -476,11 +477,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -492,7 +493,7 @@ err_unreg:
        atomic_dec(&pd->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        ib_umem_release(file->device->ib_dev, &obj->umem);
 
@@ -513,7 +514,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
        if (!mr || mr->uobject->context != file->ucontext)
@@ -527,15 +528,15 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&memobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_umem_release(file->device->ib_dev, &memobj->umem);
        kfree(memobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -594,13 +595,18 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
        if (cmd.comp_vector >= file->device->num_comp_vectors)
                return -EINVAL;
 
-       if (cmd.comp_channel >= 0)
-               ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
-
        uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
        if (!uobj)
                return -ENOMEM;
 
+       if (cmd.comp_channel >= 0) {
+               ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
+               if (!ev_file) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+
        uobj->uobject.user_handle   = cmd.user_handle;
        uobj->uobject.context       = file->ucontext;
        uobj->uverbs_file           = file;
@@ -623,7 +629,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
        cq->cq_context    = ev_file;
        atomic_set(&cq->usecnt, 0);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
        if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
@@ -648,11 +654,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -660,14 +666,56 @@ err_idr:
        idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        ib_destroy_cq(cq);
 
 err:
+       if (ev_file)
+               ib_uverbs_release_ucq(file, ev_file, uobj);
        kfree(uobj);
        return ret;
 }
 
+ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
+                           const char __user *buf, int in_len,
+                           int out_len)
+{
+       struct ib_uverbs_resize_cq      cmd;
+       struct ib_uverbs_resize_cq_resp resp;
+       struct ib_udata                 udata;
+       struct ib_cq                    *cq;
+       int                             ret = -EINVAL;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       INIT_UDATA(&udata, buf + sizeof cmd,
+                  (unsigned long) cmd.response + sizeof resp,
+                  in_len - sizeof cmd, out_len - sizeof resp);
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+       if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq)
+               goto out;
+
+       ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+       resp.cqe = cq->cqe;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                          const char __user *buf, int in_len,
                          int out_len)
@@ -694,7 +742,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                goto out_wc;
        }
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (!cq || cq->uobject->context != file->ucontext) {
                ret = -EINVAL;
@@ -724,7 +772,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        kfree(resp);
 
 out_wc:
@@ -743,14 +791,14 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (cq && cq->uobject->context == file->ucontext) {
                ib_req_notify_cq(cq, cmd.solicited_only ?
                                        IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
                ret = in_len;
        }
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret;
 }
@@ -772,7 +820,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 
        memset(&resp, 0, sizeof resp);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (!cq || cq->uobject->context != file->ucontext)
@@ -788,9 +836,9 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_ucq(file, ev_file, uobj);
 
@@ -804,7 +852,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -838,7 +886,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
@@ -923,11 +971,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -943,12 +991,112 @@ err_destroy:
                atomic_dec(&attr.srq->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
 }
 
+ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
+                          const char __user *buf, int in_len,
+                          int out_len)
+{
+       struct ib_uverbs_query_qp      cmd;
+       struct ib_uverbs_query_qp_resp resp;
+       struct ib_qp                   *qp;
+       struct ib_qp_attr              *attr;
+       struct ib_qp_init_attr         *init_attr;
+       int                            ret;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       attr      = kmalloc(sizeof *attr, GFP_KERNEL);
+       init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
+       if (!attr || !init_attr) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+       if (qp && qp->uobject->context == file->ucontext)
+               ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+
+       resp.qp_state               = attr->qp_state;
+       resp.cur_qp_state           = attr->cur_qp_state;
+       resp.path_mtu               = attr->path_mtu;
+       resp.path_mig_state         = attr->path_mig_state;
+       resp.qkey                   = attr->qkey;
+       resp.rq_psn                 = attr->rq_psn;
+       resp.sq_psn                 = attr->sq_psn;
+       resp.dest_qp_num            = attr->dest_qp_num;
+       resp.qp_access_flags        = attr->qp_access_flags;
+       resp.pkey_index             = attr->pkey_index;
+       resp.alt_pkey_index         = attr->alt_pkey_index;
+       resp.en_sqd_async_notify    = attr->en_sqd_async_notify;
+       resp.max_rd_atomic          = attr->max_rd_atomic;
+       resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
+       resp.min_rnr_timer          = attr->min_rnr_timer;
+       resp.port_num               = attr->port_num;
+       resp.timeout                = attr->timeout;
+       resp.retry_cnt              = attr->retry_cnt;
+       resp.rnr_retry              = attr->rnr_retry;
+       resp.alt_port_num           = attr->alt_port_num;
+       resp.alt_timeout            = attr->alt_timeout;
+
+       memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
+       resp.dest.flow_label        = attr->ah_attr.grh.flow_label;
+       resp.dest.sgid_index        = attr->ah_attr.grh.sgid_index;
+       resp.dest.hop_limit         = attr->ah_attr.grh.hop_limit;
+       resp.dest.traffic_class     = attr->ah_attr.grh.traffic_class;
+       resp.dest.dlid              = attr->ah_attr.dlid;
+       resp.dest.sl                = attr->ah_attr.sl;
+       resp.dest.src_path_bits     = attr->ah_attr.src_path_bits;
+       resp.dest.static_rate       = attr->ah_attr.static_rate;
+       resp.dest.is_global         = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
+       resp.dest.port_num          = attr->ah_attr.port_num;
+
+       memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
+       resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
+       resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
+       resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
+       resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
+       resp.alt_dest.dlid          = attr->alt_ah_attr.dlid;
+       resp.alt_dest.sl            = attr->alt_ah_attr.sl;
+       resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
+       resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
+       resp.alt_dest.is_global     = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
+       resp.alt_dest.port_num      = attr->alt_ah_attr.port_num;
+
+       resp.max_send_wr            = init_attr->cap.max_send_wr;
+       resp.max_recv_wr            = init_attr->cap.max_recv_wr;
+       resp.max_send_sge           = init_attr->cap.max_send_sge;
+       resp.max_recv_sge           = init_attr->cap.max_recv_sge;
+       resp.max_inline_data        = init_attr->cap.max_inline_data;
+       resp.sq_sig_all             = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
+       kfree(attr);
+       kfree(init_attr);
+
+       return ret ? ret : in_len;
+}
+
 ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                            const char __user *buf, int in_len,
                            int out_len)
@@ -965,7 +1113,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        if (!attr)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext) {
@@ -983,7 +1131,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        attr->dest_qp_num         = cmd.dest_qp_num;
        attr->qp_access_flags     = cmd.qp_access_flags;
        attr->pkey_index          = cmd.pkey_index;
-       attr->alt_pkey_index      = cmd.pkey_index;
+       attr->alt_pkey_index      = cmd.alt_pkey_index;
        attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
        attr->max_rd_atomic       = cmd.max_rd_atomic;
        attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
@@ -1026,7 +1174,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        ret = in_len;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        kfree(attr);
 
        return ret;
@@ -1047,7 +1195,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
        memset(&resp, 0, sizeof resp);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1066,9 +1214,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uevent.uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_uevent(file, &uobj->uevent);
 
@@ -1081,14 +1229,14 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
 
 ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                           const char __user *buf, int in_len,
+                           int out_len)
 {
        struct ib_uverbs_post_send      cmd;
        struct ib_uverbs_post_send_resp resp;
@@ -1112,7 +1260,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
        if (!user_wr)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1217,7 +1365,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1316,8 +1464,8 @@ err:
 }
 
 ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                           const char __user *buf, int in_len,
+                           int out_len)
 {
        struct ib_uverbs_post_recv      cmd;
        struct ib_uverbs_post_recv_resp resp;
@@ -1334,7 +1482,7 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
        if (IS_ERR(wr))
                return PTR_ERR(wr);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1355,7 +1503,7 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1367,8 +1515,8 @@ out:
 }
 
 ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
-                            const char __user *buf, int in_len,
-                            int out_len)
+                               const char __user *buf, int in_len,
+                               int out_len)
 {
        struct ib_uverbs_post_srq_recv      cmd;
        struct ib_uverbs_post_srq_recv_resp resp;
@@ -1385,7 +1533,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
        if (IS_ERR(wr))
                return PTR_ERR(wr);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
        if (!srq || srq->uobject->context != file->ucontext)
@@ -1406,7 +1554,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1439,7 +1587,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext) {
@@ -1491,11 +1639,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->list, &file->ucontext->ah_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -1506,7 +1654,7 @@ err_destroy:
        ib_destroy_ah(ah);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
@@ -1523,7 +1671,7 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle);
        if (!ah || ah->uobject->context != file->ucontext)
@@ -1537,14 +1685,14 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        kfree(uobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1562,7 +1710,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1595,7 +1743,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
                kfree(mcast);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1613,7 +1761,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1634,7 +1782,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
                }
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1666,7 +1814,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 
@@ -1716,6 +1864,8 @@ retry:
                goto err_destroy;
 
        resp.srq_handle = uobj->uobject.id;
+       resp.max_wr     = attr.attr.max_wr;
+       resp.max_sge    = attr.attr.max_sge;
 
        if (copy_to_user((void __user *) (unsigned long) cmd.response,
                         &resp, sizeof resp)) {
@@ -1723,11 +1873,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -1739,7 +1889,7 @@ err_destroy:
        atomic_dec(&pd->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
@@ -1757,7 +1907,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
        if (!srq || srq->uobject->context != file->ucontext) {
@@ -1771,8 +1921,51 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
        ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       return ret ? ret : in_len;
+}
 
+ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
+                           const char __user *buf,
+                           int in_len, int out_len)
+{
+       struct ib_uverbs_query_srq      cmd;
+       struct ib_uverbs_query_srq_resp resp;
+       struct ib_srq_attr              attr;
+       struct ib_srq                   *srq;
+       int                             ret;
+
+       if (out_len < sizeof resp)
+               return -ENOSPC;
+
+       if (copy_from_user(&cmd, buf, sizeof cmd))
+               return -EFAULT;
+
+       mutex_lock(&ib_uverbs_idr_mutex);
+
+       srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
+       if (srq && srq->uobject->context == file->ucontext)
+               ret = ib_query_srq(srq, &attr);
+       else
+               ret = -EINVAL;
+
+       mutex_unlock(&ib_uverbs_idr_mutex);
+
+       if (ret)
+               goto out;
+
+       memset(&resp, 0, sizeof resp);
+
+       resp.max_wr    = attr.max_wr;
+       resp.max_sge   = attr.max_sge;
+       resp.srq_limit = attr.srq_limit;
+
+       if (copy_to_user((void __user *) (unsigned long) cmd.response,
+                        &resp, sizeof resp))
+               ret = -EFAULT;
+
+out:
        return ret ? ret : in_len;
 }
 
@@ -1789,7 +1982,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        memset(&resp, 0, sizeof resp);
 
@@ -1805,9 +1998,9 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_uevent(file, uobj);
 
@@ -1820,7 +2013,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }