[PATCH 3/5] ntoskrnl.exe/tests: Add some pending / remove tests.
Rémi Bernon
rbernon at codeweavers.com
Mon Jun 28 05:22:56 CDT 2021
This shows that removing a device should send IRP_MN_SURPRISE_REMOVAL
only, and that it's still possible to use DeviceIoControl on already
opened handles.
IRP_MN_REMOVE_DEVICE should only be sent when all then opened handles
are closed.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/ntoskrnl.exe/tests/driver.h | 2 +
dlls/ntoskrnl.exe/tests/driver_pnp.c | 81 ++++++++++++++++++++++++++--
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 30 ++++++++++-
3 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h
index 2c62baa0a61..455695ad36b 100644
--- a/dlls/ntoskrnl.exe/tests/driver.h
+++ b/dlls/ntoskrnl.exe/tests/driver.h
@@ -35,6 +35,8 @@
#define IOCTL_WINETEST_RETURN_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_MISMATCHED_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80b, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_WINETEST_MARK_PENDING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_WINETEST_CHECK_REMOVED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80e, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_BUS_MAIN CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_BUS_REGISTER_IFACE CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 774c98bae89..58dd32039cf 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -41,6 +41,11 @@ static UNICODE_STRING control_symlink, bus_symlink;
static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *bus_fdo, *bus_pdo;
+static DWORD remove_device_count;
+static DWORD surprise_removal_count;
+static DWORD query_remove_device_count;
+static DWORD cancel_remove_device_count;
+
struct device
{
struct list entry;
@@ -51,6 +56,36 @@ struct device
DEVICE_POWER_STATE power_state;
};
+static IRP *pop_pending_irp(DEVICE_OBJECT *device)
+{
+ KDEVICE_QUEUE_ENTRY *entry;
+ IRP *irp;
+
+ if (!(entry = KeRemoveDeviceQueue(&device->DeviceQueue))) irp = NULL;
+ else irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.DeviceQueueEntry);
+
+ return irp;
+}
+
+static NTSTATUS push_pending_irp(DEVICE_OBJECT *device, IRP *irp)
+{
+ do { IoMarkIrpPending(irp); }
+ while (!KeInsertDeviceQueue(&device->DeviceQueue, &irp->Tail.Overlay.DeviceQueueEntry));
+
+ return STATUS_PENDING;
+}
+
+static void remove_pending_irps(DEVICE_OBJECT *device)
+{
+ IRP *irp;
+
+ while ((irp = pop_pending_irp(device)))
+ {
+ irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ }
+}
+
static struct list device_list = LIST_INIT(device_list);
static FAST_MUTEX driver_lock;
@@ -207,6 +242,8 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
POWER_STATE state = {.DeviceState = PowerDeviceD0};
NTSTATUS status;
+ KeInitializeDeviceQueue(&device_obj->DeviceQueue);
+
ok(!stack->Parameters.StartDevice.AllocatedResources, "expected no resources\n");
ok(!stack->Parameters.StartDevice.AllocatedResourcesTranslated, "expected no translated resources\n");
@@ -223,6 +260,14 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
}
case IRP_MN_REMOVE_DEVICE:
+ /* should've been checked and reset by IOCTL_WINETEST_CHECK_REMOVED */
+ ok(remove_device_count == 0, "expected no IRP_MN_REMOVE_DEVICE\n");
+ todo_wine ok(surprise_removal_count == 0, "expected no IRP_MN_SURPRISE_REMOVAL\n");
+ ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
+ ok(cancel_remove_device_count == 0, "expected no IRP_MN_CANCEL_REMOVE_DEVICE\n");
+
+ remove_device_count++;
+ remove_pending_irps(device_obj);
if (device->removed)
{
IoSetDeviceInterfaceState(&device->child_symlink, FALSE);
@@ -289,8 +334,20 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
break;
}
- case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
+ surprise_removal_count++;
+ remove_pending_irps(device_obj);
+ ret = STATUS_SUCCESS;
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ query_remove_device_count++;
+ remove_pending_irps(device_obj);
+ ret = STATUS_SUCCESS;
+ break;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ cancel_remove_device_count++;
ret = STATUS_SUCCESS;
break;
}
@@ -579,8 +636,10 @@ static NTSTATUS fdo_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG code)
}
}
-static NTSTATUS pdo_ioctl(struct device *device, IRP *irp, IO_STACK_LOCATION *stack, ULONG code)
+static NTSTATUS pdo_ioctl(DEVICE_OBJECT *device_obj, IRP *irp, IO_STACK_LOCATION *stack, ULONG code)
{
+ struct device *device = device_obj->DeviceExtension;
+
switch (code)
{
case IOCTL_WINETEST_CHILD_GET_ID:
@@ -590,6 +649,20 @@ static NTSTATUS pdo_ioctl(struct device *device, IRP *irp, IO_STACK_LOCATION *st
irp->IoStatus.Information = sizeof(device->id);
return STATUS_SUCCESS;
+ case IOCTL_WINETEST_MARK_PENDING:
+ return push_pending_irp(device_obj, irp);
+
+ case IOCTL_WINETEST_CHECK_REMOVED:
+ ok(remove_device_count == 0, "expected IRP_MN_REMOVE_DEVICE\n");
+ ok(surprise_removal_count == 1, "expected IRP_MN_SURPRISE_REMOVAL\n");
+ ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n");
+ ok(cancel_remove_device_count == 0, "expected no IRP_MN_CANCEL_REMOVE_DEVICE\n");
+ remove_device_count = 0;
+ surprise_removal_count = 0;
+ query_remove_device_count = 0;
+ cancel_remove_device_count = 0;
+ return STATUS_SUCCESS;
+
default:
ok(0, "Unexpected ioctl %#x.\n", code);
return STATUS_NOT_IMPLEMENTED;
@@ -605,10 +678,10 @@ static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp)
if (device == bus_fdo)
status = fdo_ioctl(irp, stack, code);
else
- status = pdo_ioctl(device->DeviceExtension, irp, stack, code);
+ status = pdo_ioctl(device, irp, stack, code);
irp->IoStatus.Status = status;
- IoCompleteRequest(irp, IO_NO_INCREMENT);
+ if (status != STATUS_PENDING) IoCompleteRequest(irp, IO_NO_INCREMENT);
return status;
}
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 432bc168259..8fdb6c75f99 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -1150,10 +1150,11 @@ static void test_pnp_devices(void)
};
HDEVNOTIFY notify_handle;
DWORD size, type, dword;
+ HANDLE bus, child, tmp;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING string;
+ OVERLAPPED ovl = {0};
IO_STATUS_BLOCK io;
- HANDLE bus, child;
HDEVINFO set;
HWND window;
BOOL ret;
@@ -1349,6 +1350,14 @@ static void test_pnp_devices(void)
CloseHandle(child);
+ ret = NtOpenFile(&child, SYNCHRONIZE, &attr, &io, 0, 0);
+ ok(!ret, "failed to open child: %#x\n", ret);
+
+ ret = DeviceIoControl(child, IOCTL_WINETEST_MARK_PENDING, NULL, 0, NULL, 0, &size, &ovl);
+ ok(!ret, "DeviceIoControl succeded\n");
+ ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError());
+ ok(size == 0, "got size %u\n", size);
+
id = 1;
ret = DeviceIoControl(bus, IOCTL_WINETEST_BUS_REMOVE_CHILD, &id, sizeof(id), NULL, 0, &size, NULL);
ok(ret, "got error %u\n", GetLastError());
@@ -1357,7 +1366,24 @@ static void test_pnp_devices(void)
ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival);
ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal);
- ret = NtOpenFile(&child, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
+ ret = DeviceIoControl(child, IOCTL_WINETEST_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL);
+ todo_wine ok(ret, "got error %u\n", GetLastError());
+
+ ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
+ todo_wine ok(ret == STATUS_NO_SUCH_DEVICE, "got %#x\n", ret);
+
+ ret = GetOverlappedResult(child, &ovl, &size, TRUE);
+ ok(!ret, "unexpected success.\n");
+ ok(GetLastError() == ERROR_DEVICE_REMOVED, "got error %u\n", GetLastError());
+ ok(size == 0, "got size %u\n", size);
+
+ CloseHandle(child);
+
+ pump_messages();
+ ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival);
+ ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal);
+
+ ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT);
ok(ret == STATUS_OBJECT_NAME_NOT_FOUND, "got %#x\n", ret);
CloseHandle(bus);
--
2.32.0
More information about the wine-devel
mailing list