[PATCH 4/5] hidclass.sys: Stop accepting IRPs after device removal.

Zebediah Figura (she/her) zfigura at codeweavers.com
Thu Jul 1 10:16:19 CDT 2021


On 7/1/21 2:51 AM, Rémi Bernon wrote:
> Handle IRP_MN_SURPRISE_REMOVAL and notify device thread to stop it, but
> only wait for it in IRP_MN_REMOVE_DEVICE, as it's probably waiting for
> an IRP sent to the lower driver, which needs to be notified of removal
> too first.
> 
> Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
> ---
>   dlls/hidclass.sys/device.c | 39 ++++++++++++++++++++++++++++++++++++++
>   dlls/hidclass.sys/hid.h    |  3 +++
>   dlls/hidclass.sys/pnp.c    | 24 ++++++++++++++++++++++-
>   3 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c
> index 82366ad1888..d3f5fa90fc7 100644
> --- a/dlls/hidclass.sys/device.c
> +++ b/dlls/hidclass.sys/device.c
> @@ -431,11 +431,24 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
>       NTSTATUS rc = STATUS_SUCCESS;
>       IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
>       BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
> +    BOOL removed;
> +    KIRQL irql;
>   
>       irp->IoStatus.Information = 0;
>   
>       TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode);
>   
> +    KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
> +    removed = ext->u.pdo.removed;
> +    KeReleaseSpinLock(&ext->u.pdo.lock, irql);
> +
> +    if (removed)
> +    {
> +        irp->IoStatus.Status = STATUS_DELETE_PENDING;
> +        IoCompleteRequest(irp, IO_NO_INCREMENT);
> +        return STATUS_DELETE_PENDING;
> +    }
> +
>       switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
>       {
>           case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
> @@ -588,6 +601,19 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp)
>       NTSTATUS rc = STATUS_SUCCESS;
>       IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
>       int ptr = -1;
> +    BOOL removed;
> +    KIRQL irql;
> +
> +    KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
> +    removed = ext->u.pdo.removed;
> +    KeReleaseSpinLock(&ext->u.pdo.lock, irql);
> +
> +    if (removed)
> +    {
> +        irp->IoStatus.Status = STATUS_DELETE_PENDING;
> +        IoCompleteRequest(irp, IO_NO_INCREMENT);
> +        return STATUS_DELETE_PENDING;
> +    }
>   
>       packet = malloc(buffer_size);
>       ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
> @@ -662,7 +688,20 @@ NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp)
>       const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
>       HID_XFER_PACKET packet;
>       ULONG max_len;
> +    BOOL removed;
>       NTSTATUS rc;
> +    KIRQL irql;
> +
> +    KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
> +    removed = ext->u.pdo.removed;
> +    KeReleaseSpinLock(&ext->u.pdo.lock, irql);
> +
> +    if (removed)
> +    {
> +        irp->IoStatus.Status = STATUS_DELETE_PENDING;
> +        IoCompleteRequest(irp, IO_NO_INCREMENT);
> +        return STATUS_DELETE_PENDING;
> +    }
>   
>       irp->IoStatus.Information = 0;
>   
> diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h
> index 5a502840691..863bb9a8bd4 100644
> --- a/dlls/hidclass.sys/hid.h
> +++ b/dlls/hidclass.sys/hid.h
> @@ -67,6 +67,9 @@ typedef struct _BASE_DEVICE_EXTENSION
>               KSPIN_LOCK irp_queue_lock;
>               LIST_ENTRY irp_queue;
>   
> +            KSPIN_LOCK lock;
> +            BOOL       removed;

Style nitpick, but none of the other members of this structure are 
aligned...

> +
>               BOOL is_mouse;
>               UNICODE_STRING mouse_link_name;
>               BOOL is_keyboard;
> diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c
> index 5f59257cdf7..5d6fb3d068c 100644
> --- a/dlls/hidclass.sys/pnp.c
> +++ b/dlls/hidclass.sys/pnp.c
> @@ -359,11 +359,24 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp)
>       }
>   }
>   
> +static void remove_pending_irps(BASE_DEVICE_EXTENSION *ext)
> +{
> +    IRP *irp;
> +
> +    while ((irp = pop_irp_from_queue(ext)))
> +    {
> +        irp->IoStatus.Status = STATUS_DELETE_PENDING;
> +        IoCompleteRequest(irp, IO_NO_INCREMENT);
> +    }
> +}
> +
>   static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp)
>   {
>       IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
>       BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
>       NTSTATUS status = irp->IoStatus.Status;
> +    IRP *queued_irp;
> +    KIRQL irql;
>   
>       TRACE("irp %p, minor function %#x.\n", irp, irpsp->MinorFunction);
>   
> @@ -453,12 +466,14 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp)
>                   IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, TRUE);
>               if (ext->u.pdo.is_keyboard)
>                   IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, TRUE);
> +
> +            ext->u.pdo.removed = FALSE;
>               status = STATUS_SUCCESS;
>               break;
>   
>           case IRP_MN_REMOVE_DEVICE:
>           {
> -            IRP *queued_irp;
> +            remove_pending_irps(ext);

In that case there's no reason to delete queued IRPs later in the handler.

>   
>               send_wm_input_device_change(ext, GIDC_REMOVAL);
>   
> @@ -494,6 +509,13 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp)
>           }
>   
>           case IRP_MN_SURPRISE_REMOVAL:
> +            KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
> +            ext->u.pdo.removed = TRUE;
> +            KeReleaseSpinLock(&ext->u.pdo.lock, irql);
> +
> +            remove_pending_irps(ext);
> +
> +            SetEvent(ext->u.pdo.halt_event);
>               status = STATUS_SUCCESS;
>               break;
>   
> 



More information about the wine-devel mailing list