Извлечь USB во время IRP_MJ_SHUTDOWN - PullRequest
0 голосов
/ 30 марта 2020

Я работаю над драйвером файловой системы WDM Windows, который в настоящее время имеет проблему, из-за которой USB-накопитель не извлекается во время выключения, из-за чего он становится нечитаемым. Если устройство отключается до выключения Windows, оно работает нормально и не становится нечитаемым. Есть ли способ вызвать другой IRP из моего метода IRP_MJ_SHUTDOWN, который может обработать извлечение USB-накопителя до завершения моего метода выключения? Какой IRP обрабатывает извлечение?

Так настроены IRP. Насколько я знаю, когда IRP_MJ_SHUTDOWN вызывается Windows, он вызывает метод, указанный в инструкции switch ниже. Мне нужно обработать извлечение USB этим способом.

NTSTATUS
IrpDispatch
(
    IN PDEVICE_OBJECT VolDevice,
    IN PIRP Irp
)
{
    /* Global IRP dispatch entry */

    PIO_STACK_LOCATION  IrpSp;
    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    /* Check IRP type */
    switch (IrpSp->MajorFunction)
    {

    case IRP_MJ_FILE_SYSTEM_CONTROL:
        KdPrint(("IRP_MJ_FILE_SYSTEM_CONTROL\n"));
        return HrfsFileSystemControl(VolDevice, Irp);

    case IRP_MJ_READ:
        KdPrint(("IRP_MJ_READ\n"));
        return HrfsFsdRead(VolDevice, Irp);


    /*case IRP_MJ_DEVICE_CONTROL:
        KdPrint(("IRP_MJ_DEVICE_CONTROL\n"));
        return HrfsFsdDeviceControl(VolDevice, Irp);*/

    case IRP_MJ_QUERY_VOLUME_INFORMATION:
        KdPrint(("IRP_MJ_QUERY_VOLUME_INFORMATION\n"));
        return HrfsFsdQueryVolumeInformation(VolDevice, Irp);
    case IRP_MJ_CREATE:
        KdPrint(("IRP_MJ_CREATE\n"));
        return HrfsFsdCreate(VolDevice, Irp);
    case IRP_MJ_DIRECTORY_CONTROL:
        KdPrint(("IRP_MJ_DIRECTORY_CONTROL\n"));
        return HrfsFsdDirectoryControl(VolDevice, Irp);
    case IRP_MJ_QUERY_INFORMATION:
        KdPrint(("IRP_MJ_QUERY_INFORMATION\n"));
        return HrfsFsdQuery(VolDevice, Irp);
    case IRP_MJ_CLEANUP:
        KdPrint(("IRP_MJ_CLEANUP\n"));
        return HrfsFsdCleanup(VolDevice, Irp);
    case IRP_MJ_CLOSE:
        KdPrint(("IRP_MJ_CLOSE\n"));
        return HrfsFsdClose(VolDevice, Irp);

    case IRP_MJ_WRITE: 
        KdPrint(("IRP_MJ_WRITE\n"));
        return HrfsFsdWrite(VolDevice, Irp);

    case IRP_MJ_SET_INFORMATION:
        KdPrint(("IRP_MJ_SET_INFORMATION\n"));
        return HrfsFsdSet(VolDevice, Irp);
    case IRP_MJ_LOCK_CONTROL:
        KdPrint(("IRP_MJ_LOCK_CONTROL\n"));
        return HrfsFsdLockControl(VolDevice, Irp);

    case IRP_MJ_SET_VOLUME_INFORMATION:
        KdPrint(("IRP_MJ_SET_VOLUME_INFORMATION\n"));
        return HrfsFsdSetVolumeInformation(VolDevice, Irp);

    case IRP_MJ_SHUTDOWN:
        KdPrint(("IRP_MJ_SHUTDOWN\n"));
        return HrfsIrpShutdown(VolDevice, Irp);
    case IRP_MJ_PNP:
        KdPrint(("IRP_MJ_PNP\n"));
        return HrfsFsdPnp(VolDevice, Irp);
    case IRP_MJ_FLUSH_BUFFERS:
        KdPrint(("IRP_MJ_FLUSH_BUFFERS\n"));
        return HrfsFsdFlushBuffers(VolDevice, Irp);
    default:
        KdPrint(("Unsupported now [%d]!\n", IrpSp->MajorFunction));
        break;
    }
    /* for un-support IRP, finish it with error */
    HrfsCompleteIrp(NULL, Irp, STATUS_UNSUCCESSFUL);

    return STATUS_UNSUCCESSFUL;
}

Способы выключения ниже:

NTSTATUS
HrfsIrpShutdown
(
    IN PDEVICE_OBJECT VolDevice,
    IN PIRP Irp
)
{
    /* IRP dispatch routing for shutdown request */
    NTSTATUS Status;
    PIRP_CONTEXT IrpContext = NULL;

    BOOLEAN TopLevel;

    FsRtlEnterFileSystem(); // x

    TopLevel = HrfsIsIrpTopLevel(Irp); // x

    try
    {
        IrpContext = HrfsCreateIrpContext(Irp, TRUE); // x ?

        Status = HrfsShutdown(IrpContext, Irp);
    }
#ifdef HRFS_ENABLE_EXCEPTION_CHECK
    except(HrfsExceptionFilter(IrpContext, GetExceptionInformation()))
    {
        Status = HrfsProcessException(IrpContext, Irp, GetExceptionCode());
    }
#else
    finally
    {
        NOTHING;
    }
#endif
    if (TopLevel)
    {
        IoSetTopLevelIrp(NULL); // x
    }

    FsRtlExitFileSystem(); // x

    return Status;
}

Выключение

NTSTATUS
HrfsShutdown
(
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
)
{
    KEVENT Event;

    PLIST_ENTRY Links;
    PVCB Vcb = NULL; // +
    PIRP NewIrp;
    IO_STATUS_BLOCK Iosb;
    BOOLEAN VcbDeleted;

    KdPrint(("HRFSSHUTDOWN\n"));

    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS |
        IRP_CONTEXT_FLAG_WRITE_THROUGH);

    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    HrfsData.ShutdownStarted = TRUE;

    HrfsAcquireExclusiveGlobal(IrpContext);

    try
    {
        /* flush and clean all volume data */
        Links = HrfsData.VcbQueue.Flink;
        while (Links != &HrfsData.VcbQueue)
        {
            Vcb = CONTAINING_RECORD(Links, VCB, VcbLinks);

            Links = Links->Flink;

            if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ||
                (Vcb->VcbCondition != VcbGood))
            {
                continue;
            }

            HrfsAcquireExclusiveVolume(IrpContext, Vcb);

            try
            {
                HrfsFlushVolume(IrpContext, Vcb, Flush);

                /*HrfsFlushAndCleanVolume(IrpContext,
                    Irp,
                    Vcb,
                    Flush);*/

                if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY))
                {
                    CcPurgeCacheSection(&Vcb->SectionObjectPointers,
                        NULL,
                        0,
                        FALSE);
                }
            }

#ifdef HRFS_ENABLE_EXCEPTION_CHECK
            except(EXCEPTION_EXECUTE_HANDLER)
            {
                HrfsResetExceptionState(IrpContext);
            }
#else
            finally
            {
                NOTHING;
            }
#endif
            try
            {
                //Send a shutdown IRP to lower driver 
                NewIrp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
                    Vcb->TargetDeviceObject,
                    NULL,
                    0,
                    NULL,
                    &Event,
                    &Iosb);

                if (NewIrp != NULL)
                {
                    if (NT_SUCCESS(IoCallDriver(Vcb->TargetDeviceObject, NewIrp)))
                    {
                        KeWaitForSingleObject(&Event,
                            Executive,
                            KernelMode,
                            FALSE,
                            NULL);

                        KeClearEvent(&Event);
                    }
                }
            }
#ifdef HRFS_ENABLE_EXCEPTION_CHECK
            except(EXCEPTION_EXECUTE_HANDLER)
            {
                HrfsResetExceptionState(IrpContext);
            }
#else
            finally
            {
                NOTHING
            }
#endif

            SetFlag(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN);

            VcbDeleted = HrfsCheckForDismount(IrpContext,
                Vcb,
                FALSE);
            if (!VcbDeleted)
            {
                HrfsReleaseVolume(Vcb);
            }
        }
    }
    finally
    {

        HrfsReleaseGlobal();

        IoUnregisterFileSystem(HrfsDeviceObject);
        IoDeleteDevice(HrfsDeviceObject);

        HrfsCompleteIrp(IrpContext, Irp, STATUS_SUCCESS);
    }

    return STATUS_SUCCESS;
}
...