📄 uverbs_cmd.c
字号:
/* * Copyright (c) 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Cisco Systems. All rights reserved. * Copyright (c) 2005 PathScale, Inc. 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 * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $ */#include <linux/file.h>#include <linux/fs.h>#include <asm/uaccess.h>#include "uverbs.h"#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ do { \ (udata)->inbuf = (void __user *) (ibuf); \ (udata)->outbuf = (void __user *) (obuf); \ (udata)->inlen = (ilen); \ (udata)->outlen = (olen); \ } while (0)ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_get_context cmd; struct ib_uverbs_get_context_resp resp; struct ib_udata udata; struct ib_device *ibdev = file->device->ib_dev; struct ib_ucontext *ucontext; struct file *filp; int ret; if (out_len < sizeof resp) return -ENOSPC; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; down(&file->mutex); if (file->ucontext) { ret = -EINVAL; goto err; } INIT_UDATA(&udata, buf + sizeof cmd, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); ucontext = ibdev->alloc_ucontext(ibdev, &udata); if (IS_ERR(ucontext)) return PTR_ERR(file->ucontext); ucontext->device = ibdev; INIT_LIST_HEAD(&ucontext->pd_list); INIT_LIST_HEAD(&ucontext->mr_list); INIT_LIST_HEAD(&ucontext->mw_list); INIT_LIST_HEAD(&ucontext->cq_list); INIT_LIST_HEAD(&ucontext->qp_list); INIT_LIST_HEAD(&ucontext->srq_list); INIT_LIST_HEAD(&ucontext->ah_list); resp.num_comp_vectors = file->device->num_comp_vectors; filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); if (IS_ERR(filp)) { ret = PTR_ERR(filp); goto err_free; } if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; goto err_file; } file->async_file = filp->private_data; INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, ib_uverbs_event_handler); ret = ib_register_event_handler(&file->event_handler); if (ret) goto err_file; kref_get(&file->async_file->ref); kref_get(&file->ref); file->ucontext = ucontext; fd_install(resp.async_fd, filp); up(&file->mutex); return in_len;err_file: put_unused_fd(resp.async_fd); fput(filp);err_free: ibdev->dealloc_ucontext(ucontext);err: up(&file->mutex); return ret;}ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_query_device cmd; struct ib_uverbs_query_device_resp resp; struct ib_device_attr attr; int ret; if (out_len < sizeof resp) return -ENOSPC; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; ret = ib_query_device(file->device->ib_dev, &attr); if (ret) return ret; memset(&resp, 0, sizeof resp); resp.fw_ver = attr.fw_ver; resp.node_guid = attr.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; resp.vendor_id = attr.vendor_id; resp.vendor_part_id = attr.vendor_part_id; resp.hw_ver = attr.hw_ver; resp.max_qp = attr.max_qp; resp.max_qp_wr = attr.max_qp_wr; resp.device_cap_flags = attr.device_cap_flags; resp.max_sge = attr.max_sge; resp.max_sge_rd = attr.max_sge_rd; resp.max_cq = attr.max_cq; resp.max_cqe = attr.max_cqe; resp.max_mr = attr.max_mr; resp.max_pd = attr.max_pd; resp.max_qp_rd_atom = attr.max_qp_rd_atom; resp.max_ee_rd_atom = attr.max_ee_rd_atom; resp.max_res_rd_atom = attr.max_res_rd_atom; resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom; resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom; resp.atomic_cap = attr.atomic_cap; resp.max_ee = attr.max_ee; resp.max_rdd = attr.max_rdd; resp.max_mw = attr.max_mw; resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp; resp.max_raw_ethy_qp = attr.max_raw_ethy_qp; resp.max_mcast_grp = attr.max_mcast_grp; resp.max_mcast_qp_attach = attr.max_mcast_qp_attach; resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach; resp.max_ah = attr.max_ah; resp.max_fmr = attr.max_fmr; resp.max_map_per_fmr = attr.max_map_per_fmr; resp.max_srq = attr.max_srq; resp.max_srq_wr = attr.max_srq_wr; resp.max_srq_sge = attr.max_srq_sge; resp.max_pkeys = attr.max_pkeys; resp.local_ca_ack_delay = attr.local_ca_ack_delay; resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) return -EFAULT; return in_len;}ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_query_port cmd; struct ib_uverbs_query_port_resp resp; struct ib_port_attr attr; int ret; if (out_len < sizeof resp) return -ENOSPC; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr); if (ret) return ret; memset(&resp, 0, sizeof resp); resp.state = attr.state; resp.max_mtu = attr.max_mtu; resp.active_mtu = attr.active_mtu; resp.gid_tbl_len = attr.gid_tbl_len; resp.port_cap_flags = attr.port_cap_flags; resp.max_msg_sz = attr.max_msg_sz; resp.bad_pkey_cntr = attr.bad_pkey_cntr; resp.qkey_viol_cntr = attr.qkey_viol_cntr; resp.pkey_tbl_len = attr.pkey_tbl_len; resp.lid = attr.lid; resp.sm_lid = attr.sm_lid; resp.lmc = attr.lmc; resp.max_vl_num = attr.max_vl_num; resp.sm_sl = attr.sm_sl; resp.subnet_timeout = attr.subnet_timeout; resp.init_type_reply = attr.init_type_reply; resp.active_width = attr.active_width; resp.active_speed = attr.active_speed; resp.phys_state = attr.phys_state; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) return -EFAULT; return in_len;}ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_alloc_pd cmd; struct ib_uverbs_alloc_pd_resp resp; struct ib_udata udata; struct ib_uobject *uobj; struct ib_pd *pd; int ret; if (out_len < sizeof resp) return -ENOSPC; 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); uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; uobj->context = file->ucontext; pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, file->ucontext, &udata); if (IS_ERR(pd)) { ret = PTR_ERR(pd); goto err; } pd->device = file->device->ib_dev; pd->uobject = uobj; atomic_set(&pd->usecnt, 0); down(&ib_uverbs_idr_mutex);retry: if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) { ret = -ENOMEM; goto err_up; } ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id); if (ret == -EAGAIN) goto retry; if (ret) goto err_up; memset(&resp, 0, sizeof resp); resp.pd_handle = uobj->id; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; goto err_idr; } down(&file->mutex); list_add_tail(&uobj->list, &file->ucontext->pd_list); up(&file->mutex); up(&ib_uverbs_idr_mutex); return in_len;err_idr: idr_remove(&ib_uverbs_pd_idr, uobj->id);err_up: up(&ib_uverbs_idr_mutex); ib_dealloc_pd(pd);err: kfree(uobj); return ret;}ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_dealloc_pd cmd; struct ib_pd *pd; struct ib_uobject *uobj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; down(&ib_uverbs_idr_mutex); pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); if (!pd || pd->uobject->context != file->ucontext) goto out; uobj = pd->uobject; ret = ib_dealloc_pd(pd); if (ret) goto out; idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); down(&file->mutex); list_del(&uobj->list); up(&file->mutex); kfree(uobj);out: up(&ib_uverbs_idr_mutex); return ret ? ret : in_len;}ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_reg_mr cmd; struct ib_uverbs_reg_mr_resp resp; struct ib_udata udata; struct ib_umem_object *obj; struct ib_pd *pd; struct ib_mr *mr; int ret; if (out_len < sizeof resp) return -ENOSPC; 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); if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) return -EINVAL; /* * Local write permission is required if remote write or * remote atomic permission is also requested. */ if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) && !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) return -EINVAL; obj = kmalloc(sizeof *obj, GFP_KERNEL); if (!obj) return -ENOMEM; obj->uobject.context = file->ucontext; /* * We ask for writable memory if any access flags other than * "remote read" are set. "Local write" and "remote write" * obviously require write access. "Remote atomic" can do * things like fetch and add, which will modify memory, and * "MW bind" can change permissions by binding a window. */ ret = ib_umem_get(file->device->ib_dev, &obj->umem, (void *) (unsigned long) cmd.start, cmd.length, !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ)); if (ret) goto err_free; obj->umem.virt_base = cmd.hca_va; down(&ib_uverbs_idr_mutex); pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); if (!pd || pd->uobject->context != file->ucontext) { ret = -EINVAL; goto err_up; } if (!pd->device->reg_user_mr) { ret = -ENOSYS; goto err_up; } mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); if (IS_ERR(mr)) { ret = PTR_ERR(mr); goto err_up; } mr->device = pd->device; mr->pd = pd; mr->uobject = &obj->uobject; atomic_inc(&pd->usecnt); atomic_set(&mr->usecnt, 0); memset(&resp, 0, sizeof resp); resp.lkey = mr->lkey; resp.rkey = mr->rkey;retry: if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) { ret = -ENOMEM; goto err_unreg; } ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id); if (ret == -EAGAIN) goto retry; if (ret) goto err_unreg; resp.mr_handle = obj->uobject.id; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { ret = -EFAULT; goto err_idr; } down(&file->mutex); list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); up(&file->mutex); up(&ib_uverbs_idr_mutex); return in_len;err_idr: idr_remove(&ib_uverbs_mr_idr, obj->uobject.id);err_unreg: ib_dereg_mr(mr);err_up: up(&ib_uverbs_idr_mutex); ib_umem_release(file->device->ib_dev, &obj->umem);err_free: kfree(obj); return ret;}ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_dereg_mr cmd; struct ib_mr *mr; struct ib_umem_object *memobj; int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; down(&ib_uverbs_idr_mutex); mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle); if (!mr || mr->uobject->context != file->ucontext) goto out; memobj = container_of(mr->uobject, struct ib_umem_object, uobject); ret = ib_dereg_mr(mr); if (ret) goto out; idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); down(&file->mutex); list_del(&memobj->uobject.list); up(&file->mutex); ib_umem_release(file->device->ib_dev, &memobj->umem); kfree(memobj);out: up(&ib_uverbs_idr_mutex); return ret ? ret : in_len;}ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_create_comp_channel cmd; struct ib_uverbs_create_comp_channel_resp resp; struct file *filp; if (out_len < sizeof resp) return -ENOSPC; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); if (IS_ERR(filp)) return PTR_ERR(filp); if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { put_unused_fd(resp.fd); fput(filp); return -EFAULT; } fd_install(resp.fd, filp); return in_len;}ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len){ struct ib_uverbs_create_cq cmd; struct ib_uverbs_create_cq_resp resp; struct ib_udata udata; struct ib_ucq_object *uobj; struct ib_uverbs_event_file *ev_file = NULL; struct ib_cq *cq; int ret; if (out_len < sizeof resp) return -ENOSPC; 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); 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; uobj->uobject.user_handle = cmd.user_handle; uobj->uobject.context = file->ucontext; uobj->uverbs_file = file; uobj->comp_events_reported = 0; uobj->async_events_reported = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -