static Bool HgfsVmciChannelOpen(HgfsTransportChannel *channel) // IN: Channel { int ret; int i; ASSERT(channel->status == HGFS_CHANNEL_NOTCONNECTED); ASSERT(channel->priv == NULL); memset(&gHgfsShmemPages, 0, sizeof gHgfsShmemPages); if (USE_VMCI == 0) { goto error; } spin_lock_init(&vmciRequestProcessLock); channel->priv = kmalloc(sizeof(VMCIHandle), GFP_KERNEL); if (!channel->priv) { goto error; } ret = vmci_datagram_create_handle( VMCI_INVALID_ID, /* Resource ID */ VMCI_FLAG_DG_NONE, /* Flags */ HgfsVmciChannelCallback,/* Datagram Recv Callback */ NULL, /* Callback data */ channel->priv); /* VMCI outhandle */ if (ret != VMCI_SUCCESS) { LOG(1, (KERN_WARNING "Failed to create VMCI handle %d\n", ret)); goto error; } gHgfsShmemPages.list = kmalloc(sizeof *gHgfsShmemPages.list * HGFS_VMCI_SHMEM_PAGES, GFP_KERNEL); if (!gHgfsShmemPages.list) { goto error; } memset(gHgfsShmemPages.list, 0, sizeof *gHgfsShmemPages.list * HGFS_VMCI_SHMEM_PAGES); for (i = 0; i < HGFS_VMCI_SHMEM_PAGES; i++) { gHgfsShmemPages.list[i].va = __get_free_page(GFP_KERNEL); if (!gHgfsShmemPages.list[i].va) { LOG(1, (KERN_WARNING "__get_free_page returned error \n")); if (i == 0) { /* Ouch. We failed on first call to __get_free_page */ goto error; } /* It's ok. We can still send few pages to the host */ break; } gHgfsShmemPages.list[i].pa = virt_to_phys((void *)(size_t)gHgfsShmemPages.list[i].va); gHgfsShmemPages.list[i].free = TRUE; } gHgfsShmemPages.totalPageCount = i; gHgfsShmemPages.freePageCount = i; ret = HgfsVmciChannelPassGuestPages(channel); if (!ret) { for (i = 0; i < gHgfsShmemPages.totalPageCount; i++) { LOG(1, (KERN_WARNING "Freeing pages\n")); free_page(gHgfsShmemPages.list[i].va); } LOG(1, (KERN_WARNING "Failed to pass pages to the guest %d\n", ret)); goto error; } return TRUE; error: kfree(gHgfsShmemPages.list); kfree(channel->priv); return FALSE; }
int VPageChannel_CreateInVM(VPageChannel **channel, // IN/OUT VMCIId resourceId, // IN VMCIId peerResourceId, // IN uint64 produceQSize, // IN uint64 consumeQSize, // IN uint32 channelFlags, // IN VPageChannelRecvCB recvCB, // IN void *clientRecvData, // IN VPageChannelAllocElemFn elemAllocFn, // IN void *allocClientData, // IN VPageChannelFreeElemFn elemFreeFn, // IN void *freeClientData, // IN int defaultRecvBuffers, // IN int maxRecvBuffers) // IN { int retval; int flags; VPageChannel *pageChannel; ASSERT(channel); ASSERT(VMCI_INVALID_ID != resourceId); ASSERT(VMCI_INVALID_ID != peerResourceId); ASSERT(recvCB); if (channelFlags & ~(VPAGECHANNEL_FLAGS_ALL)) { VMCI_WARNING((LGPFX"Invalid argument (flags=0x%x).\n", channelFlags)); return VMCI_ERROR_INVALID_ARGS; } pageChannel = VMCI_AllocKernelMem(sizeof *pageChannel, VMCI_MEMORY_NONPAGED); if (!pageChannel) { VMCI_WARNING((LGPFX"Failed to allocate channel memory.\n")); return VMCI_ERROR_NO_MEM; } /* * XXX, we should support a default internal allocation function. */ memset(pageChannel, 0, sizeof *pageChannel); pageChannel->state = VPCState_Unconnected; pageChannel->dgHandle = VMCI_INVALID_HANDLE; pageChannel->attachSubId = VMCI_INVALID_ID; pageChannel->detachSubId = VMCI_INVALID_ID; pageChannel->qpHandle = VMCI_INVALID_HANDLE; pageChannel->qpair = NULL; pageChannel->doorbellHandle = VMCI_INVALID_HANDLE; pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE; pageChannel->flags = channelFlags; pageChannel->recvCB = recvCB; pageChannel->clientRecvData = clientRecvData; pageChannel->elemAllocFn = elemAllocFn; pageChannel->allocClientData = allocClientData; pageChannel->elemFreeFn = elemFreeFn; pageChannel->freeClientData = freeClientData; pageChannel->resourceId = resourceId; pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, peerResourceId); Atomic_Write32(&pageChannel->curRecvBufs, 0); pageChannel->recvBufsTarget = defaultRecvBuffers; pageChannel->defaultRecvBufs = defaultRecvBuffers; pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD; pageChannel->produceQSize = produceQSize; pageChannel->consumeQSize = consumeQSize; /* * Create a datagram handle over which we will connection handshake packets * (once the queuepair is created we can send packets over that instead). * This handle has a delayed callback regardless of the channel flags, * because we may have to create a queuepair inside the callback. */ flags = VMCI_FLAG_DG_DELAYED_CB; retval = vmci_datagram_create_handle(resourceId, flags, VPageChannelDgRecvFunc, pageChannel, &pageChannel->dgHandle); if (retval < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to create datagram handle " "(channel=%p) (err=%d).\n", channel, retval)); goto error; } VMCI_DEBUG_LOG(10, (LGPFX"Created datagram (channel=%p) " "(handle=0x%x:0x%x).\n", channel, pageChannel->dgHandle.context, pageChannel->dgHandle.resource)); /* * Create a doorbell handle. This is used by the peer to signal the * arrival of packets in the queuepair. This handle has a delayed * callback depending on the channel flags. */ flags = channelFlags & VPAGECHANNEL_FLAGS_RECV_DELAYED ? VMCI_FLAG_DELAYED_CB : 0; retval = vmci_doorbell_create(&pageChannel->doorbellHandle, flags, VMCI_PRIVILEGE_FLAG_RESTRICTED, VPageChannelDoorbellCallback, pageChannel); if (retval < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to create doorbell " "(channel=%p) (err=%d).\n", channel, retval)); goto error; } VMCI_DEBUG_LOG(10, (LGPFX"Created doorbell (channel=%p) " "(handle=0x%x:0x%x).\n", channel, pageChannel->doorbellHandle.context, pageChannel->doorbellHandle.resource)); /* * Now create the queuepair, over which we can pass data packets. */ retval = VPageChannelCreateQueuePair(pageChannel); if (retval < VMCI_SUCCESS) { goto error; } /* * Set the receiving buffers before sending the connection message to * avoid a race when the connection is made, but there is no receiving * buffer yet. */ if (defaultRecvBuffers) { int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD; if (0 == VPageChannelAddRecvBuffers(pageChannel, numElems, TRUE)) { /* * AddRecvBuffers() returns the number of buffers actually added. If * we failed to add any at all, then fail. */ retval = VMCI_ERROR_NO_MEM; goto error; } } retval = VPageChannelSendConnectionMessage(pageChannel); if (retval < VMCI_SUCCESS) { goto error; } VMCI_DEBUG_LOG(10, (LGPFX"Created (channel=%p) (handle=0x%x:0x%x).\n", pageChannel, pageChannel->dgHandle.context, pageChannel->dgHandle.resource)); *channel = pageChannel; return retval; error: VPageChannel_Destroy(pageChannel); return retval; }