mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 18:56:48 +00:00
[WIN32SS] Rewrite LDEVOBJ reference counting
- introduce LDEVOBJ_vDisableDriver (reversal of LDEVOBJ_bEnableDriver) - introduce LDEVOBJ_bUnloadImage (reversal of LDEVOBJ_pLoadDriver) - introduce LDEVOBJ_vDereference, to remove a reference to a LDEVOBJ Also: - correctly handle success to unload the image, by removing it from pldev list - correctly handle failure to unload the image, by re-enabling the driver - simplify EngUnloadImage, as a wrapper around LDEVOBJ_vDereference - move LDEVOBJ_ulGetDriverModes lower to prevent forward declaration of LDEVOBJ_vDereference Unfortunately, disable driver unloading as long as ntoskrnl can't reload a driver it just unloaded...
This commit is contained in:
parent
3a1a2aa16f
commit
1744b01ad9
1 changed files with 146 additions and 98 deletions
|
@ -160,37 +160,6 @@ LDEVOBJ_bLoadImage(
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
LDEVOBJ_vUnloadImage(
|
|
||||||
_Inout_ PLDEVOBJ pldev)
|
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
/* Make sure we have a driver info */
|
|
||||||
ASSERT(pldev && pldev->pGdiDriverInfo != NULL);
|
|
||||||
|
|
||||||
/* Check if we have loaded a driver */
|
|
||||||
if (pldev->pfn.DisableDriver)
|
|
||||||
{
|
|
||||||
/* Call the unload function */
|
|
||||||
pldev->pfn.DisableDriver();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unload the driver */
|
|
||||||
Status = ZwSetSystemInformation(SystemUnloadGdiDriverInformation,
|
|
||||||
&pldev->pGdiDriverInfo->SectionPointer,
|
|
||||||
sizeof(HANDLE));
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ERR("Failed to unload the driver, this is bad.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the driver info structure */
|
|
||||||
ExFreePoolWithTag(pldev->pGdiDriverInfo, GDITAG_LDEV);
|
|
||||||
pldev->pGdiDriverInfo = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
BOOL
|
BOOL
|
||||||
LDEVOBJ_bEnableDriver(
|
LDEVOBJ_bEnableDriver(
|
||||||
|
@ -200,7 +169,10 @@ LDEVOBJ_bEnableDriver(
|
||||||
DRVENABLEDATA ded;
|
DRVENABLEDATA ded;
|
||||||
ULONG i;
|
ULONG i;
|
||||||
|
|
||||||
|
TRACE("LDEVOBJ_bEnableDriver('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
|
||||||
|
|
||||||
ASSERT(pldev);
|
ASSERT(pldev);
|
||||||
|
ASSERT(pldev->cRefs == 0);
|
||||||
|
|
||||||
/* Call the drivers DrvEnableDriver function */
|
/* Call the drivers DrvEnableDriver function */
|
||||||
RtlZeroMemory(&ded, sizeof(ded));
|
RtlZeroMemory(&ded, sizeof(ded));
|
||||||
|
@ -223,58 +195,21 @@ LDEVOBJ_bEnableDriver(
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG
|
static
|
||||||
LDEVOBJ_ulGetDriverModes(
|
VOID
|
||||||
_In_ LPWSTR pwszDriverName,
|
LDEVOBJ_vDisableDriver(
|
||||||
_In_ HANDLE hDriver,
|
_Inout_ PLDEVOBJ pldev)
|
||||||
_Out_ PDEVMODEW *ppdm)
|
|
||||||
{
|
{
|
||||||
PLDEVOBJ pldev = NULL;
|
ASSERT(pldev);
|
||||||
ULONG cbSize = 0;
|
ASSERT(pldev->cRefs == 0);
|
||||||
PDEVMODEW pdm = NULL;
|
|
||||||
|
|
||||||
TRACE("LDEVOBJ_ulGetDriverModes('%ls', %p)\n", pwszDriverName, hDriver);
|
TRACE("LDEVOBJ_vDisableDriver('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
|
||||||
|
|
||||||
pldev = LDEVOBJ_pLoadDriver(pwszDriverName, LDEV_DEVICE_DISPLAY);
|
if (pldev->pfn.DisableDriver)
|
||||||
if (!pldev)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Mirror drivers may omit this function */
|
|
||||||
if (!pldev->pfn.GetModes)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Call the driver to get the required size */
|
|
||||||
cbSize = pldev->pfn.GetModes(hDriver, 0, NULL);
|
|
||||||
if (!cbSize)
|
|
||||||
{
|
{
|
||||||
ERR("DrvGetModes returned 0\n");
|
/* Call the unload function */
|
||||||
goto cleanup;
|
pldev->pfn.DisableDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a buffer for the DEVMODE array */
|
|
||||||
pdm = ExAllocatePoolWithTag(PagedPool, cbSize, GDITAG_DEVMODE);
|
|
||||||
if (!pdm)
|
|
||||||
{
|
|
||||||
ERR("Could not allocate devmodeinfo\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the driver again to fill the buffer */
|
|
||||||
cbSize = pldev->pfn.GetModes(hDriver, cbSize, pdm);
|
|
||||||
if (!cbSize)
|
|
||||||
{
|
|
||||||
/* Could not get modes */
|
|
||||||
ERR("DrvrGetModes returned 0 on second call\n");
|
|
||||||
ExFreePoolWithTag(pdm, GDITAG_DEVMODE);
|
|
||||||
pdm = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (pldev)
|
|
||||||
LDEVOBJ_vUnloadImage(pldev);
|
|
||||||
|
|
||||||
*ppdm = pdm;
|
|
||||||
return cbSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -323,6 +258,41 @@ LDEVOBJ_pvFindImageProcAddress(
|
||||||
return pvProcAdress;
|
return pvProcAdress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
BOOL
|
||||||
|
LDEVOBJ_bUnloadImage(
|
||||||
|
_Inout_ PLDEVOBJ pldev)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Make sure we have a driver info */
|
||||||
|
ASSERT(pldev && pldev->pGdiDriverInfo != NULL);
|
||||||
|
ASSERT(pldev->cRefs == 0);
|
||||||
|
|
||||||
|
TRACE("LDEVOBJ_bUnloadImage('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
|
||||||
|
|
||||||
|
/* Unload the driver */
|
||||||
|
#if 0
|
||||||
|
Status = ZwSetSystemInformation(SystemUnloadGdiDriverInformation,
|
||||||
|
&pldev->pGdiDriverInfo->SectionPointer,
|
||||||
|
sizeof(HANDLE));
|
||||||
|
#else
|
||||||
|
/* Unfortunately, ntoskrnl allows unloading a driver, but fails loading
|
||||||
|
* it again with STATUS_IMAGE_ALREADY_LOADED. Prevent this problem by
|
||||||
|
* never unloading any driver.
|
||||||
|
*/
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
#endif
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ExFreePoolWithTag(pldev->pGdiDriverInfo, GDITAG_LDEV);
|
||||||
|
pldev->pGdiDriverInfo = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
PLDEVOBJ
|
PLDEVOBJ
|
||||||
LDEVOBJ_pLoadInternal(
|
LDEVOBJ_pLoadInternal(
|
||||||
_In_ PFN_DrvEnableDriver pfnEnableDriver,
|
_In_ PFN_DrvEnableDriver pfnEnableDriver,
|
||||||
|
@ -469,7 +439,7 @@ LDEVOBJ_pLoadDriver(
|
||||||
ERR("LDEVOBJ_bEnableDriver failed\n");
|
ERR("LDEVOBJ_bEnableDriver failed\n");
|
||||||
|
|
||||||
/* Unload the image. */
|
/* Unload the image. */
|
||||||
LDEVOBJ_vUnloadImage(pldev);
|
LDEVOBJ_bUnloadImage(pldev);
|
||||||
LDEVOBJ_vFreeLDEV(pldev);
|
LDEVOBJ_vFreeLDEV(pldev);
|
||||||
pldev = NULL;
|
pldev = NULL;
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -491,6 +461,102 @@ leave:
|
||||||
return pldev;
|
return pldev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
LDEVOBJ_vDereference(
|
||||||
|
_Inout_ PLDEVOBJ pldev)
|
||||||
|
{
|
||||||
|
/* Lock loader */
|
||||||
|
EngAcquireSemaphore(ghsemLDEVList);
|
||||||
|
|
||||||
|
/* Decrement reference count */
|
||||||
|
ASSERT(pldev->cRefs > 0);
|
||||||
|
pldev->cRefs--;
|
||||||
|
|
||||||
|
/* More references left? */
|
||||||
|
if (pldev->cRefs > 0)
|
||||||
|
{
|
||||||
|
EngReleaseSemaphore(ghsemLDEVList);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LDEVOBJ_vDisableDriver(pldev);
|
||||||
|
|
||||||
|
if (LDEVOBJ_bUnloadImage(pldev))
|
||||||
|
{
|
||||||
|
/* Remove ldev from the list */
|
||||||
|
RemoveEntryList(&pldev->leLink);
|
||||||
|
|
||||||
|
/* Free the driver info structure */
|
||||||
|
LDEVOBJ_vFreeLDEV(pldev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("Failed to unload driver '%wZ', trying to re-enable it.\n", &pldev->pGdiDriverInfo->DriverName);
|
||||||
|
LDEVOBJ_bEnableDriver(pldev, pldev->pGdiDriverInfo->EntryPoint);
|
||||||
|
|
||||||
|
/* Increment again reference count */
|
||||||
|
pldev->cRefs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock loader */
|
||||||
|
EngReleaseSemaphore(ghsemLDEVList);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
LDEVOBJ_ulGetDriverModes(
|
||||||
|
_In_ LPWSTR pwszDriverName,
|
||||||
|
_In_ HANDLE hDriver,
|
||||||
|
_Out_ PDEVMODEW *ppdm)
|
||||||
|
{
|
||||||
|
PLDEVOBJ pldev = NULL;
|
||||||
|
ULONG cbSize = 0;
|
||||||
|
PDEVMODEW pdm = NULL;
|
||||||
|
|
||||||
|
TRACE("LDEVOBJ_ulGetDriverModes('%ls', %p)\n", pwszDriverName, hDriver);
|
||||||
|
|
||||||
|
pldev = LDEVOBJ_pLoadDriver(pwszDriverName, LDEV_DEVICE_DISPLAY);
|
||||||
|
if (!pldev)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Mirror drivers may omit this function */
|
||||||
|
if (!pldev->pfn.GetModes)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Call the driver to get the required size */
|
||||||
|
cbSize = pldev->pfn.GetModes(hDriver, 0, NULL);
|
||||||
|
if (!cbSize)
|
||||||
|
{
|
||||||
|
ERR("DrvGetModes returned 0\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a buffer for the DEVMODE array */
|
||||||
|
pdm = ExAllocatePoolWithTag(PagedPool, cbSize, GDITAG_DEVMODE);
|
||||||
|
if (!pdm)
|
||||||
|
{
|
||||||
|
ERR("Could not allocate devmodeinfo\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the driver again to fill the buffer */
|
||||||
|
cbSize = pldev->pfn.GetModes(hDriver, cbSize, pdm);
|
||||||
|
if (!cbSize)
|
||||||
|
{
|
||||||
|
/* Could not get modes */
|
||||||
|
ERR("DrvrGetModes returned 0 on second call\n");
|
||||||
|
ExFreePoolWithTag(pdm, GDITAG_DEVMODE);
|
||||||
|
pdm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pldev)
|
||||||
|
LDEVOBJ_vDereference(pldev);
|
||||||
|
|
||||||
|
*ppdm = pdm;
|
||||||
|
return cbSize;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
LDEVOBJ_bBuildDevmodeList(
|
LDEVOBJ_bBuildDevmodeList(
|
||||||
_Inout_ PGRAPHICS_DEVICE pGraphicsDevice)
|
_Inout_ PGRAPHICS_DEVICE pGraphicsDevice)
|
||||||
|
@ -691,25 +757,7 @@ EngUnloadImage(
|
||||||
/* Make sure the LDEV is in the list */
|
/* Make sure the LDEV is in the list */
|
||||||
ASSERT((pldev->leLink.Flink != NULL) && (pldev->leLink.Blink != NULL));
|
ASSERT((pldev->leLink.Flink != NULL) && (pldev->leLink.Blink != NULL));
|
||||||
|
|
||||||
/* Lock loader */
|
LDEVOBJ_vDereference(pldev);
|
||||||
EngAcquireSemaphore(ghsemLDEVList);
|
|
||||||
|
|
||||||
/* Decrement reference count */
|
|
||||||
pldev->cRefs--;
|
|
||||||
|
|
||||||
/* No more references left? */
|
|
||||||
if (pldev->cRefs == 0)
|
|
||||||
{
|
|
||||||
/* Remove ldev from the list */
|
|
||||||
RemoveEntryList(&pldev->leLink);
|
|
||||||
|
|
||||||
/* Unload the image and free the LDEV */
|
|
||||||
LDEVOBJ_vUnloadImage(pldev);
|
|
||||||
LDEVOBJ_vFreeLDEV(pldev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlock loader */
|
|
||||||
EngReleaseSemaphore(ghsemLDEVList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue