user_mad.c

来自「linux 内核源代码」· C语言 代码 · 共 1,219 行 · 第 1/3 页

C
1,219
字号
	if (hdr1->grh_present && hdr2->grh_present)	   return !memcmp(hdr1->gid, hdr2->gid, 16);	return 0;}static int is_duplicate(struct ib_umad_file *file,			struct ib_umad_packet *packet){	struct ib_umad_packet *sent_packet;	struct ib_mad_hdr *sent_hdr, *hdr;	hdr = (struct ib_mad_hdr *) packet->mad.data;	list_for_each_entry(sent_packet, &file->send_list, list) {		sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data;		if ((hdr->tid != sent_hdr->tid) ||		    (hdr->mgmt_class != sent_hdr->mgmt_class))			continue;		/*		 * No need to be overly clever here.  If two new operations have		 * the same TID, reject the second as a duplicate.  This is more		 * restrictive than required by the spec.		 */		if (!ib_response_mad((struct ib_mad *) hdr)) {			if (!ib_response_mad((struct ib_mad *) sent_hdr))				return 1;			continue;		} else if (!ib_response_mad((struct ib_mad *) sent_hdr))			continue;		if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr))			return 1;	}	return 0;}static ssize_t ib_umad_write(struct file *filp, const char __user *buf,			     size_t count, loff_t *pos){	struct ib_umad_file *file = filp->private_data;	struct ib_umad_packet *packet;	struct ib_mad_agent *agent;	struct ib_ah_attr ah_attr;	struct ib_ah *ah;	struct ib_rmpp_mad *rmpp_mad;	__be64 *tid;	int ret, data_len, hdr_len, copy_offset, rmpp_active;	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)		return -EINVAL;	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);	if (!packet)		return -ENOMEM;	if (copy_from_user(&packet->mad, buf, hdr_size(file))) {		ret = -EFAULT;		goto err;	}	if (packet->mad.hdr.id < 0 ||	    packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {		ret = -EINVAL;		goto err;	}	buf += hdr_size(file);	if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {		ret = -EFAULT;		goto err;	}	down_read(&file->port->mutex);	agent = __get_agent(file, packet->mad.hdr.id);	if (!agent) {		ret = -EINVAL;		goto err_up;	}	memset(&ah_attr, 0, sizeof ah_attr);	ah_attr.dlid          = be16_to_cpu(packet->mad.hdr.lid);	ah_attr.sl            = packet->mad.hdr.sl;	ah_attr.src_path_bits = packet->mad.hdr.path_bits;	ah_attr.port_num      = file->port->port_num;	if (packet->mad.hdr.grh_present) {		ah_attr.ah_flags = IB_AH_GRH;		memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);		ah_attr.grh.sgid_index	   = packet->mad.hdr.gid_index;		ah_attr.grh.flow_label 	   = be32_to_cpu(packet->mad.hdr.flow_label);		ah_attr.grh.hop_limit  	   = packet->mad.hdr.hop_limit;		ah_attr.grh.traffic_class  = packet->mad.hdr.traffic_class;	}	ah = ib_create_ah(agent->qp->pd, &ah_attr);	if (IS_ERR(ah)) {		ret = PTR_ERR(ah);		goto err_up;	}	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);	if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) {		copy_offset = IB_MGMT_MAD_HDR;		rmpp_active = 0;	} else {		copy_offset = IB_MGMT_RMPP_HDR;		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &			      IB_MGMT_RMPP_FLAG_ACTIVE;	}	data_len = count - hdr_size(file) - hdr_len;	packet->msg = ib_create_send_mad(agent,					 be32_to_cpu(packet->mad.hdr.qpn),					 packet->mad.hdr.pkey_index, rmpp_active,					 hdr_len, data_len, GFP_KERNEL);	if (IS_ERR(packet->msg)) {		ret = PTR_ERR(packet->msg);		goto err_ah;	}	packet->msg->ah 	= ah;	packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;	packet->msg->retries 	= packet->mad.hdr.retries;	packet->msg->context[0] = packet;	/* Copy MAD header.  Any RMPP header is already in place. */	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);	if (!rmpp_active) {		if (copy_from_user(packet->msg->mad + copy_offset,				   buf + copy_offset,				   hdr_len + data_len - copy_offset)) {			ret = -EFAULT;			goto err_msg;		}	} else {		ret = copy_rmpp_mad(packet->msg, buf);		if (ret)			goto err_msg;	}	/*	 * Set the high-order part of the transaction ID to make MADs from	 * different agents unique, and allow routing responses back to the	 * original requestor.	 */	if (!ib_response_mad(packet->msg->mad)) {		tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;		*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |				   (be64_to_cpup(tid) & 0xffffffff));		rmpp_mad->mad_hdr.tid = *tid;	}	spin_lock_irq(&file->send_lock);	ret = is_duplicate(file, packet);	if (!ret)		list_add_tail(&packet->list, &file->send_list);	spin_unlock_irq(&file->send_lock);	if (ret) {		ret = -EINVAL;		goto err_msg;	}	ret = ib_post_send_mad(packet->msg, NULL);	if (ret)		goto err_send;	up_read(&file->port->mutex);	return count;err_send:	dequeue_send(file, packet);err_msg:	ib_free_send_mad(packet->msg);err_ah:	ib_destroy_ah(ah);err_up:	up_read(&file->port->mutex);err:	kfree(packet);	return ret;}static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wait){	struct ib_umad_file *file = filp->private_data;	/* we will always be able to post a MAD send */	unsigned int mask = POLLOUT | POLLWRNORM;	poll_wait(filp, &file->recv_wait, wait);	if (!list_empty(&file->recv_list))		mask |= POLLIN | POLLRDNORM;	return mask;}static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,			     int compat_method_mask){	struct ib_user_mad_reg_req ureq;	struct ib_mad_reg_req req;	struct ib_mad_agent *agent;	int agent_id;	int ret;	down_write(&file->port->mutex);	if (!file->port->ib_dev) {		ret = -EPIPE;		goto out;	}	if (copy_from_user(&ureq, arg, sizeof ureq)) {		ret = -EFAULT;		goto out;	}	if (ureq.qpn != 0 && ureq.qpn != 1) {		ret = -EINVAL;		goto out;	}	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)		if (!__get_agent(file, agent_id))			goto found;	ret = -ENOMEM;	goto out;found:	if (ureq.mgmt_class) {		req.mgmt_class         = ureq.mgmt_class;		req.mgmt_class_version = ureq.mgmt_class_version;		memcpy(req.oui, ureq.oui, sizeof req.oui);		if (compat_method_mask) {			u32 *umm = (u32 *) ureq.method_mask;			int i;			for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)				req.method_mask[i] =					umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);		} else			memcpy(req.method_mask, ureq.method_mask,			       sizeof req.method_mask);	}	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,				      ureq.mgmt_class ? &req : NULL,				      ureq.rmpp_version,				      send_handler, recv_handler, file);	if (IS_ERR(agent)) {		ret = PTR_ERR(agent);		goto out;	}	if (put_user(agent_id,		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {		ret = -EFAULT;		ib_unregister_mad_agent(agent);		goto out;	}	if (!file->already_used) {		file->already_used = 1;		if (!file->use_pkey_index) {			printk(KERN_WARNING "user_mad: process %s did not enable "			       "P_Key index support.\n", current->comm);			printk(KERN_WARNING "user_mad:   Documentation/infiniband/user_mad.txt "			       "has info on the new ABI.\n");		}	}	file->agent[agent_id] = agent;	ret = 0;out:	up_write(&file->port->mutex);	return ret;}static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg){	struct ib_mad_agent *agent = NULL;	u32 id;	int ret = 0;	if (get_user(id, arg))		return -EFAULT;	down_write(&file->port->mutex);	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {		ret = -EINVAL;		goto out;	}	agent = file->agent[id];	file->agent[id] = NULL;out:	up_write(&file->port->mutex);	if (agent)		ib_unregister_mad_agent(agent);	return ret;}static long ib_umad_enable_pkey(struct ib_umad_file *file){	int ret = 0;	down_write(&file->port->mutex);	if (file->already_used)		ret = -EINVAL;	else		file->use_pkey_index = 1;	up_write(&file->port->mutex);	return ret;}static long ib_umad_ioctl(struct file *filp, unsigned int cmd,			  unsigned long arg){	switch (cmd) {	case IB_USER_MAD_REGISTER_AGENT:		return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);	case IB_USER_MAD_UNREGISTER_AGENT:		return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);	case IB_USER_MAD_ENABLE_PKEY:		return ib_umad_enable_pkey(filp->private_data);	default:		return -ENOIOCTLCMD;	}}#ifdef CONFIG_COMPATstatic long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,				 unsigned long arg){	switch (cmd) {	case IB_USER_MAD_REGISTER_AGENT:		return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);	case IB_USER_MAD_UNREGISTER_AGENT:		return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));	case IB_USER_MAD_ENABLE_PKEY:		return ib_umad_enable_pkey(filp->private_data);	default:		return -ENOIOCTLCMD;	}}#endifstatic int ib_umad_open(struct inode *inode, struct file *filp){	struct ib_umad_port *port;	struct ib_umad_file *file;	int ret = 0;	spin_lock(&port_lock);	port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE];	if (port)		kref_get(&port->umad_dev->ref);	spin_unlock(&port_lock);	if (!port)		return -ENXIO;	down_write(&port->mutex);	if (!port->ib_dev) {		ret = -ENXIO;		goto out;	}	file = kzalloc(sizeof *file, GFP_KERNEL);	if (!file) {		kref_put(&port->umad_dev->ref, ib_umad_release_dev);		ret = -ENOMEM;		goto out;	}	spin_lock_init(&file->recv_lock);	spin_lock_init(&file->send_lock);	INIT_LIST_HEAD(&file->recv_list);	INIT_LIST_HEAD(&file->send_list);	init_waitqueue_head(&file->recv_wait);	file->port = port;	filp->private_data = file;	list_add_tail(&file->port_list, &port->file_list);out:	up_write(&port->mutex);	return ret;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?