Charles Davis wrote:
Hi,
This patch series moves drive handling over to mountmgr. Mountmgr will now associate UNIX device files directly to its created devices instead of having ntdll handle converting something like ??\D: to $WINEPREFIX/dosdevices/d::. This way, we can implement storage I/O controls in mountmgr instead of ntdll, while the storage I/O controls already in ntdll continue to work.
It also allows drivers to associate UNIX device files to their device objects, paving the way for separating the driver code from ntdll.
Since nobody's said anything about my patches, I'll have to assume they're good. (They work for me.)
Chip
I thought I fixed all the issues. What's wrong with my patches now?
Chip
Charles Davis cdavis@mymail.mines.edu writes:
I thought I fixed all the issues. What's wrong with my patches now?
Many things, it's a lot more complicated than that. For instance you can't just kill the fstab support, this needs to be preserved somehow, probably on the mountmgr side. Also you can't have a single file descriptor per device, you need one for each open.
Alexandre Julliard wrote:
Charles Davis cdavis@mymail.mines.edu writes:
I thought I fixed all the issues. What's wrong with my patches now?
Many things, it's a lot more complicated than that. For instance you can't just kill the fstab support, this needs to be preserved somehow, probably on the mountmgr side. Also you can't have a single file descriptor per device, you need one for each open.
OK, I can do that.
I've decided to do the open in mountmgr, so I can have it handle changes to the fstab while it's running. So, I'm working on implementing IRP_MJ_CREATE support (which is the standard way for drivers to handle open requests). I've attached a first stab at that. Can you take a look? I'm pretty sure there's something I'm missing.
BTW, I'm on #winehackers as I write this (my nick is cdavis5x).
Chip
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 93d72a6..3ad1284 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -142,6 +142,56 @@ static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs ) return EXCEPTION_CONTINUE_SEARCH; }
+/* process an open request for a given device */ +static NTSTATUS process_open( DEVICE_OBJECT *device, ULONG access, ULONG sharing, + ULONG options ) +{ + IRP irp; + IO_STACK_LOCATION irpsp; + IO_SECURITY_CONTEXT security; + PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_CREATE]; + NTSTATUS status; + LARGE_INTEGER count; + + TRACE( "open device %p access %x sharing %x options %x\n", device, access, + access, sharing, options ); + + /* so we can spot things that we should initialize */ + memset( &irp, 0x55, sizeof(irp) ); + memset( &irpsp, 0x66, sizeof(irpsp) ); + memset( &security, 0x77, sizeof(security) ); + + irp.RequestorMode = UserMode; + irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp; + irp.UserIosb = NULL; + + irpsp.MajorFunction = IRP_MJ_CREATE; + irpsp.Create.SecurityContext = &security; + security.DesiredAccess = access; + irpsp.Create.Options = options; + irpsp.Create.ShareAccess = sharing; + irpsp.DeviceObject = device; + irpsp.CompletionRoutine = NULL; + + device->CurrentIrp = &irp; + + KeQueryTickCount( &count ); /* update the global KeTickCount */ + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n", + GetCurrentThreadId(), dispatch, device, &irp ); + + status = dispatch( device, &irp ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n", + GetCurrentThreadId(), dispatch, device, &irp, status ); + + *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0; + return irp.IoStatus.u.Status; + +} + /* process an ioctl request for a given device */ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size, void *out_buff, ULONG *out_size ) @@ -206,12 +256,14 @@ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) { HANDLE manager = get_device_manager(); - obj_handle_t ioctl = 0; + obj_handle_t call = 0; + enum server_call_type type = CALL_OPEN; NTSTATUS status = STATUS_SUCCESS; ULONG code = 0; void *in_buff, *out_buff = NULL; DEVICE_OBJECT *device = NULL; ULONG in_size = 4096, out_size = 0; + ULONG access, sharing, options; HANDLE handles[2];
if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size ))) @@ -228,21 +280,35 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) SERVER_START_REQ( get_next_device_request ) { req->manager = wine_server_obj_handle( manager ); - req->prev = ioctl; + req->prev = call; req->status = status; - wine_server_add_data( req, out_buff, out_size ); - wine_server_set_reply( req, in_buff, in_size ); + if (type == CALL_IOCTL) + { + wine_server_add_data( req, out_buff, out_size ); + wine_server_set_reply( req, in_buff, in_size ); + } if (!(status = wine_server_call( req ))) { - code = reply->code; - ioctl = reply->next; + call = reply->next; + type = reply->type; device = wine_server_get_ptr( reply->user_ptr ); - in_size = reply->in_size; - out_size = reply->out_size; + switch(type) + { + case CALL_OPEN: + access = reply->data.open.access; + sharing = reply->data.open.sharing; + options = reply->data.open.options; + break; + case CALL_IOCTL: + code = reply->data.ioctl.code; + in_size = reply->data.ioctl.in_size; + out_size = reply->data.ioctl.out_size; + break; + } } else { - ioctl = 0; /* no previous ioctl */ + call = 0; /* no previous call */ out_size = 0; in_size = reply->in_size; } @@ -255,7 +321,15 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) HeapFree( GetProcessHeap(), 0, out_buff ); if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ); else out_buff = NULL; - status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); + switch(type) + { + case CALL_OPEN: + status = process_open( device, access, sharing, options ); + break; + case CALL_IOCTL: + status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); + break; + } break; case STATUS_BUFFER_OVERFLOW: HeapFree( GetProcessHeap(), 0, in_buff ); diff --git a/server/device.c b/server/device.c index 4d134a3..cc772c9 100644 --- a/server/device.c +++ b/server/device.c @@ -33,17 +33,61 @@ #include "handle.h" #include "request.h"
-struct ioctl_call +int suspend_thread( struct thread *thread ); +int resume_thread( struct thread *thread ); + +struct call_object { struct object obj; /* object header */ + enum server_call_type type; /* type of driver call */ struct list dev_entry; /* entry in device queue */ struct list mgr_entry; /* entry in manager queue */ - struct device *device; /* device containing this ioctl */ - struct thread *thread; /* thread that queued the ioctl */ + struct device *device; /* device being opened */ + struct thread *thread; /* thread that opened the device */ client_ptr_t user_arg; /* user arg used to identify the request */ + unsigned int status; /* resulting status (or STATUS_PENDING) */ +}; + +static int call_object_signaled( struct object *obj, struct thread *thread ); +static void call_object_destroy( struct object *obj ); + +struct open_call +{ + struct call_object call; /* object header */ + unsigned int access; /* desired access */ + unsigned int sharing; /* desired sharing */ + unsigned int options; /* create options */ +}; + +static void open_call_dump( struct object *obj, int verbose ); +static void open_call_destroy( struct object *obj ); + +static const struct object_ops open_call_ops = +{ + sizeof(struct open_call), /* size */ + open_call_dump, /* dump */ + no_get_type, /* get_type */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + call_object_signaled, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + open_call_destroy /* destroy */ +}; + + +struct ioctl_call +{ + struct call_object obj; /* object header */ struct async *async; /* pending async op */ ioctl_code_t code; /* ioctl code */ - unsigned int status; /* resulting status (or STATUS_PENDING) */ data_size_t in_size; /* size of input data */ void *in_data; /* input data */ data_size_t out_size; /* size of output data */ @@ -51,7 +95,6 @@ struct ioctl_call };
static void ioctl_call_dump( struct object *obj, int verbose ); -static int ioctl_call_signaled( struct object *obj, struct thread *thread ); static void ioctl_call_destroy( struct object *obj );
static const struct object_ops ioctl_call_ops = @@ -61,7 +104,7 @@ static const struct object_ops ioctl_call_ops = no_get_type, /* get_type */ add_queue, /* add_queue */ remove_queue, /* remove_queue */ - ioctl_call_signaled, /* signaled */ + call_object_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -160,17 +203,68 @@ static const struct fd_ops device_fd_ops = };
-static void ioctl_call_dump( struct object *obj, int verbose ) +static int call_object_signaled( struct object *obj, struct thread *thread ) { - struct ioctl_call *ioctl = (struct ioctl_call *)obj; - fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->device ); + struct call_object *call = (struct call_object *)obj; + + return !call->device; /* device is cleared once the ioctl has completed */ }
-static int ioctl_call_signaled( struct object *obj, struct thread *thread ) +static void call_object_destroy( struct call_object *obj ) { - struct ioctl_call *ioctl = (struct ioctl_call *)obj; + if (obj->device) release_object( obj->device ); + release_object( obj->thread ); +} + + +static void open_call_dump( struct object *obj, int verbose ) +{ + struct open_call *open = (struct open_call *)obj; + fprintf( stderr, "Open call device=%p\n", open->call.device ); +} + +static void open_call_destroy( struct object *obj ) +{ + struct open_call *open = (struct open_call *)obj;
- return !ioctl->device; /* device is cleared once the ioctl has completed */ + call_object_destroy( &open->call ); +} + +static struct open_call *create_open( struct device *device, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + struct open_call *open; + + if ((open = alloc_object( &open_call_ops ))) + { + open->call.type = CALL_OPEN; + open->call.device = (struct device *)grab_object( device ); + open->access = access; + open->sharing = sharing; + open->options = options; + } + return ioctl; +} + +static void complete_open( struct open_call *open, unsigned int status ) +{ + struct device *device = open->device; + + if (!device) return; /* already finished */ + + open->call.status = status; + resume_thread( current ); + + /* remove it from the device queue */ + list_remove( &open->call.dev_entry ); + release_object( open ); /* no longer on the device queue */ +} + + +static void ioctl_call_dump( struct object *obj, int verbose ) +{ + struct ioctl_call *ioctl = (struct ioctl_call *)obj; + fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->cal.device ); }
static void ioctl_call_destroy( struct object *obj ) @@ -184,8 +278,7 @@ static void ioctl_call_destroy( struct object *obj ) async_terminate( ioctl->async, STATUS_CANCELLED ); release_object( ioctl->async ); } - if (ioctl->device) release_object( ioctl->device ); - release_object( ioctl->thread ); + call_object_destroy( &ioctl->call ); }
static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code, @@ -196,14 +289,15 @@ static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code
if ((ioctl = alloc_object( &ioctl_call_ops ))) { - ioctl->device = (struct device *)grab_object( device ); - ioctl->code = code; - ioctl->async = NULL; - ioctl->status = STATUS_PENDING; - ioctl->in_size = in_size; - ioctl->in_data = NULL; - ioctl->out_size = out_size; - ioctl->out_data = NULL; + ioctl->call.type = CALL_IOCTL; + ioctl->call.device = (struct device *)grab_object( device ); + ioctl->code = code; + ioctl->async = NULL; + ioctl->call.status = STATUS_PENDING; + ioctl->in_size = in_size; + ioctl->in_data = NULL; + ioctl->out_size = out_size; + ioctl->out_data = NULL;
if (ioctl->in_size && !(ioctl->in_data = memdup( in_data, in_size ))) { @@ -222,7 +316,7 @@ static void set_ioctl_result( struct ioctl_call *ioctl, unsigned int status, if (!device) return; /* already finished */
/* FIXME: handle the STATUS_PENDING case */ - ioctl->status = status; + ioctl->call.status = status; ioctl->out_size = min( ioctl->out_size, out_size ); if (ioctl->out_size && !(ioctl->out_data = memdup( out_data, ioctl->out_size ))) ioctl->out_size = 0; @@ -273,12 +367,12 @@ static struct fd *device_get_fd( struct object *obj ) static void device_destroy( struct object *obj ) { struct device *device = (struct device *)obj; - struct ioctl_call *ioctl, *next; + struct call_object *obj, *next;
- LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry ) + LIST_FOR_EACH_ENTRY_SAFE( obj, next, &device->requests, struct call_object, dev_entry ) { - list_remove( &ioctl->dev_entry ); - release_object( ioctl ); /* no longer on the device queue */ + list_remove( &obj->dev_entry ); + release_object( obj ); /* no longer on the device queue */ } if (device->fd) release_object( device->fd ); if (device->manager) list_remove( &device->entry ); @@ -287,6 +381,26 @@ static void device_destroy( struct object *obj ) static struct object *device_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ) { + struct device *device = (struct device *)obj; + struct open_call *open; + + if (!device->manager) /* it has been deleted */ + { + set_error( STATUS_FILE_DELETED ); + return 0; + } + + /* create an open request */ + if (!(open = create_open( device, access, sharing, options ))) + return NULL; + open->call.thread = current; + suspend_thread( current ); + + list_add_tail( &device->requests, &open->call.dev_entry ); + list_add_tail( &device->manager->requests, &open->call.mgr_entry ); + if (list_head( &device->manager->requests ) == &open->call.mgr_entry) /* first one */ + wake_up( &device->manager->obj, 0 ); + return grab_object( obj ); }
@@ -298,10 +412,10 @@ static enum server_fd_type device_get_fd_type( struct fd *fd ) static struct ioctl_call *find_ioctl_call( struct device *device, struct thread *thread, client_ptr_t user_arg ) { - struct ioctl_call *ioctl; + struct call_object *ioctl;
- LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry ) - if (ioctl->thread == thread && ioctl->user_arg == user_arg) return ioctl; + LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct call_object, dev_entry ) + if (ioctl->thread == thread && ioctl->user_arg == user_arg && ioctl->type == CALL_IOCTL) return (struct ioctl_call *)ioctl;
set_error( STATUS_INVALID_PARAMETER ); return NULL; @@ -323,8 +437,8 @@ static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_ if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() ))) return 0;
- ioctl->thread = (struct thread *)grab_object( current ); - ioctl->user_arg = async_data->arg; + ioctl->call.thread = (struct thread *)grab_object( current ); + ioctl->call.user_arg = async_data->arg;
if (!(handle = alloc_handle( current->process, ioctl, SYNCHRONIZE, 0 ))) { @@ -482,9 +596,11 @@ DECL_HANDLER(delete_device) }
-/* retrieve the next pending device ioctl request */ +/* retrieve the next pending device request */ DECL_HANDLER(get_next_device_request) { + struct call_object *call; + struct open_call *open; struct ioctl_call *ioctl; struct device_manager *manager; struct list *ptr; @@ -502,24 +618,46 @@ DECL_HANDLER(get_next_device_request) close_handle( current->process, req->prev ); /* avoid an extra round-trip for close */ release_object( ioctl ); } + if ((open = (struct open_call *)get_handle_obj( current->process, req->prev, + 0, &open_call_ops ))) + { + complete_open( open, req->status ); + close_handle( current->process, req->prev ); /* avoid an extra round-trip for close */ + release_object( open ); + } clear_error(); }
if ((ptr = list_head( &manager->requests ))) { - ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry ); - reply->code = ioctl->code; - reply->user_ptr = ioctl->device->user_ptr; - reply->in_size = ioctl->in_size; - reply->out_size = ioctl->out_size; - if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW ); - else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 ))) + call = LIST_ENTRY( ptr, struct call_object, mgr_entry ); + reply->user_ptr = call->device->user_ptr; + switch (call->type) { - set_reply_data_ptr( ioctl->in_data, ioctl->in_size ); - ioctl->in_data = NULL; - ioctl->in_size = 0; - list_remove( &ioctl->mgr_entry ); - list_init( &ioctl->mgr_entry ); + case CALL_OPEN: + open = (struct ioctl_call *)call; + reply->data.open.access = open->access; + reply->data.open.sharing = open->sharing; + reply->data.open.options = open->options; + if ((reply->next = alloc_handle( current->process, open, 0, 0 ))) + { + list_remove( &call->mgr_entry ); + list_init( &call->mgr_entry ); + } + case CALL_IOCTL: + ioctl = (struct ioctl_call *)call; + reply->data.ioctl.code = ioctl->code; + reply->data.ioctl.in_size = ioctl->in_size; + reply->data.ioctl.out_size = ioctl->out_size; + if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW ); + else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 ))) + { + set_reply_data_ptr( ioctl->in_data, ioctl->in_size ); + ioctl->in_data = NULL; + ioctl->in_size = 0; + list_remove( &call->mgr_entry ); + list_init( &call->mgr_entry ); + } } } else set_error( STATUS_PENDING ); diff --git a/server/protocol.def b/server/protocol.def index a0e1702..e554112 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3102,18 +3102,39 @@ enum message_type @END
-/* Retrieve the next pending device ioctl request */ +enum server_call_type +{ + CALL_OPEN, + CALL_IOCTL +}; + +union next_request +{ + struct + { + ioctl_code_t code; /* ioctl code */ + data_size_t in_size; /* total needed input size */ + data_size_t out_size; /* needed output size */ + } ioctl; + struct + { + unsigned int access; + unsigned int sharing; + unsigned int options; + } open; +}; + +/* Retrieve the next pending device request */ @REQ(get_next_device_request) obj_handle_t manager; /* handle to the device manager */ - obj_handle_t prev; /* handle to the previous ioctl */ - unsigned int status; /* status of the previous ioctl */ + obj_handle_t prev; /* handle to the previous request */ + unsigned int status; /* status of the previous request */ VARARG(prev_data,bytes); /* output data of the previous ioctl */ @REPLY - obj_handle_t next; /* handle to the next ioctl */ - ioctl_code_t code; /* ioctl code */ + obj_handle_t next; /* handle to the next request */ + enum server_call_type type; /* type of this request */ client_ptr_t user_ptr; /* opaque ptr for the device */ - data_size_t in_size; /* total needed input size */ - data_size_t out_size; /* needed output size */ + union next_request data; /* data associated with the next request */ VARARG(next_data,bytes); /* input data of the next ioctl */ @END
diff --git a/server/thread.c b/server/thread.c index f45be24..a1b4120 100644 --- a/server/thread.c +++ b/server/thread.c @@ -474,7 +474,7 @@ void stop_thread( struct thread *thread ) }
/* suspend a thread */ -static int suspend_thread( struct thread *thread ) +int suspend_thread( struct thread *thread ) { int old_count = thread->suspend; if (thread->suspend < MAXIMUM_SUSPEND_COUNT) @@ -486,7 +486,7 @@ static int suspend_thread( struct thread *thread ) }
/* resume a thread */ -static int resume_thread( struct thread *thread ) +int resume_thread( struct thread *thread ) { int old_count = thread->suspend; if (thread->suspend > 0)
Alexandre Julliard wrote:
Charles Davis cdavis@mymail.mines.edu writes:
I thought I fixed all the issues. What's wrong with my patches now?
Many things, it's a lot more complicated than that. For instance you can't just kill the fstab support, this needs to be preserved somehow, probably on the mountmgr side. Also you can't have a single file descriptor per device, you need one for each open.
OK, I can do that.
I've decided to do the open in mountmgr, so I can have it handle changes to the fstab while it's running. So, I'm working on implementing IRP_MJ_CREATE support (which is the standard way for drivers to handle open requests). I've attached a first stab at that. Can you take a look? I'm pretty sure there's something I'm missing.
BTW, I'm on #winehackers as I write this (my nick is cdavis5x).
Chip
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 93d72a6..3ad1284 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -142,6 +142,56 @@ static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs ) return EXCEPTION_CONTINUE_SEARCH; }
+/* process an open request for a given device */ +static NTSTATUS process_open( DEVICE_OBJECT *device, ULONG access, ULONG sharing, + ULONG options ) +{ + IRP irp; + IO_STACK_LOCATION irpsp; + IO_SECURITY_CONTEXT security; + PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_CREATE]; + NTSTATUS status; + LARGE_INTEGER count; + + TRACE( "open device %p access %x sharing %x options %x\n", device, access, + access, sharing, options ); + + /* so we can spot things that we should initialize */ + memset( &irp, 0x55, sizeof(irp) ); + memset( &irpsp, 0x66, sizeof(irpsp) ); + memset( &security, 0x77, sizeof(security) ); + + irp.RequestorMode = UserMode; + irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp; + irp.UserIosb = NULL; + + irpsp.MajorFunction = IRP_MJ_CREATE; + irpsp.Create.SecurityContext = &security; + security.DesiredAccess = access; + irpsp.Create.Options = options; + irpsp.Create.ShareAccess = sharing; + irpsp.DeviceObject = device; + irpsp.CompletionRoutine = NULL; + + device->CurrentIrp = &irp; + + KeQueryTickCount( &count ); /* update the global KeTickCount */ + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n", + GetCurrentThreadId(), dispatch, device, &irp ); + + status = dispatch( device, &irp ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n", + GetCurrentThreadId(), dispatch, device, &irp, status ); + + *out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0; + return irp.IoStatus.u.Status; + +} + /* process an ioctl request for a given device */ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size, void *out_buff, ULONG *out_size ) @@ -206,12 +256,14 @@ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) { HANDLE manager = get_device_manager(); - obj_handle_t ioctl = 0; + obj_handle_t call = 0; + enum server_call_type type = CALL_OPEN; NTSTATUS status = STATUS_SUCCESS; ULONG code = 0; void *in_buff, *out_buff = NULL; DEVICE_OBJECT *device = NULL; ULONG in_size = 4096, out_size = 0; + ULONG access, sharing, options; HANDLE handles[2];
if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size ))) @@ -228,21 +280,35 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) SERVER_START_REQ( get_next_device_request ) { req->manager = wine_server_obj_handle( manager ); - req->prev = ioctl; + req->prev = call; req->status = status; - wine_server_add_data( req, out_buff, out_size ); - wine_server_set_reply( req, in_buff, in_size ); + if (type == CALL_IOCTL) + { + wine_server_add_data( req, out_buff, out_size ); + wine_server_set_reply( req, in_buff, in_size ); + } if (!(status = wine_server_call( req ))) { - code = reply->code; - ioctl = reply->next; + call = reply->next; + type = reply->type; device = wine_server_get_ptr( reply->user_ptr ); - in_size = reply->in_size; - out_size = reply->out_size; + switch(type) + { + case CALL_OPEN: + access = reply->data.open.access; + sharing = reply->data.open.sharing; + options = reply->data.open.options; + break; + case CALL_IOCTL: + code = reply->data.ioctl.code; + in_size = reply->data.ioctl.in_size; + out_size = reply->data.ioctl.out_size; + break; + } } else { - ioctl = 0; /* no previous ioctl */ + call = 0; /* no previous call */ out_size = 0; in_size = reply->in_size; } @@ -255,7 +321,15 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) HeapFree( GetProcessHeap(), 0, out_buff ); if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ); else out_buff = NULL; - status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); + switch(type) + { + case CALL_OPEN: + status = process_open( device, access, sharing, options ); + break; + case CALL_IOCTL: + status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size ); + break; + } break; case STATUS_BUFFER_OVERFLOW: HeapFree( GetProcessHeap(), 0, in_buff ); diff --git a/server/device.c b/server/device.c index 4d134a3..cc772c9 100644 --- a/server/device.c +++ b/server/device.c @@ -33,17 +33,61 @@ #include "handle.h" #include "request.h"
-struct ioctl_call +int suspend_thread( struct thread *thread ); +int resume_thread( struct thread *thread ); + +struct call_object { struct object obj; /* object header */ + enum server_call_type type; /* type of driver call */ struct list dev_entry; /* entry in device queue */ struct list mgr_entry; /* entry in manager queue */ - struct device *device; /* device containing this ioctl */ - struct thread *thread; /* thread that queued the ioctl */ + struct device *device; /* device being opened */ + struct thread *thread; /* thread that opened the device */ client_ptr_t user_arg; /* user arg used to identify the request */ + unsigned int status; /* resulting status (or STATUS_PENDING) */ +}; + +static int call_object_signaled( struct object *obj, struct thread *thread ); +static void call_object_destroy( struct object *obj ); + +struct open_call +{ + struct call_object call; /* object header */ + unsigned int access; /* desired access */ + unsigned int sharing; /* desired sharing */ + unsigned int options; /* create options */ +}; + +static void open_call_dump( struct object *obj, int verbose ); +static void open_call_destroy( struct object *obj ); + +static const struct object_ops open_call_ops = +{ + sizeof(struct open_call), /* size */ + open_call_dump, /* dump */ + no_get_type, /* get_type */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + call_object_signaled, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + open_call_destroy /* destroy */ +}; + + +struct ioctl_call +{ + struct call_object obj; /* object header */ struct async *async; /* pending async op */ ioctl_code_t code; /* ioctl code */ - unsigned int status; /* resulting status (or STATUS_PENDING) */ data_size_t in_size; /* size of input data */ void *in_data; /* input data */ data_size_t out_size; /* size of output data */ @@ -51,7 +95,6 @@ struct ioctl_call };
static void ioctl_call_dump( struct object *obj, int verbose ); -static int ioctl_call_signaled( struct object *obj, struct thread *thread ); static void ioctl_call_destroy( struct object *obj );
static const struct object_ops ioctl_call_ops = @@ -61,7 +104,7 @@ static const struct object_ops ioctl_call_ops = no_get_type, /* get_type */ add_queue, /* add_queue */ remove_queue, /* remove_queue */ - ioctl_call_signaled, /* signaled */ + call_object_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -160,17 +203,68 @@ static const struct fd_ops device_fd_ops = };
-static void ioctl_call_dump( struct object *obj, int verbose ) +static int call_object_signaled( struct object *obj, struct thread *thread ) { - struct ioctl_call *ioctl = (struct ioctl_call *)obj; - fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->device ); + struct call_object *call = (struct call_object *)obj; + + return !call->device; /* device is cleared once the ioctl has completed */ }
-static int ioctl_call_signaled( struct object *obj, struct thread *thread ) +static void call_object_destroy( struct call_object *obj ) { - struct ioctl_call *ioctl = (struct ioctl_call *)obj; + if (obj->device) release_object( obj->device ); + release_object( obj->thread ); +} + + +static void open_call_dump( struct object *obj, int verbose ) +{ + struct open_call *open = (struct open_call *)obj; + fprintf( stderr, "Open call device=%p\n", open->call.device ); +} + +static void open_call_destroy( struct object *obj ) +{ + struct open_call *open = (struct open_call *)obj;
- return !ioctl->device; /* device is cleared once the ioctl has completed */ + call_object_destroy( &open->call ); +} + +static struct open_call *create_open( struct device *device, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + struct open_call *open; + + if ((open = alloc_object( &open_call_ops ))) + { + open->call.type = CALL_OPEN; + open->call.device = (struct device *)grab_object( device ); + open->access = access; + open->sharing = sharing; + open->options = options; + } + return ioctl; +} + +static void complete_open( struct open_call *open, unsigned int status ) +{ + struct device *device = open->device; + + if (!device) return; /* already finished */ + + open->call.status = status; + resume_thread( current ); + + /* remove it from the device queue */ + list_remove( &open->call.dev_entry ); + release_object( open ); /* no longer on the device queue */ +} + + +static void ioctl_call_dump( struct object *obj, int verbose ) +{ + struct ioctl_call *ioctl = (struct ioctl_call *)obj; + fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->cal.device ); }
static void ioctl_call_destroy( struct object *obj ) @@ -184,8 +278,7 @@ static void ioctl_call_destroy( struct object *obj ) async_terminate( ioctl->async, STATUS_CANCELLED ); release_object( ioctl->async ); } - if (ioctl->device) release_object( ioctl->device ); - release_object( ioctl->thread ); + call_object_destroy( &ioctl->call ); }
static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code, @@ -196,14 +289,15 @@ static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code
if ((ioctl = alloc_object( &ioctl_call_ops ))) { - ioctl->device = (struct device *)grab_object( device ); - ioctl->code = code; - ioctl->async = NULL; - ioctl->status = STATUS_PENDING; - ioctl->in_size = in_size; - ioctl->in_data = NULL; - ioctl->out_size = out_size; - ioctl->out_data = NULL; + ioctl->call.type = CALL_IOCTL; + ioctl->call.device = (struct device *)grab_object( device ); + ioctl->code = code; + ioctl->async = NULL; + ioctl->call.status = STATUS_PENDING; + ioctl->in_size = in_size; + ioctl->in_data = NULL; + ioctl->out_size = out_size; + ioctl->out_data = NULL;
if (ioctl->in_size && !(ioctl->in_data = memdup( in_data, in_size ))) { @@ -222,7 +316,7 @@ static void set_ioctl_result( struct ioctl_call *ioctl, unsigned int status, if (!device) return; /* already finished */
/* FIXME: handle the STATUS_PENDING case */ - ioctl->status = status; + ioctl->call.status = status; ioctl->out_size = min( ioctl->out_size, out_size ); if (ioctl->out_size && !(ioctl->out_data = memdup( out_data, ioctl->out_size ))) ioctl->out_size = 0; @@ -273,12 +367,12 @@ static struct fd *device_get_fd( struct object *obj ) static void device_destroy( struct object *obj ) { struct device *device = (struct device *)obj; - struct ioctl_call *ioctl, *next; + struct call_object *obj, *next;
- LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry ) + LIST_FOR_EACH_ENTRY_SAFE( obj, next, &device->requests, struct call_object, dev_entry ) { - list_remove( &ioctl->dev_entry ); - release_object( ioctl ); /* no longer on the device queue */ + list_remove( &obj->dev_entry ); + release_object( obj ); /* no longer on the device queue */ } if (device->fd) release_object( device->fd ); if (device->manager) list_remove( &device->entry ); @@ -287,6 +381,26 @@ static void device_destroy( struct object *obj ) static struct object *device_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ) { + struct device *device = (struct device *)obj; + struct open_call *open; + + if (!device->manager) /* it has been deleted */ + { + set_error( STATUS_FILE_DELETED ); + return 0; + } + + /* create an open request */ + if (!(open = create_open( device, access, sharing, options ))) + return NULL; + open->call.thread = current; + suspend_thread( current ); + + list_add_tail( &device->requests, &open->call.dev_entry ); + list_add_tail( &device->manager->requests, &open->call.mgr_entry ); + if (list_head( &device->manager->requests ) == &open->call.mgr_entry) /* first one */ + wake_up( &device->manager->obj, 0 ); + return grab_object( obj ); }
@@ -298,10 +412,10 @@ static enum server_fd_type device_get_fd_type( struct fd *fd ) static struct ioctl_call *find_ioctl_call( struct device *device, struct thread *thread, client_ptr_t user_arg ) { - struct ioctl_call *ioctl; + struct call_object *ioctl;
- LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry ) - if (ioctl->thread == thread && ioctl->user_arg == user_arg) return ioctl; + LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct call_object, dev_entry ) + if (ioctl->thread == thread && ioctl->user_arg == user_arg && ioctl->type == CALL_IOCTL) return (struct ioctl_call *)ioctl;
set_error( STATUS_INVALID_PARAMETER ); return NULL; @@ -323,8 +437,8 @@ static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_ if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() ))) return 0;
- ioctl->thread = (struct thread *)grab_object( current ); - ioctl->user_arg = async_data->arg; + ioctl->call.thread = (struct thread *)grab_object( current ); + ioctl->call.user_arg = async_data->arg;
if (!(handle = alloc_handle( current->process, ioctl, SYNCHRONIZE, 0 ))) { @@ -482,9 +596,11 @@ DECL_HANDLER(delete_device) }
-/* retrieve the next pending device ioctl request */ +/* retrieve the next pending device request */ DECL_HANDLER(get_next_device_request) { + struct call_object *call; + struct open_call *open; struct ioctl_call *ioctl; struct device_manager *manager; struct list *ptr; @@ -502,24 +618,46 @@ DECL_HANDLER(get_next_device_request) close_handle( current->process, req->prev ); /* avoid an extra round-trip for close */ release_object( ioctl ); } + if ((open = (struct open_call *)get_handle_obj( current->process, req->prev, + 0, &open_call_ops ))) + { + complete_open( open, req->status ); + close_handle( current->process, req->prev ); /* avoid an extra round-trip for close */ + release_object( open ); + } clear_error(); }
if ((ptr = list_head( &manager->requests ))) { - ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry ); - reply->code = ioctl->code; - reply->user_ptr = ioctl->device->user_ptr; - reply->in_size = ioctl->in_size; - reply->out_size = ioctl->out_size; - if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW ); - else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 ))) + call = LIST_ENTRY( ptr, struct call_object, mgr_entry ); + reply->user_ptr = call->device->user_ptr; + switch (call->type) { - set_reply_data_ptr( ioctl->in_data, ioctl->in_size ); - ioctl->in_data = NULL; - ioctl->in_size = 0; - list_remove( &ioctl->mgr_entry ); - list_init( &ioctl->mgr_entry ); + case CALL_OPEN: + open = (struct ioctl_call *)call; + reply->data.open.access = open->access; + reply->data.open.sharing = open->sharing; + reply->data.open.options = open->options; + if ((reply->next = alloc_handle( current->process, open, 0, 0 ))) + { + list_remove( &call->mgr_entry ); + list_init( &call->mgr_entry ); + } + case CALL_IOCTL: + ioctl = (struct ioctl_call *)call; + reply->data.ioctl.code = ioctl->code; + reply->data.ioctl.in_size = ioctl->in_size; + reply->data.ioctl.out_size = ioctl->out_size; + if (ioctl->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW ); + else if ((reply->next = alloc_handle( current->process, ioctl, 0, 0 ))) + { + set_reply_data_ptr( ioctl->in_data, ioctl->in_size ); + ioctl->in_data = NULL; + ioctl->in_size = 0; + list_remove( &call->mgr_entry ); + list_init( &call->mgr_entry ); + } } } else set_error( STATUS_PENDING ); diff --git a/server/protocol.def b/server/protocol.def index a0e1702..e554112 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3102,18 +3102,39 @@ enum message_type @END
-/* Retrieve the next pending device ioctl request */ +enum server_call_type +{ + CALL_OPEN, + CALL_IOCTL +}; + +union next_request +{ + struct + { + ioctl_code_t code; /* ioctl code */ + data_size_t in_size; /* total needed input size */ + data_size_t out_size; /* needed output size */ + } ioctl; + struct + { + unsigned int access; + unsigned int sharing; + unsigned int options; + } open; +}; + +/* Retrieve the next pending device request */ @REQ(get_next_device_request) obj_handle_t manager; /* handle to the device manager */ - obj_handle_t prev; /* handle to the previous ioctl */ - unsigned int status; /* status of the previous ioctl */ + obj_handle_t prev; /* handle to the previous request */ + unsigned int status; /* status of the previous request */ VARARG(prev_data,bytes); /* output data of the previous ioctl */ @REPLY - obj_handle_t next; /* handle to the next ioctl */ - ioctl_code_t code; /* ioctl code */ + obj_handle_t next; /* handle to the next request */ + enum server_call_type type; /* type of this request */ client_ptr_t user_ptr; /* opaque ptr for the device */ - data_size_t in_size; /* total needed input size */ - data_size_t out_size; /* needed output size */ + union next_request data; /* data associated with the next request */ VARARG(next_data,bytes); /* input data of the next ioctl */ @END
diff --git a/server/thread.c b/server/thread.c index f45be24..a1b4120 100644 --- a/server/thread.c +++ b/server/thread.c @@ -474,7 +474,7 @@ void stop_thread( struct thread *thread ) }
/* suspend a thread */ -static int suspend_thread( struct thread *thread ) +int suspend_thread( struct thread *thread ) { int old_count = thread->suspend; if (thread->suspend < MAXIMUM_SUSPEND_COUNT) @@ -486,7 +486,7 @@ static int suspend_thread( struct thread *thread ) }
/* resume a thread */ -static int resume_thread( struct thread *thread ) +int resume_thread( struct thread *thread ) { int old_count = thread->suspend; if (thread->suspend > 0)
Charles Davis wrote:
Alexandre Julliard wrote:
Charles Davis cdavis@mymail.mines.edu writes:
I thought I fixed all the issues. What's wrong with my patches now?
Many things, it's a lot more complicated than that. For instance you can't just kill the fstab support, this needs to be preserved somehow, probably on the mountmgr side. Also you can't have a single file descriptor per device, you need one for each open.
OK, I can do that.
I've decided to do the open in mountmgr, so I can have it handle changes to the fstab while it's running. So, I'm working on implementing IRP_MJ_CREATE support (which is the standard way for drivers to handle open requests). I've attached a first stab at that. Can you take a look? I'm pretty sure there's something I'm missing.
BTW, I'm on #winehackers as I write this (my nick is cdavis5x).
Chip
Please disregard both my emails. (The second one was because my email client complained that it failed to send the email.) That patch I sent is riddled with problems. (I should know better by now, but apparently, I don't. Once again, I jumped the gun, so to speak.) I'll have a better version ready by tomorrow.