mirror of
https://github.com/reactos/reactos.git
synced 2025-05-07 02:41:22 +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;
|
||||
}
|
||||
|
||||
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
|
||||
BOOL
|
||||
LDEVOBJ_bEnableDriver(
|
||||
|
@ -200,7 +169,10 @@ LDEVOBJ_bEnableDriver(
|
|||
DRVENABLEDATA ded;
|
||||
ULONG i;
|
||||
|
||||
TRACE("LDEVOBJ_bEnableDriver('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
|
||||
|
||||
ASSERT(pldev);
|
||||
ASSERT(pldev->cRefs == 0);
|
||||
|
||||
/* Call the drivers DrvEnableDriver function */
|
||||
RtlZeroMemory(&ded, sizeof(ded));
|
||||
|
@ -223,58 +195,21 @@ LDEVOBJ_bEnableDriver(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
ULONG
|
||||
LDEVOBJ_ulGetDriverModes(
|
||||
_In_ LPWSTR pwszDriverName,
|
||||
_In_ HANDLE hDriver,
|
||||
_Out_ PDEVMODEW *ppdm)
|
||||
static
|
||||
VOID
|
||||
LDEVOBJ_vDisableDriver(
|
||||
_Inout_ PLDEVOBJ pldev)
|
||||
{
|
||||
PLDEVOBJ pldev = NULL;
|
||||
ULONG cbSize = 0;
|
||||
PDEVMODEW pdm = NULL;
|
||||
ASSERT(pldev);
|
||||
ASSERT(pldev->cRefs == 0);
|
||||
|
||||
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)
|
||||
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)
|
||||
if (pldev->pfn.DisableDriver)
|
||||
{
|
||||
ERR("DrvGetModes returned 0\n");
|
||||
goto cleanup;
|
||||
/* Call the unload function */
|
||||
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
|
||||
|
@ -323,6 +258,41 @@ LDEVOBJ_pvFindImageProcAddress(
|
|||
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
|
||||
LDEVOBJ_pLoadInternal(
|
||||
_In_ PFN_DrvEnableDriver pfnEnableDriver,
|
||||
|
@ -469,7 +439,7 @@ LDEVOBJ_pLoadDriver(
|
|||
ERR("LDEVOBJ_bEnableDriver failed\n");
|
||||
|
||||
/* Unload the image. */
|
||||
LDEVOBJ_vUnloadImage(pldev);
|
||||
LDEVOBJ_bUnloadImage(pldev);
|
||||
LDEVOBJ_vFreeLDEV(pldev);
|
||||
pldev = NULL;
|
||||
goto leave;
|
||||
|
@ -491,6 +461,102 @@ leave:
|
|||
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
|
||||
LDEVOBJ_bBuildDevmodeList(
|
||||
_Inout_ PGRAPHICS_DEVICE pGraphicsDevice)
|
||||
|
@ -691,25 +757,7 @@ EngUnloadImage(
|
|||
/* Make sure the LDEV is in the list */
|
||||
ASSERT((pldev->leLink.Flink != NULL) && (pldev->leLink.Blink != NULL));
|
||||
|
||||
/* Lock loader */
|
||||
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);
|
||||
LDEVOBJ_vDereference(pldev);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue