static int __vmbus_establish_gpadl()

in channel.c [457:571]


static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
				   enum hv_gpadl_type type, void *kbuffer,
				   u32 size, u32 send_offset,
				   struct vmbus_gpadl *gpadl)
{
	struct vmbus_channel_gpadl_header *gpadlmsg;
	struct vmbus_channel_gpadl_body *gpadl_body;
	struct vmbus_channel_msginfo *msginfo = NULL;
	struct vmbus_channel_msginfo *submsginfo, *tmp;
	struct list_head *curr;
	u32 next_gpadl_handle;
	unsigned long flags;
	int ret = 0;

	next_gpadl_handle =
		(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);

	ret = create_gpadl_header(type, kbuffer, size, send_offset, &msginfo);
	if (ret)
		return ret;

	ret = set_memory_decrypted((unsigned long)kbuffer,
				   PFN_UP(size));
	if (ret) {
		dev_warn(&channel->device_obj->device,
			 "Failed to set host visibility for new GPADL %d.\n",
			 ret);
		return ret;
	}

	init_completion(&msginfo->waitevent);
	msginfo->waiting_channel = channel;

	gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
	gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
	gpadlmsg->child_relid = channel->offermsg.child_relid;
	gpadlmsg->gpadl = next_gpadl_handle;


	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
	list_add_tail(&msginfo->msglistentry,
		      &vmbus_connection.chn_msg_list);

	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);

	if (channel->rescind) {
		ret = -ENODEV;
		goto cleanup;
	}

	ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
			     sizeof(*msginfo), true);

	trace_vmbus_establish_gpadl_header(gpadlmsg, ret);

	if (ret != 0)
		goto cleanup;

	list_for_each(curr, &msginfo->submsglist) {
		submsginfo = (struct vmbus_channel_msginfo *)curr;
		gpadl_body =
			(struct vmbus_channel_gpadl_body *)submsginfo->msg;

		gpadl_body->header.msgtype =
			CHANNELMSG_GPADL_BODY;
		gpadl_body->gpadl = next_gpadl_handle;

		ret = vmbus_post_msg(gpadl_body,
				     submsginfo->msgsize - sizeof(*submsginfo),
				     true);

		trace_vmbus_establish_gpadl_body(gpadl_body, ret);

		if (ret != 0)
			goto cleanup;

	}
	wait_for_completion(&msginfo->waitevent);

	if (msginfo->response.gpadl_created.creation_status != 0) {
		pr_err("Failed to establish GPADL: err = 0x%x\n",
		       msginfo->response.gpadl_created.creation_status);

		ret = -EDQUOT;
		goto cleanup;
	}

	if (channel->rescind) {
		ret = -ENODEV;
		goto cleanup;
	}

	/* At this point, we received the gpadl created msg */
	gpadl->gpadl_handle = gpadlmsg->gpadl;
	gpadl->buffer = kbuffer;
	gpadl->size = size;


cleanup:
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
	list_del(&msginfo->msglistentry);
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
	list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist,
				 msglistentry) {
		kfree(submsginfo);
	}

	kfree(msginfo);

	if (ret)
		set_memory_encrypted((unsigned long)kbuffer,
				     PFN_UP(size));

	return ret;
}