Module: wine Branch: master Commit: b724024d5a0db520f5f76a04ede604f313b4a578 URL: https://source.winehq.org/git/wine.git/?a=commit;h=b724024d5a0db520f5f76a04e...
Author: Jacek Caban jacek@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@codeweavers.com Signed-off-by: Alexandre Julliard julliard@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, ¶ms, 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( ¶ms, 0, sizeof(params) ); + params.cancel.type = IRP_CALL_CANCEL; + params.cancel.irp = irp->user_ptr; + + if ((cancel_irp = create_irp( NULL, ¶ms, 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; } }