Jacek Caban : server: Notify kernel when IRP is terminated by server.

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


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

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

server: Notify kernel when IRP is 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   | 12 +++++++++-
 include/wine/server_protocol.h | 11 +++++++--
 server/device.c                | 51 ++++++++++++++++++++++++++++++++++++++++--
 server/protocol.def            |  9 +++++++-
 server/trace.c                 |  5 +++++
 5 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 1892809..04a3f31 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -838,6 +838,15 @@ static NTSTATUS dispatch_free( struct dispatch_context *context )
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS dispatch_cancel( struct dispatch_context *context )
+{
+    IRP *irp = wine_server_get_ptr( context->params.cancel.irp );
+
+    FIXME( "%p\n", irp );
+
+    return STATUS_SUCCESS;
+}
+
 typedef NTSTATUS (*dispatch_func)( struct dispatch_context *context );
 
 static const dispatch_func dispatch_funcs[] =
@@ -849,7 +858,8 @@ static const dispatch_func dispatch_funcs[] =
     dispatch_write,    /* IRP_CALL_WRITE */
     dispatch_flush,    /* IRP_CALL_FLUSH */
     dispatch_ioctl,    /* IRP_CALL_IOCTL */
-    dispatch_free      /* IRP_CALL_FREE */
+    dispatch_free,     /* IRP_CALL_FREE */
+    dispatch_cancel    /* IRP_CALL_CANCEL */
 };
 
 /* helper function to update service status */
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index eab5755..15ad91c 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -649,7 +649,8 @@ enum irp_type
     IRP_CALL_WRITE,
     IRP_CALL_FLUSH,
     IRP_CALL_IOCTL,
-    IRP_CALL_FREE
+    IRP_CALL_FREE,
+    IRP_CALL_CANCEL
 };
 
 typedef union
@@ -706,6 +707,12 @@ typedef union
         int              __pad;
         client_ptr_t     obj;
     } free;
+    struct
+    {
+        enum irp_type    type;
+        int              __pad;
+        client_ptr_t     irp;
+    } cancel;
 } irp_params_t;
 
 
@@ -6695,6 +6702,6 @@ union generic_reply
     struct resume_process_reply resume_process_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 584
+#define SERVER_PROTOCOL_VERSION 585
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/device.c b/server/device.c
index 1cebc3b..ee7df5a 100644
--- a/server/device.c
+++ b/server/device.c
@@ -52,6 +52,7 @@ struct irp_call
     struct async          *async;         /* pending async op */
     irp_params_t           params;        /* irp parameters */
     struct iosb           *iosb;          /* I/O status block */
+    int                    canceled;      /* the call was canceled */
     client_ptr_t           user_ptr;      /* client side pointer */
 };
 
