From patchwork Thu Aug 13 23:21:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Narcisa Ana Maria Vasile X-Patchwork-Id: 75534 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8F524A04B1; Fri, 14 Aug 2020 01:25:07 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B79AA1C1BA; Fri, 14 Aug 2020 01:23:04 +0200 (CEST) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by dpdk.org (Postfix) with ESMTP id 628A11C0D1 for ; Fri, 14 Aug 2020 01:22:45 +0200 (CEST) Received: by linux.microsoft.com (Postfix, from userid 1059) id 49D4220B4770; Thu, 13 Aug 2020 16:22:43 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 49D4220B4770 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597360964; bh=YdHrOXqwJlgVU1bwecanFuEJn1xmuUcmut2e5AZfCOg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YIZXzzNMrZv2moc4pu+OpUgAczTPRa7x9PsCrLLUud6Dr0yFTB/gwDSmnJ0eiyNwc pI5IjaqiVNqWq2efr6sc1WzAVYqF1mf3qFCb81AHzqy+DVk6OyRXaOjwfPtTyh2arM hcJY9I9MXxuu1pCiI/mPABKalipQCBteN8HUXMRs= From: Narcisa Ana Maria Vasile To: dev@dpdk.org, thomas@monjalon.net, haramakr@linux.microsoft.com, ocardona@microsoft.com, pallavi.kadam@intel.com, dmitry.kozliuk@gmail.com Cc: ranjit.menon@intel.com, dmitrym@microsoft.com, Narcisa Vasile Date: Thu, 13 Aug 2020 16:21:40 -0700 Message-Id: <1597360905-74106-18-git-send-email-navasile@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1597360905-74106-1-git-send-email-navasile@linux.microsoft.com> References: <1597360905-74106-1-git-send-email-navasile@linux.microsoft.com> Subject: [dpdk-dev] [PATCH 17/22] uio: Use request handler that guarantees execution in correct context X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Narcisa Vasile Use EvtIoInCallerContext to assure the requests are handled in the right user thread context. If the request does not need to be handled in a specific context, send it back to framework. Signed-off-by: Narcisa Vasile Reported-by: Dmitry Kozlyuk --- kernel/windows/netuio/netuio_dev.c | 1 + kernel/windows/netuio/netuio_dev.h | 1 - kernel/windows/netuio/netuio_queue.c | 242 ++++++++++++++++----------- kernel/windows/netuio/netuio_queue.h | 2 + 4 files changed, 145 insertions(+), 101 deletions(-) diff --git a/kernel/windows/netuio/netuio_dev.c b/kernel/windows/netuio/netuio_dev.c index 3b5c95e84..e4e4570bc 100644 --- a/kernel/windows/netuio/netuio_dev.c +++ b/kernel/windows/netuio/netuio_dev.c @@ -50,6 +50,7 @@ netuio_create_device(_Inout_ PWDFDEVICE_INIT DeviceInit) // This function will be called when the WDF Device Object associated to the current device is destroyed WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, NETUIO_CONTEXT_DATA); deviceAttributes.EvtCleanupCallback = netuio_evt_device_context_cleanup; + WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, netuio_evt_IO_in_caller_context); status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); diff --git a/kernel/windows/netuio/netuio_dev.h b/kernel/windows/netuio/netuio_dev.h index 59956720e..6a9b1ff82 100644 --- a/kernel/windows/netuio/netuio_dev.h +++ b/kernel/windows/netuio/netuio_dev.h @@ -58,7 +58,6 @@ static NTSTATUS create_device_specific_symbolic_link(_In_ WDFOBJECT device); static NTSTATUS allocate_usermemory_segment(_In_ WDFOBJECT device); static VOID free_usermemory_segment(_In_ WDFOBJECT device); - EXTERN_C_END #endif // NETUIO_DEV_H diff --git a/kernel/windows/netuio/netuio_queue.c b/kernel/windows/netuio/netuio_queue.c index c2bc998dc..7714a4d3a 100644 --- a/kernel/windows/netuio/netuio_queue.c +++ b/kernel/windows/netuio/netuio_queue.c @@ -168,135 +168,177 @@ netuio_queue_initialize(_In_ WDFDEVICE Device) /* Routine Description: - This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request. + This routine is invoked to preprocess an I/O request before being placed into a queue. + It is guaranteed that it executes in the context of the process that generated the request. Return Value: None */ +_Use_decl_annotations_ VOID -netuio_evt_IO_device_control(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, - _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, - _In_ ULONG IoControlCode) +netuio_evt_IO_in_caller_context( + IN WDFDEVICE Device, + IN WDFREQUEST Request +) { - UNREFERENCED_PARAMETER(OutputBufferLength); - UNREFERENCED_PARAMETER(InputBufferLength); - + WDF_REQUEST_PARAMETERS params = { 0 }; NTSTATUS status = STATUS_SUCCESS; PVOID input_buf = NULL, output_buf = NULL; size_t input_buf_size, output_buf_size; size_t bytes_returned = 0; + PNETUIO_CONTEXT_DATA netuio_contextdata = NULL; - WDFDEVICE device = WdfIoQueueGetDevice(Queue); + netuio_contextdata = netuio_get_context_data(Device); - PNETUIO_CONTEXT_DATA netuio_contextdata; - netuio_contextdata = netuio_get_context_data(device); + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(Request, ¶ms); - switch (IoControlCode) { - case IOCTL_NETUIO_MAP_HW_INTO_USERMODE: - // First retrieve the input buffer and see if it matches our device - status = WdfRequestRetrieveInputBuffer(Request, sizeof(struct dpdk_private_info), &input_buf, &input_buf_size); - if (!NT_SUCCESS(status)) { - status = STATUS_INVALID_BUFFER_SIZE; - break; - } + // We only need to be in the context of the process that initiated the request + //when we need to map memory to userspace. Otherwise, send the request back to framework. + if (!((params.Type == WdfRequestTypeDeviceControl) && + (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_NETUIO_MAP_HW_INTO_USERMODE))) + { + status = WdfDeviceEnqueueRequest(Device, Request); - struct dpdk_private_info *dpdk_pvt_info = (struct dpdk_private_info *)input_buf; - // Ensure that the B:D:F match - otherwise, fail the IOCTL - if ((netuio_contextdata->addr.bus_num != dpdk_pvt_info->dev_addr.bus_num) || - (netuio_contextdata->addr.dev_num != dpdk_pvt_info->dev_addr.dev_num) || - (netuio_contextdata->addr.func_num != dpdk_pvt_info->dev_addr.func_num)) { - status = STATUS_NOT_SAME_DEVICE; - break; + if (!NT_SUCCESS(status)) + { + WdfRequestCompleteWithInformation(Request, status, bytes_returned); } + return; + } - if (netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr != NULL) { - status = STATUS_ALREADY_COMMITTED; - break; - } + // First retrieve the input buffer and see if it matches our device + status = WdfRequestRetrieveInputBuffer(Request, sizeof(struct dpdk_private_info), &input_buf, &input_buf_size); + if (!NT_SUCCESS(status)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto end; + } - // Return relevant data to the caller - status = WdfRequestRetrieveOutputBuffer(Request, sizeof(struct dpdk_private_info), &output_buf, &output_buf_size); - if (!NT_SUCCESS(status)) { - status = STATUS_INVALID_BUFFER_SIZE; - break; - } + struct dpdk_private_info* dpdk_pvt_info = (struct dpdk_private_info*)input_buf; + // Ensure that the B:D:F match - otherwise, fail the IOCTL + if ((netuio_contextdata->addr.bus_num != dpdk_pvt_info->dev_addr.bus_num) || + (netuio_contextdata->addr.dev_num != dpdk_pvt_info->dev_addr.dev_num) || + (netuio_contextdata->addr.func_num != dpdk_pvt_info->dev_addr.func_num)) { + status = STATUS_NOT_SAME_DEVICE; + goto end; + } - // Zero out the physically contiguous block - RtlZeroMemory(netuio_contextdata->dpdk_seg.mem.virt_addr, netuio_contextdata->dpdk_seg.mem.size); + if (netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr != NULL) { + status = STATUS_ALREADY_COMMITTED; + goto end; + } - status = netuio_map_address_into_user_process(netuio_contextdata); - if (status != STATUS_SUCCESS) { - break; - } + // Return relevant data to the caller + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(struct dpdk_private_info), &output_buf, &output_buf_size); + if (!NT_SUCCESS(status)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto end; + } - ASSERT(output_buf_size == OutputBufferLength); - netuio_handle_get_hw_data_request(Request, netuio_contextdata, output_buf, output_buf_size); - bytes_returned = output_buf_size; + // Zero out the physically contiguous block + RtlZeroMemory(netuio_contextdata->dpdk_seg.mem.virt_addr, netuio_contextdata->dpdk_seg.mem.size); - break; + status = netuio_map_address_into_user_process(netuio_contextdata); + if (status != STATUS_SUCCESS) { + goto end; + } - case IOCTL_NETUIO_PCI_CONFIG_IO: - // First retrieve the input buffer and see if it matches our device - status = WdfRequestRetrieveInputBuffer(Request, sizeof(struct dpdk_pci_config_io), &input_buf, &input_buf_size); - if (!NT_SUCCESS(status)) { - status = STATUS_INVALID_BUFFER_SIZE; - break; - } + netuio_handle_get_hw_data_request(Request, netuio_contextdata, output_buf, output_buf_size); + bytes_returned = output_buf_size; - struct dpdk_pci_config_io *dpdk_pci_io_input = (struct dpdk_pci_config_io *)input_buf; +end: + WdfRequestCompleteWithInformation(Request, status, bytes_returned); - if (dpdk_pci_io_input->access_size != 1 && - dpdk_pci_io_input->access_size != 2 && - dpdk_pci_io_input->access_size != 4 && - dpdk_pci_io_input->access_size != 8) { - status = STATUS_INVALID_PARAMETER; - break; - } + return; +} - // Ensure that the B:D:F match - otherwise, fail the IOCTL - if ((netuio_contextdata->addr.bus_num != dpdk_pci_io_input->dev_addr.bus_num) || - (netuio_contextdata->addr.dev_num != dpdk_pci_io_input->dev_addr.dev_num) || - (netuio_contextdata->addr.func_num != dpdk_pci_io_input->dev_addr.func_num)) { - status = STATUS_NOT_SAME_DEVICE; - break; - } - // Retrieve output buffer - status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &output_buf, &output_buf_size); - if (!NT_SUCCESS(status)) { - status = STATUS_INVALID_BUFFER_SIZE; - break; - } - ASSERT(output_buf_size == OutputBufferLength); - - if (dpdk_pci_io_input->op == PCI_IO_READ) { - *(UINT64 *)output_buf = 0; - bytes_returned = netuio_contextdata->bus_interface.GetBusData( - netuio_contextdata->bus_interface.Context, - PCI_WHICHSPACE_CONFIG, - output_buf, - dpdk_pci_io_input->offset, - dpdk_pci_io_input->access_size); - } - else if (dpdk_pci_io_input->op == PCI_IO_WRITE) { - // returns bytes written - bytes_returned = netuio_contextdata->bus_interface.SetBusData( - netuio_contextdata->bus_interface.Context, - PCI_WHICHSPACE_CONFIG, - (PVOID)&dpdk_pci_io_input->data, - dpdk_pci_io_input->offset, - dpdk_pci_io_input->access_size); - } - else { - status = STATUS_INVALID_PARAMETER; - break; - } +/* +Routine Description: + This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request. + +Return Value: + None + */ +VOID +netuio_evt_IO_device_control(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode) +{ + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + NTSTATUS status = STATUS_SUCCESS; + PVOID input_buf = NULL, output_buf = NULL; + size_t input_buf_size, output_buf_size; + size_t bytes_returned = 0; + + WDFDEVICE device = WdfIoQueueGetDevice(Queue); - break; + PNETUIO_CONTEXT_DATA netuio_contextdata; + netuio_contextdata = netuio_get_context_data(device); + + if (IoControlCode != IOCTL_NETUIO_PCI_CONFIG_IO) + { + status = STATUS_INVALID_DEVICE_REQUEST; + goto end; + } + + // First retrieve the input buffer and see if it matches our device + status = WdfRequestRetrieveInputBuffer(Request, sizeof(struct dpdk_pci_config_io), &input_buf, &input_buf_size); + if (!NT_SUCCESS(status)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto end; + } + + struct dpdk_pci_config_io *dpdk_pci_io_input = (struct dpdk_pci_config_io *)input_buf; + + if (dpdk_pci_io_input->access_size != 1 && + dpdk_pci_io_input->access_size != 2 && + dpdk_pci_io_input->access_size != 4 && + dpdk_pci_io_input->access_size != 8) { + status = STATUS_INVALID_PARAMETER; + goto end; + } - default: - break; + // Ensure that the B:D:F match - otherwise, fail the IOCTL + if ((netuio_contextdata->addr.bus_num != dpdk_pci_io_input->dev_addr.bus_num) || + (netuio_contextdata->addr.dev_num != dpdk_pci_io_input->dev_addr.dev_num) || + (netuio_contextdata->addr.func_num != dpdk_pci_io_input->dev_addr.func_num)) { + status = STATUS_NOT_SAME_DEVICE; + goto end; + } + // Retrieve output buffer + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UINT64), &output_buf, &output_buf_size); + if (!NT_SUCCESS(status)) { + status = STATUS_INVALID_BUFFER_SIZE; + goto end; + } + ASSERT(output_buf_size == OutputBufferLength); + + if (dpdk_pci_io_input->op == PCI_IO_READ) { + *(UINT64 *)output_buf = 0; + bytes_returned = netuio_contextdata->bus_interface.GetBusData( + netuio_contextdata->bus_interface.Context, + PCI_WHICHSPACE_CONFIG, + output_buf, + dpdk_pci_io_input->offset, + dpdk_pci_io_input->access_size); + } + else if (dpdk_pci_io_input->op == PCI_IO_WRITE) { + // returns bytes written + bytes_returned = netuio_contextdata->bus_interface.SetBusData( + netuio_contextdata->bus_interface.Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&dpdk_pci_io_input->data, + dpdk_pci_io_input->offset, + dpdk_pci_io_input->access_size); + } + else { + status = STATUS_INVALID_PARAMETER; + goto end; } +end: WdfRequestCompleteWithInformation(Request, status, bytes_returned); return; diff --git a/kernel/windows/netuio/netuio_queue.h b/kernel/windows/netuio/netuio_queue.h index 90fdb4008..68fdaa296 100644 --- a/kernel/windows/netuio/netuio_queue.h +++ b/kernel/windows/netuio/netuio_queue.h @@ -27,6 +27,8 @@ netuio_queue_initialize(_In_ WDFDEVICE hDevice); EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL netuio_evt_IO_device_control; EVT_WDF_IO_QUEUE_IO_STOP netuio_evt_IO_stop; +EVT_WDF_IO_IN_CALLER_CONTEXT netuio_evt_IO_in_caller_context; + EXTERN_C_END #endif // NETUIO_QUEUE_H