[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(¶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
--
2.23.0.vfs.1.1.63.g5a5ad7f
More information about the dev
mailing list