[dpdk-dev] [PATCH 17/22] uio: Use request handler that guarantees execution in correct context

Narcisa Ana Maria Vasile navasile at linux.microsoft.com
Fri Aug 14 01:21:40 CEST 2020


From: Narcisa Vasile <navasile at microsoft.com>

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 <navasile at microsoft.com>
Reported-by: Dmitry Kozlyuk <dmitry.kozliuk at gmail.com>
---
 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(&params);
+    WdfRequestGetParameters(Request, &params);
 
-    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
-- 
2.23.0.vfs.1.1.63.g5a5ad7f



More information about the dev mailing list