Jacek Caban : ntoskrnl.exe: Cancel IRPs terminated by server.

Alexandre Julliard julliard at winehq.org
Tue May 28 15:06:51 CDT 2019


Module: wine
Branch: master
Commit: 9157129fc86c8759e75fc6f68b49b28693c6c9ca
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9157129fc86c8759e75fc6f68b49b28693c6c9ca

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue May 28 14:10:48 2019 +0200

ntoskrnl.exe: Cancel IRPs terminated by server.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntoskrnl.exe/ntoskrnl.c       | 38 +++++++++++++++++++++++++++++++++++---
 dlls/ntoskrnl.exe/tests/ntoskrnl.c |  3 ---
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 04a3f31..b5d89f6 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -523,15 +523,31 @@ static void *create_file_object( HANDLE handle )
     return file;
 }
 
+DECLARE_CRITICAL_SECTION(irp_completion_cs);
+
+static void WINAPI cancel_completed_irp( DEVICE_OBJECT *device, IRP *irp )
+{
+    TRACE( "(%p %p)\n", device, irp );
+
+    IoReleaseCancelSpinLock(irp->CancelIrql);
+
+    irp->IoStatus.u.Status = STATUS_CANCELLED;
+    irp->IoStatus.Information = 0;
+    IoCompleteRequest(irp, IO_NO_INCREMENT);
+}
+
 /* transfer result of IRP back to wineserver */
 static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
 {
     HANDLE irp_handle = context;
     void *out_buff = irp->UserBuffer;
+    NTSTATUS status;
 
     if (irp->Flags & IRP_WRITE_OPERATION)
         out_buff = NULL;  /* do not transfer back input buffer */
 
+    EnterCriticalSection( &irp_completion_cs );
+
     SERVER_START_REQ( set_irp_result )
     {
         req->handle   = wine_server_obj_handle( irp_handle );
@@ -541,16 +557,29 @@ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp,
             req->size = irp->IoStatus.Information;
             if (out_buff) wine_server_add_data( req, out_buff, irp->IoStatus.Information );
         }
-        wine_server_call( req );
+        status = wine_server_call( req );
     }
     SERVER_END_REQ;
 
+    if (status == STATUS_MORE_PROCESSING_REQUIRED)
+    {
+        /* IRP is complete, but server may have already ordered cancel call. In such case,
+         * it will return STATUS_MORE_PROCESSING_REQUIRED, leaving the IRP alive until
+         * cancel frees it. */
+        if (irp->Cancel)
+            status = STATUS_SUCCESS;
+        else
+            IoSetCancelRoutine( irp, cancel_completed_irp );
+    }
+
     if (irp->UserBuffer != irp->AssociatedIrp.SystemBuffer)
     {
         HeapFree( GetProcessHeap(), 0, irp->UserBuffer );
         irp->UserBuffer = NULL;
     }
-    return STATUS_SUCCESS;
+
+    LeaveCriticalSection( &irp_completion_cs );
+    return status;
 }
 
 struct dispatch_context
@@ -842,8 +871,11 @@ static NTSTATUS dispatch_cancel( struct dispatch_context *context )
 {
     IRP *irp = wine_server_get_ptr( context->params.cancel.irp );
 
-    FIXME( "%p\n", irp );
+    TRACE( "%p\n", irp );
 
+    EnterCriticalSection( &irp_completion_cs );
+    IoCancelIrp( irp );
+    LeaveCriticalSection( &irp_completion_cs );
     return STATUS_SUCCESS;
 }
 
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index d505643..43418f3 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -234,7 +234,6 @@ static void test_overlapped(void)
     cancel_cnt = 0xdeadbeef;
     res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped);
     ok(res, "DeviceIoControl failed: %u\n", GetLastError());
-    todo_wine
     ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt);
 
     /* test cancelling selected overlapped event */
@@ -254,7 +253,6 @@ static void test_overlapped(void)
         cancel_cnt = 0xdeadbeef;
         res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped);
         ok(res, "DeviceIoControl failed: %u\n", GetLastError());
-        todo_wine
         ok(cancel_cnt == 1, "cancel_cnt = %u\n", cancel_cnt);
 
         pCancelIoEx(file, &overlapped2);
@@ -262,7 +260,6 @@ static void test_overlapped(void)
         cancel_cnt = 0xdeadbeef;
         res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped);
         ok(res, "DeviceIoControl failed: %u\n", GetLastError());
-        todo_wine
         ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt);
     }
 




More information about the wine-cvs mailing list