Заставить PnP менеджер послать IRP_MN_QUERY_REMOVE_DEVICE ещё раз

Тема в разделе "WASM.NT.KERNEL", создана пользователем Sheph, 9 июл 2009.

  1. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    Ситуация следующая: есть PnP Device FDO (Не Bus FDO), который создаёт legacy DO (который фактически не знает о том что он как-то связан с PnP) и на него SymLink. Юзер может открыть этот legacy DO через SymLink и работать с ним.
    Допустим мы хотим удалить FDO, тогда в PnP dispatch routine объекта FDO приходит IRP_MN_QUERY_REMOVE_DEVICE,
    теперь:

    1. Если legacy DO открыт, то мы возвращаем STATUS_DEVICE_BUSY, т.к устройство занято, мы не хотим выгружать его сейчас.
    2. Мы закрываем legacy DO и снова пытаемся удалить FDO, но IRP_MN_QUERY_REMOVE_DEVICE повторно не приходит и устройство будет висеть в системе до перезагрузки.

    Вопрос: как дать понять PnP менеджеру что наше устройство можно попробовать удалить ещё раз ? чтобы он снова послал IRP_MN_QUERY_REMOVE_DEVICE, тогда я отвечу STATUS_SUCCESS, получу IRP_MN_REMOVE_DEVICE и удалю устройство.

    Пробовал через IoInvalidateDeviceState, но с его помощью можно лишь дать понять что устройства уже нет, тогда PnP менеджер пошлёт IRP_MN_REMOVE_DEVICE сразу, а мне нужно чтобы он сначала спросил с помощью IRP_MN_QUERY_REMOVE_DEVICE.

    Пробовал также делать ObReferenceObject на FDO, чтобы дать системе понять что на него есть ссылка и выгружать его нельзя, не помогло.

    Пробовал ObOpenObjectByPointer чтобы открыть хэндл на FDO, тоже не помогло, всё равно шлёт IRP_MN_QUERY_REMOVE_DEVICE и если я отвечаю что busy то всё, устройство не выгрузить...
     
  2. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
    MSDN читал? http://msdn.microsoft.com/en-us/library/aa489854.aspx
     
  3. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    g00r, первым делом, но там ничего нет по моему вопросу. да, если я верну допустим STATUS_UNSUCCESSFUL, то PnP менеджер поймёт что устройство удалять нельзя. но это в данный момент времени нельзя, а что если потом будет можно, как дать PnP менеджеру понять, что теперь всё ok и устройство удалять можно ?
    Мне просто непонято почему PnP менеджер не пересылает IRP_MN_QUERY_REMOVE_DEVICE когда я даю девайсу комманду remove (например из device manager'а), ведь логичнее было бы посылать этот IRP всякий раз и проверять можно ли удалить девайс сейчас или нет
     
  4. Wizard109

    Wizard109 New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2006
    Сообщения:
    346
    А можно отсрочить возврат STATUS_UNSUCCESSFUL возвратив STATUS_PENDING ?
     
  5. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    Wizard109, это будет немного не то, тогда, скажем, нажимая remove в device manager'е я буду висеть и ждать пока мой виртуальный девайс можно будет закрыть, а этот момент может настать через час к примеру. Возможно, прождав какое-то время PnP менеджер сам всё поймёт и отменить запрос, да, надо будет попробовать как-нибудь, спасибо!
     
  6. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
    Я имел ввиду обработку запроса IRP_MN_CANCEL_REMOVE_DEVICE. Можно посмотреть код?
     
  7. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    g00r, вот:
    Код (Text):
    1.         case IRP_MN_QUERY_REMOVE_DEVICE:
    2.         {  
    3.             if (!CardMakeUnavailable(DevExt->Card))
    4.             {                
    5.                 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
    6.                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
    7.  
    8.                 VCADIRPEpilogue(TO_COMMON_EXTENSION(DevExt), Irp);            
    9.  
    10.                 return STATUS_UNSUCCESSFUL;
    11.             }
    12.  
    13.             ReaderStallRequests(DeviceObject);
    14.  
    15.             KeAcquireSpinLock(&DevExt->StateLock, &OldIrql);
    16.  
    17.             SET_NEW_PNP_STATE(DevExt, RemovePending);
    18.    
    19.             KeReleaseSpinLock(&DevExt->StateLock, OldIrql);
    20.            
    21.             Irp->IoStatus.Status = STATUS_SUCCESS;
    22.  
    23.             break;
    24.         }
    25.         case IRP_MN_CANCEL_REMOVE_DEVICE:
    26.         {              
    27.             KeAcquireSpinLock(&DevExt->StateLock, &OldIrql);
    28.  
    29.             if(DevExt->DevicePnPState == RemovePending)
    30.             {                
    31.                 RESTORE_PREVIOUS_PNP_STATE(DevExt);
    32.  
    33.                 KeReleaseSpinLock(&DevExt->StateLock, OldIrql);
    34.  
    35.                 ReaderRestartRequests(DeviceObject);
    36.  
    37.                 CardMakeAvailable(DevExt->Card);
    38.             }
    39.             else
    40.             {
    41.                 KeReleaseSpinLock(&DevExt->StateLock, OldIrql);
    42.             }
    43.  
    44.             Irp->IoStatus.Status = STATUS_SUCCESS;
    45.  
    46.             break;
    47.         }
    далее в конце switch:
    Код (Text):
    1.     IoSkipCurrentIrpStackLocation(Irp);
    2.     Status = IoCallDriver(DevExt->LowerDeviceObject, Irp);        
    3.  
    4.     VCADIRPEpilogue(TO_COMMON_EXTENSION(DevExt), Irp);    
    5.    
    6.     return Status;
     
  8. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
    А каким образом диспетчер PnP узнает о том, что устройтсво нужно удалить в первый раз?
     
  9. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    g00r, при помощи 'SetupApi', грубо говоря, когда я нажму на 'Remove Device' в окне 'Device Manager'а', что аналогично вызову:
    Код (Text):
    1. SetupDiCallClassInstaller(DIF_REMOVE, ..., ...);
    первый-то раз оно приходит, а вот второй уже нет. т.е второй вызов этой функции просто ничего не делает. PnP Manager думает что девайс нельзя удалить до следующей перезагрузки и предлагает ребутнуться. Может это просто особенность работы windows...
     
  10. g00r

    g00r New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    20
    Вроде по идеи, нужно в начале PnpDispatch вызвать IoInitializeRemoveLock(...), а
    после обработки запроса IoReleaseRemoveLock(...).
     
  11. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    g00r, у меня это делается с помощью VCADIRPPrologue/VCADIRPEpilogue (там ещё дополнительные вещи проверяются), но это к делу не относится. IoAcquireRemoveLock тебя всё равно пропустит если ты не вызвал IoReleaseRemoveLockAndWait, а это обычно делается в IRP_MN_REMOVE_DEVICE, а до туда у меня дело так или иначе не доходит.
     
  12. Wizard109

    Wizard109 New Member

    Публикаций:
    0
    Регистрация:
    6 ноя 2006
    Сообщения:
    346
    Откровенно говоря я не встречал девайса, который откладывает процедуру своего удаления на время большее чем 10 сек... М/б правдо особенность работы Windows.
    Т.е. если такой девайс присуцтвует, то пользователю нужно выдать мессагу с предложением перезагрузиться....
     
  13. Sheph

    Sheph New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    89
    Ну да, у меня сейчас так и происходит. Просто допустим в линуксе когда я выгружаю драйвер он мне вернёт EBUSY если девайс занят, а потом я могу попробовать выгрузить ещё раз и если на этот раз девайс свободен то он выгрузится, в винде видимо так не получится...