Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

View: New views
5 Messages — Rating Filter:   Alert me  

Parent Message unknown Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

by Charles Davis-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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




Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

by Alexandre Julliard :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Charles Davis <cdavis@...> 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
julliard@...



Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

by Charles Davis-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Alexandre Julliard wrote:
> Charles Davis <cdavis@...> 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)



Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

by Charles Davis-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Alexandre Julliard wrote:
> Charles Davis <cdavis@...> 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)



Re: [PATCH 0/3] Handling DOS drives in mountmgr (try 2)

by Charles Davis-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Charles Davis wrote:

> Alexandre Julliard wrote:
>> Charles Davis <cdavis@...> 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.