devrem.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. devrem.c
  5. Abstract:
  6. This module implements device removal functionality.
  7. Author:
  8. Chris Stevens 17-Jun-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "iop.h"
  17. #include "pmp.h"
  18. #include "pagecach.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // ------------------------------------------------------ Data Type Definitions
  24. //
  25. //
  26. // ----------------------------------------------- Internal Function Prototypes
  27. //
  28. KSTATUS
  29. IopSendRemovalIrp (
  30. PDEVICE Device
  31. );
  32. VOID
  33. IopDeviceDestroyDriverStack (
  34. PDEVICE Device
  35. );
  36. //
  37. // -------------------------------------------------------------------- Globals
  38. //
  39. //
  40. // ------------------------------------------------------------------ Functions
  41. //
  42. VOID
  43. IopPrepareRemoveDevice (
  44. PDEVICE Device,
  45. PDEVICE_WORK_ENTRY Work
  46. )
  47. /*++
  48. Routine Description:
  49. This routine prepares a device for removal. It puts the device in the
  50. awaiting removal state. If it has no children, it queues the removal work
  51. item on itself. If this routine discovers that the device is already in the
  52. awaiting removal state, it exits.
  53. Arguments:
  54. Device - Supplies a pointer to the device that is preparing to be removed.
  55. Work - Supplies a pointer to the work request.
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. BOOL QueueRemoval;
  61. KSTATUS Status;
  62. PVOLUME Volume;
  63. ASSERT(Work->Action == DeviceActionPrepareRemove);
  64. ASSERT((Work->Flags & DEVICE_ACTION_SEND_TO_SUBTREE) != 0);
  65. //
  66. // This device should not already be marked removed. If it was removed,
  67. // then no additional work items should have been scheduled on its queue.
  68. //
  69. ASSERT(Device->State != DeviceRemoved);
  70. //
  71. // If the device is already awaiting removal, that means that some process
  72. // already scheduled this prepare removal work item on this device. It
  73. // should get signaled for removal by its children. In this case, this
  74. // work entry no longer needs to traverse this device's subtree.
  75. //
  76. if (Device->State == DeviceAwaitingRemoval) {
  77. Work->Flags &= ~DEVICE_ACTION_SEND_TO_SUBTREE;
  78. goto PrepareRemoveDeviceEnd;
  79. }
  80. //
  81. // Acquire the lock here to synchronize with child device creation. By the
  82. // time this lock is acquired, any concurrently active device creations
  83. // are finished and any future attempts at creation should fail because the
  84. // device is now awaiting removal. This also synchronizes with removal so
  85. // a device does not get two removal work items queued - one by this
  86. // routine and another when the last child gets removed.
  87. //
  88. KeAcquireSharedExclusiveLockExclusive(Device->Lock);
  89. //
  90. // The state check above is safe because a device's queue items are
  91. // processed sequentially and only this work item moves the state to
  92. // awaiting removal. Assert this though for good measure.
  93. //
  94. ASSERT(Device->State != DeviceAwaitingRemoval);
  95. //
  96. // Mark the device as awaiting removal.
  97. //
  98. IopSetDeviceState(Device, DeviceAwaitingRemoval);
  99. //
  100. // Unsignal the device so that anyone waiting on it will have to let the
  101. // removal finish.
  102. //
  103. ObSignalObject(Device, SignalOptionUnsignal);
  104. //
  105. // If this is a volume, make sure that it is marked that it is in the
  106. // process of being unmounted.
  107. //
  108. if (Device->Header.Type == ObjectVolume) {
  109. Volume = (PVOLUME)Device;
  110. Volume->Flags |= VOLUME_FLAG_UNMOUNTING;
  111. }
  112. //
  113. // Queue removal on the device if it has no active children.
  114. //
  115. QueueRemoval = FALSE;
  116. if (LIST_EMPTY(&(Device->ActiveChildListHead)) != FALSE) {
  117. QueueRemoval = TRUE;
  118. }
  119. KeReleaseSharedExclusiveLockExclusive(Device->Lock);
  120. //
  121. // Queue the removal work item on this device if necessary. If this fails,
  122. // handle the queue failure, which will roll back the state of any device
  123. // waiting on this device's removal process.
  124. //
  125. // N.B. There could be another prepare to remove work item in this device's
  126. // queue that could end up succeeding removal, making the rollback
  127. // unnecessary. Don't bother to check, however. A parent that gets
  128. // rolled back can attempt removal again.
  129. //
  130. if (QueueRemoval != FALSE) {
  131. Status = IopQueueDeviceWork(Device,
  132. DeviceActionRemove,
  133. NULL,
  134. DEVICE_ACTION_CLOSE_QUEUE);
  135. if (!KSUCCESS(Status)) {
  136. IopHandleDeviceQueueFailure(Device, DeviceActionRemove);
  137. }
  138. }
  139. PrepareRemoveDeviceEnd:
  140. return;
  141. }
  142. VOID
  143. IopRemoveDevice (
  144. PDEVICE Device,
  145. PDEVICE_WORK_ENTRY Work
  146. )
  147. /*++
  148. Routine Description:
  149. This routine removes a device by sending a removal IRP and then removing
  150. the device reference added during device creation. The removal IRP allows
  151. the driver to clean up any necessary state that cannot be cleaned up by the
  152. object manager's destruction call-back.
  153. Arguments:
  154. Device - Supplies a pointer to the device that is to be removed.
  155. Work - Supplies a pointer to the work request.
  156. Return Value:
  157. None.
  158. --*/
  159. {
  160. PDEVICE ParentDevice;
  161. BOOL RemoveParent;
  162. KSTATUS Status;
  163. ASSERT(Device->State == DeviceAwaitingRemoval);
  164. ASSERT((Work->Flags & DEVICE_ACTION_CLOSE_QUEUE) != 0);
  165. ASSERT(Device->QueueState == DeviceQueueActiveClosing);
  166. ASSERT(LIST_EMPTY(&(Device->ActiveChildListHead)) != FALSE);
  167. ASSERT(KeGetRunLevel() == RunLevelLow);
  168. //
  169. // Attempt to remove any device paths that belong to the device. Do this
  170. // before the remove IRP in case something fails. It will be done again
  171. // after the remove IRP, ingorning failures.
  172. //
  173. Status = IopRemoveDevicePaths(Device);
  174. if (!KSUCCESS(Status)) {
  175. IopAbortDeviceRemoval(Device, DeviceProblemFailedPathRemoval, TRUE);
  176. goto RemoveDeviceEnd;
  177. }
  178. //
  179. // Acquire the device lock exclusive for the remove IRP to synchronize with
  180. // I/O opens, system control IRPs, and user control IRPs.
  181. //
  182. KeAcquireSharedExclusiveLockExclusive(Device->Lock);
  183. //
  184. // Clean up the power management state.
  185. //
  186. PmpRemoveDevice(Device);
  187. //
  188. // Send the removal IRP to the device. If this fails, the removal process
  189. // must be rolled back for this branch of the device tree.
  190. //
  191. Status = IopSendRemovalIrp(Device);
  192. if (!KSUCCESS(Status)) {
  193. KeReleaseSharedExclusiveLockExclusive(Device->Lock);
  194. IopAbortDeviceRemoval(Device, DeviceProblemFailedToSendRemoveIrp, TRUE);
  195. goto RemoveDeviceEnd;
  196. }
  197. //
  198. // With the removal IRP sent, rolling back should not happen anymore. Thus,
  199. // without further ado, declare this device removed.
  200. //
  201. IopSetDeviceState(Device, DeviceRemoved);
  202. ObSignalObject(Device, SignalOptionSignalAll);
  203. //
  204. // Remove the device from the global list so that racy folks trying to
  205. // look up the device by device ID must finish now. It would be bad to get
  206. // all the way down to releasing the last reference only to have that
  207. // lookup function try to re-add one.
  208. //
  209. KeAcquireQueuedLock(IoDeviceListLock);
  210. LIST_REMOVE(&(Device->ListEntry));
  211. Device->ListEntry.Next = NULL;
  212. KeReleaseQueuedLock(IoDeviceListLock);
  213. //
  214. // Officially close the work queue.
  215. //
  216. KeAcquireQueuedLock(Device->QueueLock);
  217. Device->QueueState = DeviceQueueClosed;
  218. KeReleaseQueuedLock(Device->QueueLock);
  219. //
  220. // Release the device lock to let everyone else waiting on the state see
  221. // that it has now switched to removed.
  222. //
  223. KeReleaseSharedExclusiveLockExclusive(Device->Lock);
  224. //
  225. // Clean up the device paths again, ignoring failures this time.
  226. //
  227. IopRemoveDevicePaths(Device);
  228. //
  229. // Evict any lingering file object entries in the page cache. Clean removal
  230. // should have flushed block devices by this point.
  231. //
  232. IopEvictFileObjects(Device->DeviceId, PAGE_CACHE_EVICTION_FLAG_REMOVE);
  233. //
  234. // Flush the file objects for the device. Eviction should have removed all
  235. // the page cache entries, but the file object properties may be dirty and
  236. // keeping the file objects for this device in the dirty file objects list.
  237. // The writes will fail, but the flush should do the job to moving them all
  238. // out of the list.
  239. //
  240. IopFlushFileObjects(
  241. Device->DeviceId,
  242. IO_FLAG_DATA_SYNCHRONIZED | IO_FLAG_METADATA_SYNCHRONIZED,
  243. NULL);
  244. //
  245. // Release any lingering file objects that may be stuck open for this
  246. // device. Be nice, and do it for other devices as well.
  247. //
  248. IopCleanupFileObjects();
  249. //
  250. // Determine which device to consider the parent. A volume's effective
  251. // "parent" is the target device.
  252. //
  253. if (Device->Header.Type == ObjectVolume) {
  254. ParentDevice = Device->TargetDevice;
  255. } else {
  256. ParentDevice = Device->ParentDevice;
  257. }
  258. ASSERT(ParentDevice->Header.ReferenceCount >= 2);
  259. //
  260. // Acquire the parent's device lock exclusively to free its active child
  261. // list and its state. This needs to happen under the lock to synchronize
  262. // with the parent's own prepare remove work item which can schedule the
  263. // remove work item on a device with no children.
  264. //
  265. KeAcquireSharedExclusiveLockExclusive(ParentDevice->Lock);
  266. //
  267. // With the device officially removed, remove it from its parent's list of
  268. // active children.
  269. //
  270. LIST_REMOVE(&(Device->ActiveListEntry));
  271. Device->ActiveListEntry.Next = NULL;
  272. //
  273. // Handle the special case where the device is a volume and it's "parent"
  274. // is its target device.
  275. //
  276. if (Device->Header.Type == ObjectVolume) {
  277. //
  278. // If the parent has no more children, then nothing is mounted.
  279. //
  280. if (LIST_EMPTY(&(ParentDevice->ActiveChildListHead)) != FALSE) {
  281. ParentDevice->Flags &= ~DEVICE_FLAG_MOUNTED;
  282. }
  283. }
  284. //
  285. // If the parent device is awaiting removal, determine if the given device
  286. // is its last active child.
  287. //
  288. RemoveParent = FALSE;
  289. if ((ParentDevice->State == DeviceAwaitingRemoval) &&
  290. (LIST_EMPTY(&(ParentDevice->ActiveChildListHead)) != FALSE)) {
  291. ObAddReference(ParentDevice);
  292. RemoveParent = TRUE;
  293. }
  294. KeReleaseSharedExclusiveLockExclusive(ParentDevice->Lock);
  295. //
  296. // Release the initial volume reference.
  297. //
  298. if (Device->Header.Type == ObjectVolume) {
  299. IoVolumeReleaseReference((PVOLUME)Device);
  300. }
  301. //
  302. // Release the reference taken by the object manager. This is not
  303. // necessarily the device's last reference.
  304. //
  305. ObReleaseReference(Device);
  306. //
  307. // Queue the removal of the parent if it has no more children.
  308. //
  309. if (RemoveParent != FALSE) {
  310. Status = IopQueueDeviceWork(ParentDevice,
  311. DeviceActionRemove,
  312. NULL,
  313. DEVICE_ACTION_CLOSE_QUEUE);
  314. if (!KSUCCESS(Status)) {
  315. IopHandleDeviceQueueFailure(ParentDevice, DeviceActionRemove);
  316. }
  317. ObReleaseReference(ParentDevice);
  318. }
  319. RemoveDeviceEnd:
  320. return;
  321. }
  322. VOID
  323. IopAbortDeviceRemoval (
  324. PDEVICE Device,
  325. DEVICE_PROBLEM DeviceProblem,
  326. BOOL RollbackDevice
  327. )
  328. /*++
  329. Routine Description:
  330. This routine aborts the device removal process for the given device. It
  331. also walks back up the device tree reverting the removal process for any
  332. ancestor devices that were awaiting the given device's removal.
  333. Arguments:
  334. Device - Supplies a pointer to the device that failed the removal process
  335. and requires rollback.
  336. DeviceProblem - Supplies the devices problem (i.e. the reason for the
  337. abort).
  338. RollbackDevice - Supplies a boolean indicating whether or not the supplied
  339. device should be included in the rollback.
  340. Return Value:
  341. None.
  342. --*/
  343. {
  344. PDEVICE CurrentDevice;
  345. PDEVICE ParentDevice;
  346. DEVICE_STATE PreviousState;
  347. ULONG PreviousStateIndex;
  348. PVOLUME Volume;
  349. ASSERT(Device->Header.ReferenceCount >= 1);
  350. //
  351. // This routine could be called when the given device is not marked for
  352. // removal. In this case, just start with the parent device. In the case of
  353. // volumes, the "parent" device is the target device.
  354. //
  355. if (RollbackDevice == FALSE) {
  356. ASSERT(Device->State != DeviceAwaitingRemoval);
  357. if (Device->Header.Type == ObjectVolume) {
  358. ASSERT(Device->TargetDevice != NULL);
  359. CurrentDevice = Device->TargetDevice;
  360. } else {
  361. CurrentDevice = Device->ParentDevice;
  362. }
  363. } else {
  364. ASSERT(Device->State == DeviceAwaitingRemoval);
  365. CurrentDevice = Device;
  366. }
  367. //
  368. // Look back up the device tree reverting all the device's ancestors out of
  369. // the awaiting removal state. Since the caller must have a reference on
  370. // the supplied device, this routine does not need to worry about devices
  371. // disappearing; every device holds a reference to its parent (including
  372. // volumes and their target device).
  373. //
  374. KeAcquireSharedExclusiveLockExclusive(CurrentDevice->Lock);
  375. while (CurrentDevice->State == DeviceAwaitingRemoval) {
  376. ASSERT(CurrentDevice->Header.ReferenceCount >= 1);
  377. PreviousStateIndex = CurrentDevice->StateHistoryNextIndex - 1;
  378. if (PreviousStateIndex == MAX_ULONG) {
  379. PreviousStateIndex = DEVICE_STATE_HISTORY - 1;
  380. }
  381. PreviousState = CurrentDevice->StateHistory[PreviousStateIndex];
  382. IopSetDeviceState(CurrentDevice, PreviousState);
  383. //
  384. // Modify the device's queue back to the correct state. This depends on
  385. // the current queue state and the previous device state.
  386. //
  387. KeAcquireQueuedLock(Device->QueueLock);
  388. //
  389. // Devices with closed queues should never need to be rolled back.
  390. //
  391. ASSERT(CurrentDevice->QueueState != DeviceQueueClosed);
  392. //
  393. // The only queue state that needs rolling back is the active closing
  394. // state. All other device removal aborts come from failing to queue an
  395. // action, which already rolls back the queue state correctly.
  396. //
  397. if (CurrentDevice->QueueState == DeviceQueueActiveClosing) {
  398. ASSERT(LIST_EMPTY(&(CurrentDevice->WorkQueue)) != FALSE);
  399. //
  400. // If the previous state was unreported, then the queue should be
  401. // marked closed. Otherwise, it is open.
  402. //
  403. if (PreviousState == DeviceUnreported) {
  404. CurrentDevice->QueueState = DeviceQueueClosed;
  405. } else {
  406. CurrentDevice->QueueState = DeviceQueueOpen;
  407. }
  408. }
  409. KeReleaseQueuedLock(Device->QueueLock);
  410. //
  411. // Signal anyone waiting on this device's removal state. It will no
  412. // longer reach that signal.
  413. //
  414. ObSignalObject(CurrentDevice, SignalOptionSignalAll);
  415. //
  416. // Move backwards up the tree. For a volume, the effective parent is
  417. // the target device.
  418. //
  419. if (CurrentDevice->Header.Type == ObjectVolume) {
  420. Volume = (PVOLUME)CurrentDevice;
  421. //
  422. // Also make sure that the volume is no longer marked as
  423. // "unmounting".
  424. //
  425. Volume->Flags &= ~VOLUME_FLAG_UNMOUNTING;
  426. ASSERT(Device->TargetDevice != NULL);
  427. ParentDevice = Device->TargetDevice;
  428. } else {
  429. ParentDevice = CurrentDevice->ParentDevice;
  430. }
  431. //
  432. // Release the current device's lock before gettings the parent's lock.
  433. //
  434. KeReleaseSharedExclusiveLockExclusive(CurrentDevice->Lock);
  435. //
  436. // Move up to the parent device and acquire its lock.
  437. //
  438. CurrentDevice = ParentDevice;
  439. KeAcquireSharedExclusiveLockExclusive(CurrentDevice->Lock);
  440. }
  441. KeReleaseSharedExclusiveLockExclusive(CurrentDevice->Lock);
  442. //
  443. // Set the device problem state on the orignal device to record that this
  444. // device is the origin of the removal failure.
  445. //
  446. IopSetDeviceProblem(Device, DeviceProblem, STATUS_UNSUCCESSFUL);
  447. return;
  448. }
  449. VOID
  450. IopDestroyDevice (
  451. PVOID Object
  452. )
  453. /*++
  454. Routine Description:
  455. This routine destroys a device and its resources. The object manager will
  456. clean up the object header, leaving this routine to clean up the device
  457. specific elements of the object. This routine is meant only as a callback
  458. for the object manager.
  459. Arguments:
  460. Object - Supplies a pointer to the object to be destroyed.
  461. Return Value:
  462. None.
  463. --*/
  464. {
  465. PDEVICE Device;
  466. Device = (PDEVICE)Object;
  467. ASSERT(KeGetRunLevel() == RunLevelLow);
  468. ASSERT(Device != NULL);
  469. ASSERT((Device->State == DeviceRemoved) ||
  470. (Device->State == DeviceUnreported));
  471. //
  472. // Remove the device from the global list if not already done.
  473. //
  474. if (Device->ListEntry.Next != NULL) {
  475. ASSERT(Device->State == DeviceUnreported);
  476. KeAcquireQueuedLock(IoDeviceListLock);
  477. LIST_REMOVE(&(Device->ListEntry));
  478. Device->ListEntry.Next = NULL;
  479. KeReleaseQueuedLock(IoDeviceListLock);
  480. }
  481. //
  482. // If there's a target device, release the reference on it.
  483. //
  484. if (Device->TargetDevice != NULL) {
  485. ObReleaseReference(Device->TargetDevice);
  486. }
  487. //
  488. // The device's work queue should be empty.
  489. //
  490. ASSERT(LIST_EMPTY(&(Device->WorkQueue)) != FALSE);
  491. //
  492. // Detached the drivers from the device.
  493. //
  494. IopDeviceDestroyDriverStack(Device);
  495. //
  496. // Assert all the children are gone, there are no active children, and this
  497. // device is not an active child to anyone.
  498. //
  499. ASSERT(LIST_EMPTY(&(Device->Header.ChildListHead)) != FALSE);
  500. ASSERT(LIST_EMPTY(&(Device->ActiveChildListHead)) != FALSE);
  501. ASSERT(Device->ActiveListEntry.Next == NULL);
  502. //
  503. // Clean up the power management state.
  504. //
  505. PmpDestroyDevice(Device);
  506. //
  507. // Delete the arbiter list and the various resource lists.
  508. //
  509. IopDestroyArbiterList(Device);
  510. if (Device->ResourceRequirements != NULL) {
  511. IoDestroyResourceConfigurationList(Device->ResourceRequirements);
  512. }
  513. if (Device->SelectedConfiguration != NULL) {
  514. IoDestroyResourceRequirementList(Device->SelectedConfiguration);
  515. }
  516. if (Device->BusLocalResources != NULL) {
  517. IoDestroyResourceAllocationList(Device->BusLocalResources);
  518. }
  519. if (Device->ProcessorLocalResources != NULL) {
  520. IoDestroyResourceAllocationList(Device->ProcessorLocalResources);
  521. }
  522. if (Device->BootResources != NULL) {
  523. IoDestroyResourceAllocationList(Device->BootResources);
  524. }
  525. if (Device->Lock != NULL) {
  526. KeDestroySharedExclusiveLock(Device->Lock);
  527. }
  528. //
  529. // Deallocate the class ID, and compatible IDs. The object manager will
  530. // free the device ID (i.e. the name).
  531. //
  532. ASSERT((Device->Header.Flags & OBJECT_FLAG_USE_NAME_DIRECTLY) == 0);
  533. if (Device->ClassId != NULL) {
  534. MmFreePagedPool(Device->ClassId);
  535. } else if (Device->CompatibleIds != NULL) {
  536. MmFreePagedPool(Device->CompatibleIds);
  537. }
  538. RtlDebugPrint("Destroyed Device: %s, 0x%x\n", Device->Header.Name, Device);
  539. return;
  540. }
  541. //
  542. // --------------------------------------------------------- Internal Functions
  543. //
  544. KSTATUS
  545. IopSendRemovalIrp (
  546. PDEVICE Device
  547. )
  548. /*++
  549. Routine Description:
  550. This routine sends a removal IRP to a device, allowing device drivers to
  551. clean up any resources for the given device.
  552. Arguments:
  553. Device - Supplies a pointer to the device that is to receive a removal IRP.
  554. Return Value:
  555. Status code.
  556. --*/
  557. {
  558. PIRP RemovalIrp;
  559. KSTATUS Status;
  560. RemovalIrp = NULL;
  561. Status = STATUS_SUCCESS;
  562. //
  563. // The system should only send removal IRPs to devices awaiting removal.
  564. //
  565. ASSERT(Device->State == DeviceAwaitingRemoval);
  566. //
  567. // The device should have no active children.
  568. //
  569. ASSERT(LIST_EMPTY(&(Device->ActiveChildListHead)) != FALSE);
  570. //
  571. // The device's work queue should be closing and the work queue should be
  572. // empty.
  573. //
  574. ASSERT(Device->QueueState == DeviceQueueActiveClosing);
  575. ASSERT(LIST_EMPTY(&(Device->WorkQueue)) != FALSE);
  576. //
  577. // Skip to the end if there are no drivers.
  578. //
  579. if (Device->DriverStackSize == 0) {
  580. ASSERT(LIST_EMPTY(&(Device->DriverStackHead)) != FALSE);
  581. goto SendRemovalIrpEnd;
  582. }
  583. //
  584. // Allocate a removal IRP.
  585. //
  586. RemovalIrp = IoCreateIrp(Device, IrpMajorStateChange, 0);
  587. if (RemovalIrp == NULL) {
  588. Status = STATUS_INSUFFICIENT_RESOURCES;
  589. goto SendRemovalIrpEnd;
  590. }
  591. RemovalIrp->MinorCode = IrpMinorRemoveDevice;
  592. //
  593. // Send the removal IRP to the device. Release the topology lock while
  594. // calling the driver.
  595. //
  596. Status = IoSendSynchronousIrp(RemovalIrp);
  597. if (!KSUCCESS(Status)) {
  598. ASSERT(KSUCCESS(Status));
  599. goto SendRemovalIrpEnd;
  600. }
  601. Status = IoGetIrpStatus(RemovalIrp);
  602. if (!KSUCCESS(Status)) {
  603. RtlDebugPrint("IO: Remove IRP failed for device 0x%08x with status "
  604. "0x%08x\n",
  605. Device,
  606. Status);
  607. goto SendRemovalIrpEnd;
  608. }
  609. SendRemovalIrpEnd:
  610. if (RemovalIrp != NULL) {
  611. IoDestroyIrp(RemovalIrp);
  612. }
  613. return Status;
  614. }
  615. VOID
  616. IopDeviceDestroyDriverStack (
  617. PDEVICE Device
  618. )
  619. /*++
  620. Routine Description:
  621. This routine destroys the driver stack for the given device.
  622. Arguments:
  623. Device - Supplies a pointer to the device whose driver stack is to be
  624. destroyed.
  625. Return Value:
  626. None.
  627. --*/
  628. {
  629. PLIST_ENTRY DriverListEntry;
  630. PDRIVER_STACK_ENTRY DriverStackEntry;
  631. PLIST_ENTRY RemovalEntry;
  632. ASSERT(Device != NULL);
  633. ASSERT((Device->State == DeviceRemoved) ||
  634. (Device->State == DeviceUnreported));
  635. //
  636. // Detached the drivers from the device.
  637. //
  638. DriverListEntry = Device->DriverStackHead.Next;
  639. while (DriverListEntry != &(Device->DriverStackHead)) {
  640. DriverStackEntry = (PDRIVER_STACK_ENTRY)LIST_VALUE(DriverListEntry,
  641. DRIVER_STACK_ENTRY,
  642. ListEntry);
  643. RemovalEntry = DriverListEntry;
  644. DriverListEntry = DriverListEntry->Next;
  645. LIST_REMOVE(RemovalEntry);
  646. IoDriverReleaseReference(DriverStackEntry->Driver);
  647. MmFreeNonPagedPool(DriverStackEntry);
  648. Device->DriverStackSize -= 1;
  649. }
  650. ASSERT(Device->DriverStackSize == 0);
  651. return;
  652. }