@@ -188,6 +189,7 @@ static int device_file_read( struct fd *fd, struct async *async, file_pos_t pos
 static int device_file_write( struct fd *fd, struct async *async, file_pos_t pos );
 static int device_file_flush( struct fd *fd, struct async *async );
 static int device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
+static void device_file_reselect_async( struct fd *fd, struct async_queue *queue );
 
 static const struct object_ops device_file_ops =
 {
@@ -224,7 +226,7 @@ static const struct fd_ops device_file_fd_ops =
     no_fd_get_volume_info,            /* get_volume_info */
     device_file_ioctl,                /* ioctl */
     default_fd_queue_async,           /* queue_async */
-    default_fd_reselect_async         /* reselect_async */
+    device_file_reselect_async        /* reselect_async */
 };
 
 
@@ -352,6 +354,7 @@ static struct irp_call *create_irp( struct device_file *file, const irp_params_t
         irp->async    = NULL;
         irp->params   = *params;
         irp->iosb     = NULL;
+        irp->canceled = 0;
         irp->user_ptr = 0;
 
         if (async) irp->iosb = async_get_iosb( async );
@@ -548,6 +551,7 @@ static int fill_irp_params( struct device_manager *manager, struct irp_call *irp
     {
     case IRP_CALL_NONE:
     case IRP_CALL_FREE:
+    case IRP_CALL_CANCEL:
         break;
     case IRP_CALL_CREATE:
         irp->params.create.file    = alloc_handle( current->process, irp->file,
@@ -653,6 +657,40 @@ static int device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *as
     return queue_irp( file, &params, async );
 }
 
+static void cancel_irp_call( struct irp_call *irp )
+{
+    struct irp_call *cancel_irp;
+    irp_params_t params;
+
+    irp->canceled = 1;
+    if (!irp->user_ptr || !irp->file || !irp->file->device->manager) return;
+
+    memset( &params, 0, sizeof(params) );
+    params.cancel.type = IRP_CALL_CANCEL;
+    params.cancel.irp  = irp->user_ptr;
+
+    if ((cancel_irp = create_irp( NULL, &params, NULL )))
+    {
+        add_irp_to_queue( irp->file->device->manager, cancel_irp, NULL );
+        release_object( cancel_irp );
+    }
+
+    set_irp_result( irp, STATUS_CANCELLED, NULL, 0, 0 );
+}
+
+static void device_file_reselect_async( struct fd *fd, struct async_queue *queue )
+{
+    struct device_file *file = get_fd_user( fd );
+    struct irp_call *irp;
+
+    LIST_FOR_EACH_ENTRY( irp, &file->requests, struct irp_call, dev_entry )
+        if (irp->iosb->status != STATUS_PENDING)
+        {
+            cancel_irp_call( irp );
+            return;
+        }
+}
+
 static struct device *create_device( struct object *root, const struct unicode_str *name,
                                      struct device_manager *manager )
 {
@@ -897,6 +935,10 @@ DECL_HANDLER(get_next_device_request)
 
         if (req->status)
             set_irp_result( irp, req->status, NULL, 0, 0 );
+        if (irp->canceled)
+            /* if it was canceled during dispatch, we couldn't queue cancel call without client pointer,
+             * so we need to do it now */
+            cancel_irp_call( irp );
         else if (irp->async)
             set_async_pending( irp->async, irp->file && is_fd_overlapped( irp->file->fd ) );
 
@@ -947,7 +989,12 @@ DECL_HANDLER(set_irp_result)
 
     if ((irp = (struct irp_call *)get_handle_obj( current->process, req->handle, 0, &irp_call_ops )))
     {
-        set_irp_result( irp, req->status, get_req_data(), get_req_data_size(), req->size );
+        if (!irp->canceled)
+            set_irp_result( irp, req->status, get_req_data(), get_req_data_size(), req->size );
+        else if(irp->user_ptr) /* cancel already queued */
+            set_error( STATUS_MORE_PROCESSING_REQUIRED );
+        else /* we may be still dispatching the IRP. don't bother queuing cancel if it's already complete */
+            irp->canceled = 0;
         close_handle( current->process, req->handle );  /* avoid an extra round-trip for close */
         release_object( irp );
     }
diff --git a/server/protocol.def b/server/protocol.def
index 6b6e868..e450388 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -665,7 +665,8 @@ enum irp_type
     IRP_CALL_WRITE,
     IRP_CALL_FLUSH,
     IRP_CALL_IOCTL,
-    IRP_CALL_FREE
+    IRP_CALL_FREE,
+    IRP_CALL_CANCEL
 };
 
 typedef union
@@ -722,6 +723,12 @@ typedef union
         int              __pad;
         client_ptr_t     obj;       /* opaque ptr for the freed object */
     } free;
+    struct
+    {
+        enum irp_type    type;      /* IRP_CALL_CANCEL */
+        int              __pad;
+        client_ptr_t     irp;       /* opaque ptr for canceled irp */
+    } cancel;
 } irp_params_t;
 
 /* information about a PE image mapping, roughly equivalent to SECTION_IMAGE_INFORMATION */
diff --git a/server/trace.c b/server/trace.c
index 82ea93f..8d3de65 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -363,6 +363,11 @@ static void dump_irp_params( const char *prefix, const irp_params_t *data )
         dump_uint64( ",obj=", &data->free.obj );
         fputc( '}', stderr );
         break;
+    case IRP_CALL_CANCEL:
+        fprintf( stderr, "%s{CANCEL", prefix );
+        dump_uint64( ",irp=", &data->cancel.irp );
+        fputc( '}', stderr );
+        break;
     }
 }
 




More information about the wine-cvs mailing list