devrem.c 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. devrem.c
  9. Abstract:
  10. This module implements a test driver that handles device removal.
  11. Author:
  12. Chris Stevens 31-May-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. //
  24. // Device removal pool tag.
  25. //
  26. #define DEVR_ALLOCATION_TAG 0x52766544 // 'RveD'
  27. //
  28. // Device removal level and children constants.
  29. //
  30. #define DEVICE_REMOVAL_LEVEL_MAX 4
  31. #define DEVICE_REMOVAL_ROOT_LEVEL 0
  32. //
  33. // Device IDs and lengths.
  34. //
  35. #define DEVR_ROOT_ID "DEVREMROOT"
  36. #define DEVR_CHILD_ID "DEVREMCHLD"
  37. #define DEVR_DEVICE_ID_SIZE 11
  38. //
  39. // Class ID format and length.
  40. //
  41. #define DEVR_CLASS_ID_FORMAT "Level%04x"
  42. #define DEVR_CLASS_ID_FORMAT_SIZE 10
  43. #define DEVR_CLASS_ID_SIZE 10
  44. //
  45. // Removal test timer values.
  46. //
  47. #define DEVICE_REMOVAL_TEST_PERIOD (300 * MICROSECONDS_PER_MILLISECOND)
  48. #define DEVICE_REMOVAL_TEST_DUE_TIME (15000 * MICROSECONDS_PER_MILLISECOND)
  49. //
  50. // Defines the rate at which removal IRPs fail when removal IRP failure is
  51. // enabled.
  52. //
  53. #define REMOVAL_IRP_FAILURE_RATE 15
  54. //
  55. // Defines the rate at which the random test cleans up the test tracking tree.
  56. //
  57. #define RANDOM_TEST_CLEAN_TREE_RATE 5
  58. #define RANDOM_REMOVE_START_LEVEL (DEVICE_REMOVAL_ROOT_LEVEL + 1)
  59. #define RANDOM_REMOVE_END_LEVEL (DEVICE_REMOVAL_LEVEL_MAX - 1)
  60. #define RANDOM_ADD_START_LEVEL DEVICE_REMOVAL_ROOT_LEVEL
  61. #define RANDOM_ADD_END_LEVEL (DEVICE_REMOVAL_LEVEL_MAX - 2)
  62. #define RANDOM_TEST_MAX_COUNT 100
  63. //
  64. // Define the rate at which device queue failures should occur.
  65. //
  66. #define DEVICE_QUEUE_FAILURE_RATE 10
  67. //
  68. // ------------------------------------------------------ Data Type Definitions
  69. //
  70. typedef struct _REMOVAL_DEVICE REMOVAL_DEVICE, *PREMOVAL_DEVICE;
  71. typedef enum _REMOVAL_DEVICE_TEST {
  72. RemovalDeviceTestAddChild,
  73. RemovalDeviceTestUnreportedChild,
  74. RemovalDeviceTestAddSibling,
  75. RemovalDeviceTestRemoveChild,
  76. RemovalDeviceTestRemoveSibling,
  77. RemovalDeviceTestAddRemoveChild,
  78. RemovalDeviceTestAddRemoveSibling,
  79. RemovalDeviceTestCascadeRemove,
  80. RemovalDeviceTestRandom,
  81. RemovalDeviceTestCleanup,
  82. RemovalDeviceTestMax
  83. } REMOVAL_DEVICE_TEST, *PREMOVAL_DEVICE_TEST;
  84. /*++
  85. Structure Definition:
  86. This structure defines an entry in the removal device tree.
  87. Members:
  88. DeviceToken - Stores an opaque token representing the device.
  89. BusContext - Stores the bus device's driver context for this device.
  90. FunctionContext - Stores the function device's driver context for this
  91. device.
  92. Attached - Stores a bool indicating whether or not the device is attached.
  93. RemovalIrp - Stores a bool indicating whether or not the device has
  94. received a removal IRP.
  95. SilbingEntry - Stores a list entry pointing to the entries sibling devices.
  96. ChildListHead - Stores a list entry pointing to the entries children.
  97. --*/
  98. typedef struct _REMOVAL_DEVICE_ENTRY {
  99. PVOID DeviceToken;
  100. PREMOVAL_DEVICE BusContext;
  101. PREMOVAL_DEVICE FunctionContext;
  102. BOOL Attached;
  103. BOOL RemovalIrp;
  104. LIST_ENTRY SiblingEntry;
  105. LIST_ENTRY ChildListHead;
  106. } REMOVAL_DEVICE_ENTRY, *PREMOVAL_DEVICE_ENTRY;
  107. /*++
  108. Enum Definition:
  109. This enumerates device removal types.
  110. Values:
  111. DeviceRemovalInvalid - Represents an invalid device.
  112. DeviceRemovalBus - Represents a bus device, implying that this driver will
  113. act as a functional driver for the bus.
  114. DeviceRemovalFunction - Represents a functional device, implying that this
  115. driver will act as a bus driver for the function.
  116. --*/
  117. typedef enum _REMOVAL_DEVICE_TYPE {
  118. DeviceRemovalInvalid,
  119. DeviceRemovalBus,
  120. DeviceRemovalFunction
  121. } REMOVAL_DEVICE_TYPE, *PREMOVAL_DEVICE_TYPE;
  122. /*++
  123. Structure Definition:
  124. This structure defines a removal device.
  125. Members:
  126. Type - Stores the type of removal device.
  127. Root - Stores whether or not the device is the root removal device.
  128. Level - Stores the heirarchy level of the device.
  129. Children - Stores an array of the device's children.
  130. ChildCount - Stores the number of children that belong to the device.
  131. TreeEntry - Stores the devices entry in the global tree.
  132. --*/
  133. struct _REMOVAL_DEVICE {
  134. REMOVAL_DEVICE_TYPE Type;
  135. BOOL Root;
  136. ULONG Level;
  137. PDEVICE *Children;
  138. ULONG ChildCount;
  139. PREMOVAL_DEVICE_ENTRY TreeEntry;
  140. };
  141. //
  142. // ----------------------------------------------- Internal Function Prototypes
  143. //
  144. KSTATUS
  145. DeviceRemovalAddDevice (
  146. PVOID Driver,
  147. PCSTR DeviceId,
  148. PCSTR ClassId,
  149. PCSTR CompatibleIds,
  150. PVOID DeviceToken
  151. );
  152. VOID
  153. DeviceRemovalDispatchStateChange (
  154. PIRP Irp,
  155. PVOID DeviceContext,
  156. PVOID IrpContext
  157. );
  158. VOID
  159. DeviceRemovalDispatchSystemControl (
  160. PIRP Irp,
  161. PVOID DeviceContext,
  162. PVOID IrpContext
  163. );
  164. VOID
  165. DeviceRemovalReportChildren (
  166. PIRP Irp,
  167. PREMOVAL_DEVICE Device
  168. );
  169. VOID
  170. DeviceRemovalEnumerateChildren (
  171. PIRP Irp,
  172. PREMOVAL_DEVICE Device
  173. );
  174. VOID
  175. DeviceRemovalValidateChildren (
  176. PIRP Irp,
  177. PREMOVAL_DEVICE Device
  178. );
  179. KSTATUS
  180. DeviceRemovalRemoveDevice (
  181. PIRP Irp,
  182. PREMOVAL_DEVICE Device
  183. );
  184. VOID
  185. DeviceRemovalRunTests (
  186. VOID
  187. );
  188. VOID
  189. DeviceRemovalDestroyTests (
  190. PVOID Parameter
  191. );
  192. VOID
  193. DeviceRemovalServiceRemovalDpc (
  194. PDPC Dpc
  195. );
  196. VOID
  197. DeviceRemovalTests (
  198. PVOID Parameter
  199. );
  200. VOID
  201. DeviceRemovalTestAddChild (
  202. VOID
  203. );
  204. VOID
  205. DeviceRemovalTestUnreportedChild (
  206. VOID
  207. );
  208. VOID
  209. DeviceRemovalTestAddSibling (
  210. VOID
  211. );
  212. VOID
  213. DeviceRemovalTestRemoveChild (
  214. VOID
  215. );
  216. VOID
  217. DeviceRemovalTestRemoveSibling (
  218. VOID
  219. );
  220. VOID
  221. DeviceRemovalTestAddRemoveChild (
  222. VOID
  223. );
  224. VOID
  225. DeviceRemovalTestAddRemoveSibling (
  226. VOID
  227. );
  228. VOID
  229. DeviceRemovalTestCascadeRemove (
  230. VOID
  231. );
  232. VOID
  233. DeviceRemovalCascadeRemoveHelper (
  234. PREMOVAL_DEVICE_ENTRY RootEntry,
  235. PVOID ParentDeviceToken
  236. );
  237. VOID
  238. DeviceRemovalTestRandom (
  239. VOID
  240. );
  241. PREMOVAL_DEVICE_ENTRY
  242. DeviceRemovalFindDeviceAndDetach (
  243. PREMOVAL_DEVICE_ENTRY Entry,
  244. PREMOVAL_DEVICE_ENTRY *ParentEntry,
  245. ULONG Level
  246. );
  247. PREMOVAL_DEVICE_ENTRY
  248. DeviceRemovalFindDeviceAndAddChild (
  249. PREMOVAL_DEVICE_ENTRY Entry,
  250. PREMOVAL_DEVICE_ENTRY *ParentEntry,
  251. ULONG Level
  252. );
  253. VOID
  254. DeviceRemovalDestroyTree (
  255. PREMOVAL_DEVICE_ENTRY RootEntry
  256. );
  257. VOID
  258. DeviceRemovalCleanTree (
  259. PREMOVAL_DEVICE_ENTRY Entry,
  260. PREMOVAL_DEVICE_ENTRY ParentEntry
  261. );
  262. VOID
  263. DeviceRemovalNukeTree (
  264. VOID
  265. );
  266. PREMOVAL_DEVICE_ENTRY
  267. DeviceRemovalInitializeTreeForTest (
  268. VOID
  269. );
  270. VOID
  271. DeviceRemovalWaitForTreeCreation (
  272. PREMOVAL_DEVICE_ENTRY RootEntry
  273. );
  274. VOID
  275. DeviceRemovalDetachDevice (
  276. PREMOVAL_DEVICE_ENTRY DeviceEntry
  277. );
  278. PREMOVAL_DEVICE_ENTRY
  279. DeviceRemovalAttachChildDevice (
  280. PREMOVAL_DEVICE Device
  281. );
  282. PREMOVAL_DEVICE_ENTRY
  283. DeviceRemovalAttachChildDeviceHelper (
  284. PREMOVAL_DEVICE Device
  285. );
  286. PREMOVAL_DEVICE_ENTRY
  287. DeviceRemovalCreateTreeEntry (
  288. PREMOVAL_DEVICE DeviceContext,
  289. PREMOVAL_DEVICE_ENTRY ParentEntry
  290. );
  291. VOID
  292. DeviceRemovalDeleteTreeEntry (
  293. PREMOVAL_DEVICE_ENTRY Entry
  294. );
  295. PREMOVAL_DEVICE_ENTRY
  296. DeviceRemovalFindChildByToken (
  297. PREMOVAL_DEVICE_ENTRY Root,
  298. PVOID DeviceToken
  299. );
  300. PREMOVAL_DEVICE_ENTRY
  301. DeviceRemovalFindEntryByToken (
  302. PVOID DeviceToken
  303. );
  304. //
  305. // -------------------------------------------------------------------- Globals
  306. //
  307. //
  308. // Stores a boolean to toggle running the device removal tests during system
  309. // startup.
  310. //
  311. BOOL DeviceRemovalTestsEnabled = FALSE;
  312. //
  313. // Array of how many children each level should automaticlly create.
  314. //
  315. ULONG LevelChildCount[DEVICE_REMOVAL_LEVEL_MAX] = {0, 2, 4, 0};
  316. //
  317. // Reference to this device driver.
  318. //
  319. PDRIVER DeviceRemovalDriver = NULL;
  320. //
  321. // Tree of device removal devices.
  322. //
  323. PREMOVAL_DEVICE_ENTRY RemovalDeviceTree = NULL;
  324. KSPIN_LOCK DeviceTreeLock;
  325. volatile ULONG DeviceEntryCount = 0;
  326. //
  327. // Device removal initialization, timer and work queue variables.
  328. //
  329. ULONG RemovalTestsInitialized = FALSE;
  330. PKTIMER RemovalTestTimer = NULL;
  331. PWORK_QUEUE RemovalTestWorkQueue = NULL;
  332. PWORK_ITEM RemovalTestWorkItem = NULL;
  333. PDPC RemovalTestDpc = NULL;
  334. KSPIN_LOCK RemovalTestLock;
  335. REMOVAL_DEVICE_TEST RemovalTest;
  336. //
  337. // Random device removal test variables.
  338. //
  339. ULONG RandomTestCount = 0;
  340. BOOL RandomRemoveDevice = TRUE;
  341. ULONG RandomRemoveLevel = RANDOM_REMOVE_START_LEVEL;
  342. ULONG RandomAddLevel = RANDOM_ADD_START_LEVEL;
  343. //
  344. // IRP failure variables.
  345. //
  346. BOOL RemovalIrpFailEnabled = FALSE;
  347. volatile ULONG RemovalIrpFailureCount = 0;
  348. //
  349. // Device queue failure variables.
  350. //
  351. BOOL DeviceQueueFailEnabled = FALSE;
  352. volatile ULONG DeviceQueueFailureCount = 0;
  353. //
  354. // The root device context.
  355. //
  356. PREMOVAL_DEVICE RootDevice;
  357. PDEVICE RootDeviceToken;
  358. //
  359. // Allocation counters.
  360. //
  361. volatile ULONG BusDeviceCount = 0;
  362. volatile ULONG FunctionDeviceCount = 0;
  363. //
  364. // ------------------------------------------------------------------ Functions
  365. //
  366. __USED
  367. KSTATUS
  368. DriverEntry (
  369. PDRIVER Driver
  370. )
  371. /*++
  372. Routine Description:
  373. This routine is the entry point for the device removal driver. It registers
  374. its other dispatch functions, and performs driver-wide initialization.
  375. Arguments:
  376. Driver - Supplies a pointer to the driver object.
  377. Return Value:
  378. STATUS_SUCCESS on success.
  379. Failure code on error.
  380. --*/
  381. {
  382. DRIVER_FUNCTION_TABLE FunctionTable;
  383. KSTATUS Status;
  384. DeviceRemovalDriver = Driver;
  385. KeInitializeSpinLock(&DeviceTreeLock);
  386. KeInitializeSpinLock(&RemovalTestLock);
  387. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  388. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  389. FunctionTable.AddDevice = DeviceRemovalAddDevice;
  390. FunctionTable.DispatchStateChange = DeviceRemovalDispatchStateChange;
  391. FunctionTable.DispatchSystemControl = DeviceRemovalDispatchSystemControl;
  392. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  393. if (!KSUCCESS(Status)) {
  394. goto DriverEntryEnd;
  395. }
  396. //
  397. // Create the root device.
  398. //
  399. if (DeviceRemovalTestsEnabled != FALSE) {
  400. Status = IoCreateDevice(NULL,
  401. NULL,
  402. NULL,
  403. "DEVREMROOT",
  404. NULL,
  405. NULL,
  406. &RootDeviceToken);
  407. }
  408. DriverEntryEnd:
  409. return Status;
  410. }
  411. KSTATUS
  412. DeviceRemovalAddDevice (
  413. PVOID Driver,
  414. PCSTR DeviceId,
  415. PCSTR ClassId,
  416. PCSTR CompatibleIds,
  417. PVOID DeviceToken
  418. )
  419. /*++
  420. Routine Description:
  421. This routine is called when a device is detected for which the device
  422. removal driver acts as the function driver. The driver will attach itself
  423. to the stack.
  424. Arguments:
  425. Driver - Supplies a pointer to the driver being called.
  426. DeviceId - Supplies a pointer to a string with the device ID.
  427. ClassId - Supplies a pointer to a string containing the device's class ID.
  428. CompatibleIds - Supplies a pointer to a string containing device IDs
  429. that would be compatible with this device.
  430. DeviceToken - Supplies an opaque token that the driver can use to identify
  431. the device in the system. This token should be used when attaching to
  432. the stack.
  433. Return Value:
  434. STATUS_SUCCESS on success.
  435. Failure code if the driver was unsuccessful in attaching itself.
  436. --*/
  437. {
  438. PREMOVAL_DEVICE DeviceContext;
  439. ULONG ItemsScanned;
  440. ULONG Level;
  441. BOOL Root;
  442. KSTATUS Status;
  443. PREMOVAL_DEVICE_ENTRY TreeEntry;
  444. TreeEntry = NULL;
  445. DeviceContext = NULL;
  446. //
  447. // Determine if this is the device removal root or some child.
  448. //
  449. Root = IoAreDeviceIdsEqual(DeviceId, DEVR_ROOT_ID);
  450. if (Root != FALSE) {
  451. Level = DEVICE_REMOVAL_ROOT_LEVEL;
  452. } else {
  453. ASSERT(IoAreDeviceIdsEqual(DeviceId, DEVR_CHILD_ID) != FALSE);
  454. //
  455. // Look at the class ID to determine the level.
  456. //
  457. Status = RtlStringScan(ClassId,
  458. DEVR_CLASS_ID_SIZE,
  459. DEVR_CLASS_ID_FORMAT,
  460. DEVR_CLASS_ID_FORMAT_SIZE,
  461. CharacterEncodingDefault,
  462. &ItemsScanned,
  463. &Level);
  464. if (!KSUCCESS(Status)) {
  465. goto AddDeviceEnd;
  466. }
  467. if (ItemsScanned != 1) {
  468. Status = STATUS_UNSUCCESSFUL;
  469. goto AddDeviceEnd;
  470. }
  471. }
  472. //
  473. // Initialize the functional device context that treats this device as a
  474. // bus.
  475. //
  476. DeviceContext = MmAllocateNonPagedPool(sizeof(REMOVAL_DEVICE),
  477. DEVR_ALLOCATION_TAG);
  478. if (DeviceContext == NULL) {
  479. Status = STATUS_INSUFFICIENT_RESOURCES;
  480. goto AddDeviceEnd;
  481. }
  482. RtlAtomicAdd32(&BusDeviceCount, 1);
  483. RtlZeroMemory(DeviceContext, sizeof(REMOVAL_DEVICE));
  484. DeviceContext->Type = DeviceRemovalBus;
  485. DeviceContext->Root = Root;
  486. DeviceContext->Level = Level;
  487. ASSERT(Level < DEVICE_REMOVAL_LEVEL_MAX);
  488. DeviceContext->ChildCount = LevelChildCount[Level];
  489. //
  490. // The root device needs to create a tree entry for itself.
  491. //
  492. if (Root != FALSE) {
  493. KeAcquireSpinLock(&DeviceTreeLock);
  494. TreeEntry = DeviceRemovalCreateTreeEntry(DeviceContext,
  495. NULL);
  496. KeReleaseSpinLock(&DeviceTreeLock);
  497. if (TreeEntry == NULL) {
  498. Status = STATUS_INSUFFICIENT_RESOURCES;
  499. goto AddDeviceEnd;
  500. }
  501. TreeEntry->DeviceToken = DeviceToken;
  502. RemovalDeviceTree = TreeEntry;
  503. //
  504. // For other devices, the tree entry was created by the parent, find it and
  505. // attach it to this devie context.
  506. //
  507. } else {
  508. TreeEntry = DeviceRemovalFindEntryByToken(DeviceToken);
  509. ASSERT(TreeEntry != NULL);
  510. DeviceContext->TreeEntry = TreeEntry;
  511. TreeEntry->BusContext = DeviceContext;
  512. }
  513. //
  514. // Attach the bus driver context to the device.
  515. //
  516. Status = IoAttachDriverToDevice(Driver, DeviceToken, DeviceContext);
  517. if (!KSUCCESS(Status)) {
  518. goto AddDeviceEnd;
  519. }
  520. //
  521. // When adding the root device, begin the test sequence.
  522. //
  523. if (Root != FALSE) {
  524. RootDevice = DeviceContext;
  525. DeviceRemovalRunTests();
  526. }
  527. AddDeviceEnd:
  528. if (!KSUCCESS(Status)) {
  529. if (TreeEntry != NULL) {
  530. DeviceRemovalDeleteTreeEntry(TreeEntry);
  531. }
  532. if (DeviceContext != NULL) {
  533. MmFreeNonPagedPool(DeviceContext);
  534. RtlAtomicAdd32(&BusDeviceCount, (ULONG)-1);
  535. }
  536. }
  537. return Status;
  538. }
  539. VOID
  540. DeviceRemovalDispatchStateChange (
  541. PIRP Irp,
  542. PVOID DeviceContext,
  543. PVOID IrpContext
  544. )
  545. /*++
  546. Routine Description:
  547. This routine handles State Change IRPs.
  548. Arguments:
  549. Irp - Supplies a pointer to the I/O request packet.
  550. DeviceContext - Supplies the context pointer supplied by the driver when it
  551. attached itself to the driver stack. Presumably this pointer contains
  552. driver-specific device context.
  553. IrpContext - Supplies the context pointer supplied by the driver when
  554. the IRP was created.
  555. Return Value:
  556. None.
  557. --*/
  558. {
  559. PREMOVAL_DEVICE Device;
  560. KSTATUS Status;
  561. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  562. Device = (PREMOVAL_DEVICE)DeviceContext;
  563. //
  564. // Process the IRP based on the minor code and direction.
  565. //
  566. if (Irp->Direction == IrpDown) {
  567. switch (Irp->MinorCode) {
  568. case IrpMinorQueryResources:
  569. //
  570. // Act on this IRP if the driver is acting as the bus driver or
  571. // if it is the only driver for the device, which is the case for
  572. // the root.
  573. //
  574. if ((Device->Type == DeviceRemovalFunction) ||
  575. (Device->Root != FALSE)) {
  576. IoCompleteIrp(DeviceRemovalDriver, Irp, STATUS_SUCCESS);
  577. }
  578. break;
  579. case IrpMinorStartDevice:
  580. //
  581. // Act on this IRP fi the driver is acting as the bus driver or
  582. // if it is the only driver for the device, which is the case for
  583. // the root.
  584. //
  585. if ((Device->Type == DeviceRemovalFunction) ||
  586. (Device->Root != FALSE)) {
  587. IoCompleteIrp(DeviceRemovalDriver, Irp, STATUS_SUCCESS);
  588. }
  589. break;
  590. case IrpMinorQueryChildren:
  591. //
  592. // The device is a function and this is operating as a bus driver,
  593. // so just complete the IRP.
  594. //
  595. if (Device->Type == DeviceRemovalFunction) {
  596. IoCompleteIrp(DeviceRemovalDriver, Irp, STATUS_SUCCESS);
  597. //
  598. // The device is a bus and this driver is acting as the
  599. // functional driver, so report the children.
  600. //
  601. } else {
  602. ASSERT(Device->Type == DeviceRemovalBus);
  603. DeviceRemovalReportChildren(Irp, Device);
  604. //
  605. // The root device has no bus driver, so it has to complete
  606. // the IRP itself.
  607. //
  608. if (Device->Root != FALSE) {
  609. IoCompleteIrp(DeviceRemovalDriver, Irp, STATUS_SUCCESS);
  610. }
  611. }
  612. break;
  613. case IrpMinorRemoveDevice:
  614. if ((Device->Type == DeviceRemovalFunction) ||
  615. (Device->Root != FALSE)) {
  616. Status = DeviceRemovalRemoveDevice(Irp, Device);
  617. IoCompleteIrp(DeviceRemovalDriver, Irp, Status);
  618. }
  619. default:
  620. break;
  621. }
  622. } else {
  623. ASSERT(Irp->Direction == IrpUp);
  624. switch (Irp->MinorCode) {
  625. case IrpMinorRemoveDevice:
  626. DeviceRemovalRemoveDevice(Irp, Device);
  627. break;
  628. default:
  629. break;
  630. }
  631. }
  632. return;
  633. }
  634. VOID
  635. DeviceRemovalDispatchSystemControl (
  636. PIRP Irp,
  637. PVOID DeviceContext,
  638. PVOID IrpContext
  639. )
  640. /*++
  641. Routine Description:
  642. This routine handles System Control IRPs.
  643. Arguments:
  644. Irp - Supplies a pointer to the I/O request packet.
  645. DeviceContext - Supplies the context pointer supplied by the driver when it
  646. attached itself to the driver stack. Presumably this pointer contains
  647. driver-specific device context.
  648. IrpContext - Supplies the context pointer supplied by the driver when
  649. the IRP was created.
  650. Return Value:
  651. None.
  652. --*/
  653. {
  654. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  655. //
  656. // Complete the IRP.
  657. //
  658. if (Irp->Direction == IrpDown) {
  659. IoCompleteIrp(DeviceRemovalDriver, Irp, STATUS_NOT_HANDLED);
  660. } else {
  661. ASSERT(Irp->Direction == IrpUp);
  662. }
  663. return;
  664. }
  665. VOID
  666. DeviceRemovalReportChildren (
  667. PIRP Irp,
  668. PREMOVAL_DEVICE Device
  669. )
  670. /*++
  671. Routine Description:
  672. This routine reports the number of children of the device. If the children
  673. have not yet been enumerated, it will enumerate them. If they have
  674. previously been enumerated, then it will validate them to make sure they
  675. all still exist.
  676. Arguments:
  677. Irp - Supplies a pointer to the IRP requestion the children.
  678. Device - Supplies a pointer to the current device context.
  679. Return Value:
  680. None.
  681. --*/
  682. {
  683. PDEVICE *Children;
  684. ASSERT(KeGetRunLevel() == RunLevelLow);
  685. Irp->U.QueryChildren.Children = NULL;
  686. Irp->U.QueryChildren.ChildCount = 0;
  687. //
  688. // If the device has never reported children, enumerate them. Otherwise
  689. // validate that they all still exist.
  690. //
  691. if (Device->Children == NULL) {
  692. DeviceRemovalEnumerateChildren(Irp, Device);
  693. } else {
  694. DeviceRemovalValidateChildren(Irp, Device);
  695. }
  696. //
  697. // If the bus driver has no children, exit immediately.
  698. //
  699. if (Device->ChildCount == 0) {
  700. return;
  701. }
  702. //
  703. // Report the current children in the IRP.
  704. //
  705. ASSERT(Device->ChildCount != 0);
  706. Children = MmAllocatePagedPool(sizeof(PDEVICE) * Device->ChildCount,
  707. DEVR_ALLOCATION_TAG);
  708. if (Children == NULL) {
  709. goto ReportChildrenEnd;
  710. }
  711. RtlCopyMemory(Children,
  712. Device->Children,
  713. Device->ChildCount * sizeof(PDEVICE));
  714. Irp->U.QueryChildren.Children = Children;
  715. Irp->U.QueryChildren.ChildCount = Device->ChildCount;
  716. ReportChildrenEnd:
  717. return;
  718. }
  719. VOID
  720. DeviceRemovalEnumerateChildren (
  721. PIRP Irp,
  722. PREMOVAL_DEVICE Device
  723. )
  724. /*++
  725. Routine Description:
  726. This routine enumerates the children of the supplied device.
  727. Arguments:
  728. Irp - Supplies a pointer to the IRP requesting the enumeration.
  729. Device - Supplies a pointer to the device removal context.
  730. Return Value:
  731. None.
  732. --*/
  733. {
  734. PREMOVAL_DEVICE_ENTRY ChildEntry;
  735. ULONG ChildIndex;
  736. CHAR ClassId[DEVR_CLASS_ID_SIZE];
  737. PREMOVAL_DEVICE NewContext;
  738. KSTATUS Status;
  739. ASSERT(KeGetRunLevel() == RunLevelLow);
  740. Status = STATUS_SUCCESS;
  741. //
  742. // Synchronize with device creation.
  743. //
  744. KeAcquireSpinLock(&DeviceTreeLock);
  745. ASSERT(Device->TreeEntry->RemovalIrp == FALSE);
  746. //
  747. // Only bus driver should report children.
  748. //
  749. ASSERT(Device->Type == DeviceRemovalBus);
  750. if (Device->ChildCount == 0) {
  751. goto EnumerateChildrenEnd;
  752. }
  753. //
  754. // Allocate an array for child device pointers.
  755. //
  756. Device->Children = MmAllocatePagedPool(sizeof(PDEVICE) * Device->ChildCount,
  757. DEVR_ALLOCATION_TAG);
  758. if (Device->Children == NULL) {
  759. Status = STATUS_INSUFFICIENT_RESOURCES;
  760. goto EnumerateChildrenEnd;
  761. }
  762. RtlZeroMemory(Device->Children, sizeof(PDEVICE) * Device->ChildCount);
  763. //
  764. // Create the class ID for the children.
  765. //
  766. RtlPrintToString(ClassId,
  767. DEVR_CLASS_ID_SIZE,
  768. CharacterEncodingDefault,
  769. DEVR_CLASS_ID_FORMAT,
  770. (Device->Level + 1));
  771. //
  772. // Create devices for the current device's children and track them in the
  773. // the global device removal tree.
  774. //
  775. for (ChildIndex = 0; ChildIndex < Device->ChildCount; ChildIndex += 1) {
  776. NewContext = MmAllocateNonPagedPool(sizeof(REMOVAL_DEVICE),
  777. DEVR_ALLOCATION_TAG);
  778. if (NewContext == NULL) {
  779. Status = STATUS_INSUFFICIENT_RESOURCES;
  780. goto EnumerateChildrenEnd;
  781. }
  782. RtlAtomicAdd32(&FunctionDeviceCount, 1);
  783. RtlZeroMemory(NewContext, sizeof(REMOVAL_DEVICE));
  784. NewContext->Type = DeviceRemovalFunction;
  785. NewContext->Root = FALSE;
  786. //
  787. // Create a tree entry for the child device.
  788. //
  789. ChildEntry = DeviceRemovalCreateTreeEntry(NewContext,
  790. Device->TreeEntry);
  791. if (ChildEntry == NULL) {
  792. MmFreeNonPagedPool(NewContext);
  793. RtlAtomicAdd32(&FunctionDeviceCount, (ULONG)-1);
  794. break;
  795. }
  796. //
  797. // Create the child device and fill out the accounting structures.
  798. //
  799. Status = IoCreateDevice(DeviceRemovalDriver,
  800. NewContext,
  801. Irp->Device,
  802. DEVR_CHILD_ID,
  803. ClassId,
  804. NULL,
  805. &(Device->Children[ChildIndex]));
  806. if (!KSUCCESS(Status)) {
  807. RtlDebugPrint("IoCreateDevice failed with status %d.\n", Status);
  808. DeviceRemovalDeleteTreeEntry(ChildEntry);
  809. MmFreeNonPagedPool(NewContext);
  810. RtlAtomicAdd32(&FunctionDeviceCount, (ULONG)-1);
  811. break;
  812. }
  813. ChildEntry->DeviceToken = Device->Children[ChildIndex];
  814. }
  815. //
  816. // If child creation ever failed, the current index is the count of how
  817. // many children were successfully created.
  818. //
  819. Device->ChildCount = ChildIndex;
  820. EnumerateChildrenEnd:
  821. KeReleaseSpinLock(&DeviceTreeLock);
  822. return;
  823. }
  824. VOID
  825. DeviceRemovalValidateChildren (
  826. PIRP Irp,
  827. PREMOVAL_DEVICE Device
  828. )
  829. /*++
  830. Routine Description:
  831. This routine validates that all of the devices children still exist. Where
  832. a physical device would query hardware, this driver searches through the
  833. global tree for missing children. If any of the children have been removed,
  834. it updates the device's child list.
  835. Arguments:
  836. Irp - Supplies a pointer to the IRP that requires child validation.
  837. Device - Supplies a pointer to the current device context.
  838. Return Value:
  839. None.
  840. --*/
  841. {
  842. ULONG ChildCount;
  843. PREMOVAL_DEVICE_ENTRY ChildEntry;
  844. ULONG ChildIndex;
  845. PDEVICE *CurrentChildren;
  846. ULONG CurrentIndex;
  847. PDEVICE *OriginalChildren;
  848. ASSERT(KeGetRunLevel() == RunLevelLow);
  849. //
  850. // Search through the children to determine how many devices are still
  851. // attached.
  852. //
  853. KeAcquireSpinLock(&DeviceTreeLock);
  854. ASSERT(Device->TreeEntry->RemovalIrp == FALSE);
  855. ASSERT(((Device->ChildCount == 0) && (Device->Children == NULL)) ||
  856. ((Device->ChildCount != 0) && (Device->Children != NULL)));
  857. ChildCount = 0;
  858. OriginalChildren = Device->Children;
  859. for (ChildIndex = 0; ChildIndex < Device->ChildCount; ChildIndex += 1) {
  860. ChildEntry = DeviceRemovalFindChildByToken(
  861. Device->TreeEntry,
  862. OriginalChildren[ChildIndex]);
  863. //
  864. // If the child has an entry and is attached, count is as validated.
  865. // Otherwise, remove it from the original array.
  866. //
  867. if ((ChildEntry != NULL) && (ChildEntry->Attached != FALSE)) {
  868. ChildCount += 1;
  869. }
  870. }
  871. //
  872. // If the count did not change, exit.
  873. //
  874. if (Device->ChildCount == ChildCount) {
  875. goto ValidateChildrenEnd;
  876. }
  877. //
  878. // If there are no children anymore, free the old list and do not create a
  879. // new list.
  880. //
  881. if (ChildCount == 0) {
  882. MmFreePagedPool(Device->Children);
  883. Device->Children = NULL;
  884. Device->ChildCount = 0;
  885. goto ValidateChildrenEnd;
  886. }
  887. //
  888. // Allocate an array for the new children.
  889. //
  890. CurrentChildren = MmAllocatePagedPool(sizeof(PDEVICE) * ChildCount,
  891. DEVR_ALLOCATION_TAG);
  892. if (CurrentChildren == NULL) {
  893. goto ValidateChildrenEnd;
  894. }
  895. CurrentIndex = 0;
  896. for (ChildIndex = 0; ChildIndex < Device->ChildCount; ChildIndex += 1) {
  897. ChildEntry = DeviceRemovalFindChildByToken(
  898. Device->TreeEntry,
  899. OriginalChildren[ChildIndex]);
  900. if ((ChildEntry != NULL) && (ChildEntry->Attached != FALSE)) {
  901. CurrentChildren[CurrentIndex] = OriginalChildren[ChildIndex];
  902. CurrentIndex += 1;
  903. }
  904. }
  905. ASSERT(CurrentIndex == ChildCount);
  906. Device->Children = CurrentChildren;
  907. Device->ChildCount = ChildCount;
  908. MmFreePagedPool(OriginalChildren);
  909. ValidateChildrenEnd:
  910. KeReleaseSpinLock(&DeviceTreeLock);
  911. return;
  912. }
  913. KSTATUS
  914. DeviceRemovalRemoveDevice (
  915. PIRP Irp,
  916. PREMOVAL_DEVICE Device
  917. )
  918. /*++
  919. Routine Description:
  920. This routine prepares the device for removal from the system.
  921. Arguments:
  922. Irp - Supplies a pointer to the IRP that is requesting the device removal.
  923. Device - Supplies a pointer to the device context for this driver.
  924. Return Value:
  925. Status code.
  926. --*/
  927. {
  928. PREMOVAL_DEVICE_ENTRY ChildEntry;
  929. PLIST_ENTRY CurrentEntry;
  930. ULONG OldFailureCount;
  931. PREMOVAL_DEVICE_ENTRY TreeEntry;
  932. ASSERT(KeGetRunLevel() == RunLevelLow);
  933. //
  934. // Handle two cases where the driver is acting as the functional driver.
  935. //
  936. if (Device->Type == DeviceRemovalBus) {
  937. //
  938. // If the bus driver failed the IRP on the way down, exit immediately
  939. // on the way back up.
  940. //
  941. if ((RemovalIrpFailEnabled != FALSE) &&
  942. (Irp->Status != STATUS_NOT_HANDLED) &&
  943. (!KSUCCESS(Irp->Status))) {
  944. return Irp->Status;
  945. }
  946. //
  947. // Otherwise free the device context and return successfully.
  948. //
  949. if (Device->Children != NULL) {
  950. MmFreePagedPool(Device->Children);
  951. }
  952. MmFreeNonPagedPool(Device);
  953. RtlAtomicAdd32(&BusDeviceCount, (ULONG)-1);
  954. return STATUS_SUCCESS;
  955. }
  956. //
  957. // Fail some removal IRPs once IRP failure is enabled.
  958. //
  959. if (RemovalIrpFailEnabled != FALSE) {
  960. OldFailureCount = RtlAtomicAdd32(&RemovalIrpFailureCount, 1);
  961. if ((OldFailureCount % REMOVAL_IRP_FAILURE_RATE) == 0) {
  962. return STATUS_UNSUCCESSFUL;
  963. }
  964. }
  965. //
  966. // Fail the next device queue action if enabled.
  967. //
  968. if (DeviceQueueFailEnabled != FALSE) {
  969. OldFailureCount = RtlAtomicAdd32(&DeviceQueueFailureCount, 1);
  970. if ((OldFailureCount % DEVICE_QUEUE_FAILURE_RATE) == 0) {
  971. IoSetTestHook(IO_FAIL_QUEUE_DEVICE_WORK);
  972. }
  973. }
  974. //
  975. // Mark the device as detached.
  976. //
  977. KeAcquireSpinLock(&DeviceTreeLock);
  978. TreeEntry = Device->TreeEntry;
  979. ASSERT(TreeEntry != NULL);
  980. TreeEntry->Attached = FALSE;
  981. //
  982. // Assert that the device's children have already been marked as detached
  983. // and that they have seen a removal IRP.
  984. //
  985. CurrentEntry = TreeEntry->ChildListHead.Next;
  986. while (CurrentEntry != &(TreeEntry->ChildListHead)) {
  987. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  988. REMOVAL_DEVICE_ENTRY,
  989. SiblingEntry);
  990. CurrentEntry = CurrentEntry->Next;
  991. ASSERT(ChildEntry->Attached == FALSE);
  992. ASSERT(ChildEntry->RemovalIrp != FALSE);
  993. }
  994. TreeEntry->RemovalIrp = TRUE;
  995. KeReleaseSpinLock(&DeviceTreeLock);
  996. if (Device->Children != NULL) {
  997. MmFreePagedPool(Device->Children);
  998. }
  999. MmFreeNonPagedPool(Device);
  1000. RtlAtomicAdd32(&FunctionDeviceCount, (ULONG)-1);
  1001. return STATUS_SUCCESS;
  1002. }
  1003. //
  1004. // -------------------------------------------------------- Test Infrastructure
  1005. //
  1006. VOID
  1007. DeviceRemovalRunTests (
  1008. VOID
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This routine initializes the device removal test sequence.
  1013. Arguments:
  1014. None.
  1015. Return Value:
  1016. None.
  1017. --*/
  1018. {
  1019. ULONGLONG DueTime;
  1020. BOOL Initialized;
  1021. ULONGLONG Period;
  1022. KSTATUS Status;
  1023. //
  1024. // Test and set the initialization boolean. If the test sequence has
  1025. // already begun, exit. This could be done with the timer pointer, but
  1026. // there is no compare-exchange pointer routine yet.
  1027. //
  1028. Initialized = RtlAtomicCompareExchange32(&RemovalTestsInitialized,
  1029. TRUE,
  1030. FALSE);
  1031. if (Initialized != FALSE) {
  1032. return;
  1033. }
  1034. ASSERT(RemovalTestTimer == NULL);
  1035. ASSERT(RemovalTestWorkQueue == NULL);
  1036. ASSERT(RemovalTestWorkItem == NULL);
  1037. //
  1038. // Create and queue a timer that will kick off the test sequence.
  1039. //
  1040. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  1041. RemovalTestTimer = KeCreateTimer(DEVR_ALLOCATION_TAG);
  1042. if (RemovalTestTimer == NULL) {
  1043. Status = STATUS_INSUFFICIENT_RESOURCES;
  1044. goto RunTestsEnd;
  1045. }
  1046. //
  1047. // Create a work queue that will be filled with a work item when the DPC
  1048. // fires.
  1049. //
  1050. RemovalTestWorkQueue = KeCreateWorkQueue(
  1051. WORK_QUEUE_FLAG_SUPPORT_DISPATCH_LEVEL,
  1052. "DeviceRemovalTestQueue");
  1053. if (RemovalTestWorkQueue == NULL) {
  1054. Status = STATUS_INSUFFICIENT_RESOURCES;
  1055. goto RunTestsEnd;
  1056. }
  1057. //
  1058. // Create a work item to be added to the work queue by the DPC.
  1059. //
  1060. RemovalTestWorkItem = KeCreateWorkItem(RemovalTestWorkQueue,
  1061. WorkPriorityNormal,
  1062. DeviceRemovalTests,
  1063. NULL,
  1064. DEVR_ALLOCATION_TAG);
  1065. if (RemovalTestWorkItem == NULL) {
  1066. Status = STATUS_INSUFFICIENT_RESOURCES;
  1067. goto RunTestsEnd;
  1068. }
  1069. //
  1070. // Create a DPC to queue once the timer expires.
  1071. //
  1072. RemovalTestDpc = KeCreateDpc(DeviceRemovalServiceRemovalDpc, NULL);
  1073. if (RemovalTestDpc == NULL) {
  1074. Status = STATUS_INSUFFICIENT_RESOURCES;
  1075. goto RunTestsEnd;
  1076. }
  1077. //
  1078. // Now that the test sequence is almost good to go, set the first test.
  1079. // This just needs to happen before the timer first expires.
  1080. //
  1081. RemovalTest = RemovalDeviceTestAddChild;
  1082. //
  1083. // Set the timer to go off at the test intervals.
  1084. //
  1085. DueTime = HlQueryTimeCounter();
  1086. DueTime += KeConvertMicrosecondsToTimeTicks(DEVICE_REMOVAL_TEST_DUE_TIME);
  1087. Period = KeConvertMicrosecondsToTimeTicks(DEVICE_REMOVAL_TEST_PERIOD);
  1088. Status = KeQueueTimer(RemovalTestTimer,
  1089. TimerQueueSoftWake,
  1090. DueTime,
  1091. Period,
  1092. 0,
  1093. RemovalTestDpc);
  1094. if (!KSUCCESS(Status)) {
  1095. goto RunTestsEnd;
  1096. }
  1097. RunTestsEnd:
  1098. if (!KSUCCESS(Status)) {
  1099. if (RemovalTestDpc != NULL) {
  1100. KeDestroyDpc(RemovalTestDpc);
  1101. }
  1102. if (RemovalTestTimer != NULL) {
  1103. KeDestroyTimer(RemovalTestTimer);
  1104. }
  1105. if (RemovalTestWorkQueue != NULL) {
  1106. KeDestroyWorkQueue(RemovalTestWorkQueue);
  1107. }
  1108. if (RemovalTestWorkItem != NULL) {
  1109. KeDestroyWorkItem(RemovalTestWorkItem);
  1110. }
  1111. }
  1112. return;
  1113. }
  1114. VOID
  1115. DeviceRemovalDestroyTests (
  1116. PVOID Parameter
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. This routine destroys the resources allocated to run the device removal
  1121. tests.
  1122. Arguments:
  1123. Parameter - Supplies an optional parameter for the work item routine.
  1124. Return Value:
  1125. None.
  1126. --*/
  1127. {
  1128. KeDestroyTimer(RemovalTestTimer);
  1129. KeDestroyDpc(RemovalTestDpc);
  1130. KeDestroyWorkQueue(RemovalTestWorkQueue);
  1131. KeDestroyWorkItem(RemovalTestWorkItem);
  1132. return;
  1133. }
  1134. VOID
  1135. DeviceRemovalServiceRemovalDpc (
  1136. PDPC Dpc
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This routine services the removal DPC that is queued by the test timer.
  1141. Arguments:
  1142. Dpc - Supplies a pointer to the DPC that is running.
  1143. Return Value:
  1144. None.
  1145. --*/
  1146. {
  1147. //
  1148. // Only queue more work if there isn't an entry already on the queue. This
  1149. // needs a lock in case two DPCs are on top of each other and they both see
  1150. // that the work item is not currently queued.
  1151. //
  1152. KeAcquireSpinLock(&RemovalTestLock);
  1153. KeQueueWorkItem(RemovalTestWorkItem);
  1154. KeReleaseSpinLock(&RemovalTestLock);
  1155. return;
  1156. }
  1157. VOID
  1158. DeviceRemovalTests (
  1159. PVOID Parameter
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. This routine runs through a sequence of device tests.
  1164. Arguments:
  1165. Parameter - Supplies an optional parameter for the work item routine.
  1166. Return Value:
  1167. None.
  1168. --*/
  1169. {
  1170. switch (RemovalTest) {
  1171. //
  1172. // The child addition test stresses adding a child device "concurrently"
  1173. // with removing the parent device. This will test both notifying the
  1174. // system of the child's addition followed by the parent's removal and vice
  1175. // versa.
  1176. //
  1177. case RemovalDeviceTestAddChild:
  1178. DeviceRemovalTestAddChild();
  1179. break;
  1180. //
  1181. // The unreported child test forces a case that is not guaranteed to be
  1182. // tested by the child add test due to timing. It tests the scenario where
  1183. // a device needs to remove a child device that is yet to be reported.
  1184. //
  1185. case RemovalDeviceTestUnreportedChild:
  1186. DeviceRemovalTestUnreportedChild();
  1187. break;
  1188. //
  1189. // The sibling addition test will stress adding two devices to a bus at the
  1190. // same time. It will test adding with the same notification and in
  1191. // subsequent notifications.
  1192. //
  1193. case RemovalDeviceTestAddSibling:
  1194. DeviceRemovalTestAddSibling();
  1195. break;
  1196. //
  1197. // The child remove test will stress removing a child while removing the
  1198. // parent. This will test both notifying the system of the child's removal
  1199. // followed by the parent's removal and vice versa.
  1200. //
  1201. case RemovalDeviceTestRemoveChild:
  1202. DeviceRemovalTestRemoveChild();
  1203. break;
  1204. //
  1205. // The sibling removal test will stress removing two devices from a bus
  1206. // at the same time. It will test removing the devices in the same
  1207. // notification and in two subsequent notifications.
  1208. //
  1209. case RemovalDeviceTestRemoveSibling:
  1210. DeviceRemovalTestRemoveSibling();
  1211. break;
  1212. //
  1213. // The child add/remove test stresses the scenario where one child gets
  1214. // added and another removed just before a parent device gets removed.
  1215. //
  1216. case RemovalDeviceTestAddRemoveChild:
  1217. DeviceRemovalTestAddRemoveChild();
  1218. break;
  1219. //
  1220. // The sibling add/remove test stresses the scenario where one device gets
  1221. // added while another gets removed.
  1222. //
  1223. case RemovalDeviceTestAddRemoveSibling:
  1224. DeviceRemovalTestAddRemoveSibling();
  1225. break;
  1226. //
  1227. // This test covers the case where non-parent ancestory devices get removed
  1228. // while a device is getting removed.
  1229. //
  1230. case RemovalDeviceTestCascadeRemove:
  1231. DeviceRemovalTestCascadeRemove();
  1232. break;
  1233. //
  1234. // The random test creates and removes devices at various levels of the
  1235. // tree every time it is called. This test is used to flush out any timing
  1236. // related issues that cannot be simulated directly.
  1237. //
  1238. case RemovalDeviceTestRandom:
  1239. if (RandomTestCount == 0) {
  1240. RemovalIrpFailEnabled = TRUE;
  1241. DeviceQueueFailEnabled = TRUE;
  1242. }
  1243. DeviceRemovalTestRandom();
  1244. break;
  1245. case RemovalDeviceTestCleanup:
  1246. DeviceRemovalNukeTree();
  1247. RtlDebugPrint("Device Removal Tests Complete.\n");
  1248. if ((DeviceEntryCount != 1) ||
  1249. (BusDeviceCount != 1) ||
  1250. (FunctionDeviceCount != 0)) {
  1251. RtlDebugPrint("Device Removal Cleanup Failed:\n");
  1252. if (DeviceEntryCount != 1) {
  1253. RtlDebugPrint("\tDeviceEntryCount: %d, expected 1\n",
  1254. DeviceEntryCount);
  1255. }
  1256. if (BusDeviceCount != 1) {
  1257. RtlDebugPrint("\tBusDeviceCount: %d, expected 1\n",
  1258. BusDeviceCount);
  1259. }
  1260. if (FunctionDeviceCount != 0) {
  1261. RtlDebugPrint("\tFunctionDeviceCount: %d, expected 1\n",
  1262. FunctionDeviceCount);
  1263. }
  1264. } else {
  1265. RtlDebugPrint("Device Removal Cleanup Succeeded.\n");
  1266. }
  1267. //
  1268. // Fire off a work item to clean everything up.
  1269. //
  1270. KeCreateAndQueueWorkItem(NULL,
  1271. WorkPriorityNormal,
  1272. DeviceRemovalDestroyTests,
  1273. NULL);
  1274. break;
  1275. default:
  1276. break;
  1277. }
  1278. //
  1279. // If the random test is currently not running or the random test has
  1280. // completed its cycles, increment the test counter.
  1281. //
  1282. if ((RemovalTest != RemovalDeviceTestRandom) ||
  1283. (RandomTestCount == RANDOM_TEST_MAX_COUNT)) {
  1284. RemovalTest += 1;
  1285. }
  1286. return;
  1287. }
  1288. VOID
  1289. DeviceRemovalTestAddChild (
  1290. VOID
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. This routine performs the child addition test. This stresses adding a child
  1295. device "concurrently" with removing the parent device. This will test both
  1296. notifying the system of the child's addition followed by the parent's
  1297. removal and vice versa.
  1298. Arguments:
  1299. None.
  1300. Return Value:
  1301. None.
  1302. --*/
  1303. {
  1304. PREMOVAL_DEVICE_ENTRY ChildEntry;
  1305. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1306. BOOL Result;
  1307. RtlDebugPrint("ChildAdd: Started.\n");
  1308. //
  1309. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1310. // until it is enumerated.
  1311. //
  1312. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1313. if (ParentEntry == NULL) {
  1314. RtlDebugPrint("ChildAdd 0: Failed to attach parent device.\n");
  1315. goto TestAddChild;
  1316. }
  1317. //
  1318. // Now that the tree has been fully initialized, add a child device to the
  1319. // parent, notify the system, and then immediately remove the parent,
  1320. // notifying the system again. This will cause the parent to make the start
  1321. // device call on the child before it gets the removal call. This should
  1322. // trigger some bugs if children cannot be removed mid-initialization.
  1323. //
  1324. ChildEntry = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1325. if (ChildEntry == NULL) {
  1326. RtlDebugPrint("ChildAdd 0: Failed to attach child device.\n");
  1327. }
  1328. //
  1329. // If the child failed to be attached, there should be nothing to notify,
  1330. // but do it anyway to stress the system.
  1331. //
  1332. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1333. DeviceRemovalDetachDevice(ParentEntry);
  1334. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1335. //
  1336. // Wait until the parent receives its removal IRP.
  1337. //
  1338. while (ParentEntry->RemovalIrp == FALSE) {
  1339. KeYield();
  1340. }
  1341. //
  1342. // The child should have been removed even though it was in the middle of
  1343. // being initialized. Validate this.
  1344. //
  1345. Result = TRUE;
  1346. if ((ChildEntry != NULL) &&
  1347. ((ChildEntry->Attached != FALSE) ||
  1348. (ChildEntry->RemovalIrp == FALSE))) {
  1349. RtlDebugPrint("ChildAdd 0: Failed to detach the child!\n");
  1350. Result = FALSE;
  1351. }
  1352. if (ParentEntry->Attached != FALSE) {
  1353. RtlDebugPrint("ChildAdd 0: Failed to detach the parent!\n");
  1354. Result = FALSE;
  1355. }
  1356. //
  1357. // The original device tree should have been destroyed, clean up the tree
  1358. // tracking entries.
  1359. //
  1360. KeAcquireSpinLock(&DeviceTreeLock);
  1361. DeviceRemovalDestroyTree(ParentEntry);
  1362. KeReleaseSpinLock(&DeviceTreeLock);
  1363. if (Result != FALSE) {
  1364. RtlDebugPrint("ChildAdd 0: Succeeded!\n");
  1365. }
  1366. //
  1367. // Now perform the test again, but send the parent removal notification
  1368. // first.
  1369. //
  1370. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1371. if (ParentEntry == NULL) {
  1372. RtlDebugPrint("ChildAdd 1: Failed to attach parent device.\n");
  1373. goto TestAddChild;
  1374. }
  1375. //
  1376. // Now that the tree has been fully initialized, remove the parent device,
  1377. // add the child device, signal the system of the parent change and then
  1378. // the child change. This should either test unreported device removal or
  1379. // handling a query children work item between prepare remove and remove
  1380. // work items.
  1381. //
  1382. DeviceRemovalDetachDevice(ParentEntry);
  1383. ChildEntry = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1384. if (ChildEntry == NULL) {
  1385. RtlDebugPrint("ChildAdd 1: Failed to attach child device.\n");
  1386. }
  1387. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1388. KeAcquireSpinLock(&DeviceTreeLock);
  1389. //
  1390. // Only notify the system about the child's creation if the parent is yet
  1391. // to receive a removal IRP and the child was actually created.
  1392. //
  1393. if ((ParentEntry->RemovalIrp == FALSE) && (ChildEntry != NULL)) {
  1394. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1395. }
  1396. KeReleaseSpinLock(&DeviceTreeLock);
  1397. //
  1398. // Wait until the parent receives its removal IRP.
  1399. //
  1400. while (ParentEntry->RemovalIrp == FALSE) {
  1401. KeYield();
  1402. }
  1403. //
  1404. // The child should have been removed even though it was in the middle of
  1405. // being initialized. Validate this.
  1406. //
  1407. Result = TRUE;
  1408. if ((ChildEntry != NULL) &&
  1409. ((ChildEntry->Attached != FALSE) ||
  1410. (ChildEntry->RemovalIrp == FALSE))) {
  1411. RtlDebugPrint("ChildAdd 1: Failed to detach the child!\n");
  1412. Result = FALSE;
  1413. }
  1414. if (ParentEntry->Attached != FALSE) {
  1415. RtlDebugPrint("ChildAdd 1: Failed to detach the parent!\n");
  1416. Result = FALSE;
  1417. }
  1418. //
  1419. // The original device tree should have been destroyed, clean up the tree
  1420. // tracking entries.
  1421. //
  1422. KeAcquireSpinLock(&DeviceTreeLock);
  1423. DeviceRemovalDestroyTree(ParentEntry);
  1424. KeReleaseSpinLock(&DeviceTreeLock);
  1425. if (Result != FALSE) {
  1426. RtlDebugPrint("ChildAdd 1: Succeeded!\n");
  1427. }
  1428. TestAddChild:
  1429. return;
  1430. }
  1431. VOID
  1432. DeviceRemovalTestUnreportedChild (
  1433. VOID
  1434. )
  1435. /*++
  1436. Routine Description:
  1437. This routine performs the unreported child test. It causes a device with a
  1438. child in the unreported state to be removed. This triggers some failure
  1439. handling behavior in the IO subsystem.
  1440. Arguments:
  1441. None.
  1442. Return Value:
  1443. None.
  1444. --*/
  1445. {
  1446. PREMOVAL_DEVICE_ENTRY ChildEntry;
  1447. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1448. BOOL Result;
  1449. RtlDebugPrint("UnreportedChild: Started.\n");
  1450. //
  1451. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1452. // until it is enumerated.
  1453. //
  1454. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1455. if (ParentEntry == NULL) {
  1456. RtlDebugPrint("UnreportedChild: Failed to attach parent device.\n");
  1457. goto TestUnreportedChildEnd;
  1458. }
  1459. //
  1460. // Now that the tree has been fully initialized, remove the parent device,
  1461. // add the child device, and signal the system of the parent change. Do not
  1462. // notify the system of the child's presence. This should test unreported
  1463. // device removal.
  1464. //
  1465. DeviceRemovalDetachDevice(ParentEntry);
  1466. ChildEntry = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1467. if (ChildEntry == NULL) {
  1468. RtlDebugPrint("UnreportedChild: Failed to attach child device.\n");
  1469. }
  1470. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1471. //
  1472. // Wait until the parent receives its removal IRP.
  1473. //
  1474. while (ParentEntry->RemovalIrp == FALSE) {
  1475. KeYield();
  1476. }
  1477. //
  1478. // The child should have been removed even though it was in the middle of
  1479. // being initialized. Validate this.
  1480. //
  1481. Result = TRUE;
  1482. if ((ChildEntry != NULL) &&
  1483. ((ChildEntry->Attached != FALSE) ||
  1484. (ChildEntry->RemovalIrp == FALSE))) {
  1485. RtlDebugPrint("UnreportedChild: Failed to detach the child!\n");
  1486. Result = FALSE;
  1487. }
  1488. if (ParentEntry->Attached != FALSE) {
  1489. RtlDebugPrint("UnreportedChild: Failed to detach the parent!\n");
  1490. Result = FALSE;
  1491. }
  1492. //
  1493. // The original device tree should have been destroyed, clean up the tree
  1494. // tracking entries.
  1495. //
  1496. KeAcquireSpinLock(&DeviceTreeLock);
  1497. DeviceRemovalDestroyTree(ParentEntry);
  1498. KeReleaseSpinLock(&DeviceTreeLock);
  1499. if (Result != FALSE) {
  1500. RtlDebugPrint("UnreportedChild: Succeeded!\n");
  1501. }
  1502. TestUnreportedChildEnd:
  1503. return;
  1504. }
  1505. VOID
  1506. DeviceRemovalTestAddSibling (
  1507. VOID
  1508. )
  1509. /*++
  1510. Routine Description:
  1511. This routine tests adding two sibling devices. It first tests adding them
  1512. within one system notification call and then from sequential calls.
  1513. Arguments:
  1514. None.
  1515. Return Value:
  1516. None.
  1517. --*/
  1518. {
  1519. PREMOVAL_DEVICE_ENTRY FirstSibling;
  1520. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1521. BOOL Result;
  1522. PREMOVAL_DEVICE_ENTRY SecondSibling;
  1523. RtlDebugPrint("AddSibling: Started.\n");
  1524. //
  1525. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1526. // until it is enumerated.
  1527. //
  1528. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1529. if (ParentEntry == NULL) {
  1530. RtlDebugPrint("AddSibling Failed to attach parent device.\n");
  1531. goto TestAddSiblingEnd;
  1532. }
  1533. //
  1534. // Now attach two devices and notify the system.
  1535. //
  1536. FirstSibling = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1537. if (FirstSibling == NULL) {
  1538. RtlDebugPrint("AddSibling 0: Failed to allocate first sibling.\n");
  1539. }
  1540. SecondSibling = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1541. if (SecondSibling == NULL) {
  1542. RtlDebugPrint("AddSibling 0: Failed to allocate second sibling.\n");
  1543. }
  1544. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1545. //
  1546. // Wait for the tree creation to complete and then check to make sure the
  1547. // devices are fully attached.
  1548. //
  1549. Result = TRUE;
  1550. DeviceRemovalWaitForTreeCreation(ParentEntry);
  1551. if ((FirstSibling != NULL) && (FirstSibling->BusContext == NULL)) {
  1552. RtlDebugPrint("AddSibling 0: First sibling failed to enumerate.\n");
  1553. Result = FALSE;
  1554. }
  1555. if ((SecondSibling != NULL) && (SecondSibling->BusContext == NULL)) {
  1556. RtlDebugPrint("AddSibling 0: Second sibling failed to enumerate.\n");
  1557. Result = FALSE;
  1558. }
  1559. if (Result != FALSE) {
  1560. RtlDebugPrint("AddSibling 0: Succeeded!\n");
  1561. }
  1562. //
  1563. // Now add two additional siblings and notify the system after each
  1564. // addition.
  1565. //
  1566. FirstSibling = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1567. if (FirstSibling == NULL) {
  1568. RtlDebugPrint("AddSibling 1: Failed to allocate first sibling.\n");
  1569. }
  1570. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1571. SecondSibling = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1572. if (SecondSibling == NULL) {
  1573. RtlDebugPrint("AddSibling 1: Failed to allocate second sibling.\n");
  1574. }
  1575. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1576. //
  1577. // Wait for the tree creation to complete and then check to make sure the
  1578. // devices are fully attached.
  1579. //
  1580. Result = TRUE;
  1581. DeviceRemovalWaitForTreeCreation(ParentEntry);
  1582. if ((FirstSibling != NULL) && (FirstSibling->BusContext == NULL)) {
  1583. RtlDebugPrint("AddSibling 1: First sibling failed to enumerate.\n");
  1584. Result = FALSE;
  1585. }
  1586. if ((SecondSibling != NULL) && (SecondSibling->BusContext == NULL)) {
  1587. RtlDebugPrint("AddSibling 1: Second sibling failed to enumerate.\n");
  1588. Result = FALSE;
  1589. }
  1590. if (Result != FALSE) {
  1591. RtlDebugPrint("AddSibling 1: Succeeded!\n");
  1592. }
  1593. //
  1594. // Now detach the parent device and exit.
  1595. //
  1596. DeviceRemovalDetachDevice(ParentEntry);
  1597. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1598. //
  1599. // Wait until the parent receives its removal IRP.
  1600. //
  1601. while (ParentEntry->RemovalIrp == FALSE) {
  1602. KeYield();
  1603. }
  1604. //
  1605. // The original device tree should have been destroyed, clean up the tree
  1606. // tracking entries.
  1607. //
  1608. KeAcquireSpinLock(&DeviceTreeLock);
  1609. DeviceRemovalDestroyTree(ParentEntry);
  1610. KeReleaseSpinLock(&DeviceTreeLock);
  1611. TestAddSiblingEnd:
  1612. return;
  1613. }
  1614. VOID
  1615. DeviceRemovalTestRemoveChild (
  1616. VOID
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. This routine tests removing a child device while removing the devices
  1621. parent. This test should stress scenarios where a child device has already
  1622. entered the removal process by the time the parent tries to remove it and
  1623. where the parent has already pushed the child into the removal process by
  1624. the time the child tries to remove itself.
  1625. Arguments:
  1626. None.
  1627. Return Value:
  1628. None.
  1629. --*/
  1630. {
  1631. PREMOVAL_DEVICE_ENTRY ChildEntry;
  1632. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1633. RtlDebugPrint("RemoveChild: Started.\n");
  1634. //
  1635. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1636. // until it is enumerated.
  1637. //
  1638. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1639. if (ParentEntry == NULL) {
  1640. RtlDebugPrint("RemoveChild: Failed to attach parent device.\n");
  1641. goto TestRemoveChild;
  1642. }
  1643. //
  1644. // Get one of the children and mark it for removal.
  1645. //
  1646. ASSERT(LIST_EMPTY(&(ParentEntry->ChildListHead)) == FALSE);
  1647. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1648. ParentEntry->ChildListHead.Next,
  1649. REMOVAL_DEVICE_ENTRY,
  1650. SiblingEntry);
  1651. DeviceRemovalDetachDevice(ChildEntry);
  1652. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1653. //
  1654. // Now remove the parent.
  1655. //
  1656. DeviceRemovalDetachDevice(ParentEntry);
  1657. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1658. //
  1659. // Wait for the removal process to complete and then validate the tree.
  1660. //
  1661. while (ParentEntry->RemovalIrp == FALSE) {
  1662. KeYield();
  1663. }
  1664. //
  1665. // Make sure the child was detached.
  1666. //
  1667. if ((ChildEntry->RemovalIrp == FALSE) || (ChildEntry->Attached != FALSE)) {
  1668. RtlDebugPrint("RemoveChild 0: Failed to properly remove child.\n");
  1669. } else {
  1670. RtlDebugPrint("RemoveChild 0: Succeeded!\n");
  1671. }
  1672. //
  1673. // Clean up the tree.
  1674. //
  1675. KeAcquireSpinLock(&DeviceTreeLock);
  1676. DeviceRemovalDestroyTree(ParentEntry);
  1677. KeReleaseSpinLock(&DeviceTreeLock);
  1678. //
  1679. // Now perform the test again but notify the system about the parent's
  1680. // removal first.
  1681. //
  1682. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1683. if (ParentEntry == NULL) {
  1684. RtlDebugPrint("RemoveChild: Failed to attach parent device.\n");
  1685. goto TestRemoveChild;
  1686. }
  1687. //
  1688. // Get one of the children.
  1689. //
  1690. ASSERT(LIST_EMPTY(&(ParentEntry->ChildListHead)) == FALSE);
  1691. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1692. ParentEntry->ChildListHead.Next,
  1693. REMOVAL_DEVICE_ENTRY,
  1694. SiblingEntry);
  1695. //
  1696. // Mark the parent for removal, notify the system, and then try to remove
  1697. // the child.
  1698. //
  1699. DeviceRemovalDetachDevice(ParentEntry);
  1700. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1701. DeviceRemovalDetachDevice(ChildEntry);
  1702. KeAcquireSpinLock(&DeviceTreeLock);
  1703. if (ParentEntry->RemovalIrp == FALSE) {
  1704. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1705. }
  1706. KeReleaseSpinLock(&DeviceTreeLock);
  1707. //
  1708. // Wait for the removal process to complete and then validate the tree.
  1709. //
  1710. while (ParentEntry->RemovalIrp == FALSE) {
  1711. KeYield();
  1712. }
  1713. //
  1714. // Make sure the child was detached.
  1715. //
  1716. if ((ChildEntry->RemovalIrp == FALSE) || (ChildEntry->Attached != FALSE)) {
  1717. RtlDebugPrint("RemoveChild 1: Failed to properly remove child.\n");
  1718. } else {
  1719. RtlDebugPrint("RemoveChild 1: Succeeded!\n");
  1720. }
  1721. //
  1722. // Clean up the tree.
  1723. //
  1724. KeAcquireSpinLock(&DeviceTreeLock);
  1725. DeviceRemovalDestroyTree(ParentEntry);
  1726. KeReleaseSpinLock(&DeviceTreeLock);
  1727. TestRemoveChild:
  1728. return;
  1729. }
  1730. VOID
  1731. DeviceRemovalTestRemoveSibling (
  1732. VOID
  1733. )
  1734. /*++
  1735. Routine Description:
  1736. This routine implements the sibling removal test. This test stresses
  1737. removing two devices from a bus at the same time. It tests removing the
  1738. devices in the same system notification and in sequential notifications.
  1739. Arguments:
  1740. None.
  1741. Return Value:
  1742. None.
  1743. --*/
  1744. {
  1745. PREMOVAL_DEVICE_ENTRY FirstSibling;
  1746. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1747. PREMOVAL_DEVICE_ENTRY SecondSibling;
  1748. RtlDebugPrint("RemoveSibling: Started.\n");
  1749. //
  1750. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1751. // until it is enumerated.
  1752. //
  1753. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1754. if (ParentEntry == NULL) {
  1755. RtlDebugPrint("RemoveSibling: Failed to attach parent device.\n");
  1756. goto TestRemoveSibling;
  1757. }
  1758. //
  1759. // Make sure that the parent has at least two children.
  1760. //
  1761. ASSERT(ParentEntry->ChildListHead.Next !=
  1762. ParentEntry->ChildListHead.Previous);
  1763. FirstSibling = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1764. ParentEntry->ChildListHead.Next,
  1765. REMOVAL_DEVICE_ENTRY,
  1766. SiblingEntry);
  1767. SecondSibling = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1768. ParentEntry->ChildListHead.Previous,
  1769. REMOVAL_DEVICE_ENTRY,
  1770. SiblingEntry);
  1771. //
  1772. // Detach the children and notify the system.
  1773. //
  1774. DeviceRemovalDetachDevice(FirstSibling);
  1775. DeviceRemovalDetachDevice(SecondSibling);
  1776. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1777. //
  1778. // Wait for their removal IRPs.
  1779. //
  1780. while (FirstSibling->RemovalIrp == FALSE) {
  1781. KeYield();
  1782. }
  1783. while (SecondSibling->RemovalIrp == FALSE) {
  1784. KeYield();
  1785. }
  1786. RtlDebugPrint("RemoveSibling: Successful!\n");
  1787. //
  1788. // Make sure removing the children did not remove the parent.
  1789. //
  1790. ASSERT(ParentEntry->RemovalIrp == FALSE);
  1791. ASSERT(ParentEntry->Attached != FALSE);
  1792. //
  1793. // Now destroy the parent and exit.
  1794. //
  1795. DeviceRemovalDetachDevice(ParentEntry);
  1796. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1797. while (ParentEntry->RemovalIrp == FALSE) {
  1798. KeYield();
  1799. }
  1800. //
  1801. // Clean up the tree.
  1802. //
  1803. KeAcquireSpinLock(&DeviceTreeLock);
  1804. DeviceRemovalDestroyTree(ParentEntry);
  1805. KeReleaseSpinLock(&DeviceTreeLock);
  1806. TestRemoveSibling:
  1807. return;
  1808. }
  1809. VOID
  1810. DeviceRemovalTestAddRemoveChild (
  1811. VOID
  1812. )
  1813. /*++
  1814. Routine Description:
  1815. This routine implements the add/remove child test. This test adds a child
  1816. and removes a different child while removing their parent device.
  1817. Arguments:
  1818. None.
  1819. Return Value:
  1820. None.
  1821. --*/
  1822. {
  1823. PREMOVAL_DEVICE_ENTRY AddChild;
  1824. PREMOVAL_DEVICE_ENTRY ParentEntry;
  1825. PREMOVAL_DEVICE_ENTRY RemoveChild;
  1826. BOOL Result;
  1827. RtlDebugPrint("AddRemoveChild: Started.\n");
  1828. //
  1829. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1830. // until it is enumerated.
  1831. //
  1832. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1833. if (ParentEntry == NULL) {
  1834. RtlDebugPrint("AddRemoveChild: Failed to attach parent device.\n");
  1835. goto TestAddRemoveChildEnd;
  1836. }
  1837. //
  1838. // Get a child entry to remove and mark it for removal.
  1839. //
  1840. ASSERT(LIST_EMPTY(&(ParentEntry->ChildListHead)) == FALSE);
  1841. RemoveChild = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1842. ParentEntry->ChildListHead.Next,
  1843. REMOVAL_DEVICE_ENTRY,
  1844. SiblingEntry);
  1845. DeviceRemovalDetachDevice(RemoveChild);
  1846. //
  1847. // Attach a new child to the parent device and notify the system that the
  1848. // parent device's topology changed.
  1849. //
  1850. AddChild = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1851. if (AddChild == NULL) {
  1852. RtlDebugPrint("AddRemoveChild 0: Failed to allocate child device.\n");
  1853. }
  1854. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1855. //
  1856. // Now remove the parent device.
  1857. //
  1858. DeviceRemovalDetachDevice(ParentEntry);
  1859. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1860. //
  1861. // Wait for the removal.
  1862. //
  1863. while (ParentEntry->RemovalIrp == FALSE) {
  1864. KeYield();
  1865. }
  1866. //
  1867. // Check the state of the tree.
  1868. //
  1869. Result = TRUE;
  1870. if ((AddChild->RemovalIrp == FALSE) || (AddChild->Attached != FALSE)) {
  1871. RtlDebugPrint("AddRemoveChild 0: Failed to remove added child.\n");
  1872. Result = FALSE;
  1873. }
  1874. if ((RemoveChild->RemovalIrp == FALSE) ||
  1875. (RemoveChild->Attached != FALSE)) {
  1876. RtlDebugPrint("AddRemoveChild 0: Failed to remove child marked "
  1877. "removed.\n");
  1878. Result = FALSE;
  1879. }
  1880. if (Result != FALSE) {
  1881. RtlDebugPrint("AddRemoveChild 0: Successful!\n");
  1882. }
  1883. //
  1884. // Destroy the tree.
  1885. //
  1886. KeAcquireSpinLock(&DeviceTreeLock);
  1887. DeviceRemovalDestroyTree(ParentEntry);
  1888. KeReleaseSpinLock(&DeviceTreeLock);
  1889. //
  1890. // Now do it where the system gets notified of the parent's removal first.
  1891. //
  1892. ParentEntry = DeviceRemovalInitializeTreeForTest();
  1893. if (ParentEntry == NULL) {
  1894. RtlDebugPrint("AddRemoveChild: Failed to attach parent device.\n");
  1895. goto TestAddRemoveChildEnd;
  1896. }
  1897. //
  1898. // Get a child entry to remove and mark it for removal.
  1899. //
  1900. ASSERT(LIST_EMPTY(&(ParentEntry->ChildListHead)) == FALSE);
  1901. RemoveChild = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(
  1902. ParentEntry->ChildListHead.Next,
  1903. REMOVAL_DEVICE_ENTRY,
  1904. SiblingEntry);
  1905. DeviceRemovalDetachDevice(RemoveChild);
  1906. //
  1907. // Attach a new child to the parent device and notify the system that the
  1908. // parent device's topology changed.
  1909. //
  1910. AddChild = DeviceRemovalAttachChildDevice(ParentEntry->BusContext);
  1911. if (AddChild == NULL) {
  1912. RtlDebugPrint("AddRemoveChild 1: Failed to allocate child device.\n");
  1913. }
  1914. //
  1915. // Mark the parent for removal and notify the system.
  1916. //
  1917. DeviceRemovalDetachDevice(ParentEntry);
  1918. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1919. //
  1920. // If the children haven't received removal IRPs yet, signal the system.
  1921. //
  1922. KeAcquireSpinLock(&DeviceTreeLock);
  1923. if ((AddChild->RemovalIrp == FALSE) || (RemoveChild->RemovalIrp == FALSE)) {
  1924. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  1925. }
  1926. KeReleaseSpinLock(&DeviceTreeLock);
  1927. //
  1928. // Wait for the removal.
  1929. //
  1930. while (ParentEntry->RemovalIrp == FALSE) {
  1931. KeYield();
  1932. }
  1933. //
  1934. // Check the state of the tree.
  1935. //
  1936. Result = TRUE;
  1937. if ((AddChild->RemovalIrp == FALSE) || (AddChild->Attached != FALSE)) {
  1938. RtlDebugPrint("AddRemoveChild 1: Failed to remove added child.\n");
  1939. Result = FALSE;
  1940. }
  1941. if ((RemoveChild->RemovalIrp == FALSE) ||
  1942. (RemoveChild->Attached != FALSE)) {
  1943. RtlDebugPrint("AddRemoveChild 1: Failed to remove child marked "
  1944. "removed.\n");
  1945. Result = FALSE;
  1946. }
  1947. if (Result != FALSE) {
  1948. RtlDebugPrint("AddRemoveChild 1: Successful!\n");
  1949. }
  1950. //
  1951. // Destroy the tree.
  1952. //
  1953. KeAcquireSpinLock(&DeviceTreeLock);
  1954. DeviceRemovalDestroyTree(ParentEntry);
  1955. KeReleaseSpinLock(&DeviceTreeLock);
  1956. TestAddRemoveChildEnd:
  1957. return;
  1958. }
  1959. VOID
  1960. DeviceRemovalTestAddRemoveSibling (
  1961. VOID
  1962. )
  1963. /*++
  1964. Routine Description:
  1965. This routine implements the add/remove sibling test. This test adds a
  1966. device tree while removing another.
  1967. Arguments:
  1968. None.
  1969. Return Value:
  1970. None.
  1971. --*/
  1972. {
  1973. PREMOVAL_DEVICE_ENTRY FirstSibling;
  1974. PREMOVAL_DEVICE_ENTRY SecondSibling;
  1975. RtlDebugPrint("AddRemoveSibling: Started.\n");
  1976. //
  1977. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  1978. // until it is enumerated.
  1979. //
  1980. FirstSibling = DeviceRemovalInitializeTreeForTest();
  1981. if (FirstSibling == NULL) {
  1982. RtlDebugPrint("AddRemoveSibling: Failed to attach first sibling.\n");
  1983. goto TestAddRemoveSiblingEnd;
  1984. }
  1985. //
  1986. // Now attach another device to the root, remove the one that was just
  1987. // created and then notify the system.
  1988. //
  1989. SecondSibling = DeviceRemovalAttachChildDevice(RootDevice);
  1990. if (SecondSibling == NULL) {
  1991. RtlDebugPrint("AddRemoveSibling: Failed to attach second sibling.\n");
  1992. }
  1993. DeviceRemovalDetachDevice(FirstSibling);
  1994. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  1995. //
  1996. // Wait for the first sibling to be removed.
  1997. //
  1998. while (FirstSibling->RemovalIrp == FALSE) {
  1999. KeYield();
  2000. }
  2001. //
  2002. // Wait for the second sibling to be created.
  2003. //
  2004. DeviceRemovalWaitForTreeCreation(SecondSibling);
  2005. //
  2006. // If it made it this far, it succeeeded.
  2007. //
  2008. RtlDebugPrint("AddRemoveSibling: Successful!\n");
  2009. //
  2010. // Remove the second sibling's tree.
  2011. //
  2012. DeviceRemovalDetachDevice(SecondSibling);
  2013. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  2014. while (SecondSibling->RemovalIrp == FALSE) {
  2015. KeYield();
  2016. }
  2017. //
  2018. // Clean up the accounting structures.
  2019. //
  2020. KeAcquireSpinLock(&DeviceTreeLock);
  2021. DeviceRemovalDestroyTree(FirstSibling);
  2022. DeviceRemovalDestroyTree(SecondSibling);
  2023. KeReleaseSpinLock(&DeviceTreeLock);
  2024. TestAddRemoveSiblingEnd:
  2025. return;
  2026. }
  2027. VOID
  2028. DeviceRemovalTestCascadeRemove (
  2029. VOID
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. This routine implements the cascade removal test. This test sends removal
  2034. notifications about multiple devices that are in a device hierarchy.
  2035. Arguments:
  2036. None.
  2037. Return Value:
  2038. None.
  2039. --*/
  2040. {
  2041. PREMOVAL_DEVICE_ENTRY ParentEntry;
  2042. RtlDebugPrint("CascadeRemove: Started.\n");
  2043. //
  2044. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  2045. // until it is enumerated.
  2046. //
  2047. ParentEntry = DeviceRemovalInitializeTreeForTest();
  2048. if (ParentEntry== NULL) {
  2049. RtlDebugPrint("CascadeRemove: Failed to attach root entry.\n");
  2050. goto TestCascadeRemoveEnd;
  2051. }
  2052. //
  2053. // Mark each element in the tree for removal.
  2054. //
  2055. KeAcquireSpinLock(&DeviceTreeLock);
  2056. DeviceRemovalCascadeRemoveHelper(ParentEntry,
  2057. RootDevice->TreeEntry->DeviceToken);
  2058. KeReleaseSpinLock(&DeviceTreeLock);
  2059. //
  2060. // Wait for the parent device to be removed. Its removal process will
  2061. // assert if any other removal failed.
  2062. //
  2063. while (ParentEntry->RemovalIrp == FALSE) {
  2064. KeYield();
  2065. }
  2066. RtlDebugPrint("CascadeRemove: Successful!\n");
  2067. //
  2068. // Clean up the accounting structures.
  2069. //
  2070. KeAcquireSpinLock(&DeviceTreeLock);
  2071. DeviceRemovalDestroyTree(ParentEntry);
  2072. KeReleaseSpinLock(&DeviceTreeLock);
  2073. TestCascadeRemoveEnd:
  2074. return;
  2075. }
  2076. VOID
  2077. DeviceRemovalCascadeRemoveHelper (
  2078. PREMOVAL_DEVICE_ENTRY RootEntry,
  2079. PVOID ParentDeviceToken
  2080. )
  2081. /*++
  2082. Routine Description:
  2083. This routine recursively marks every device in a tree for removal,
  2084. notifying the system along the way. It does a post-order traversal.
  2085. Arguments:
  2086. RootEntry - Supplies a pointer to the root of the device tree that needs
  2087. to be removed.
  2088. ParentDeviceToken - Supplies a pointer to the device token of the root's
  2089. parent device.
  2090. Return Value:
  2091. None.
  2092. --*/
  2093. {
  2094. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2095. PLIST_ENTRY CurrentEntry;
  2096. CurrentEntry = RootEntry->ChildListHead.Next;
  2097. while (CurrentEntry != &(RootEntry->ChildListHead)) {
  2098. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2099. REMOVAL_DEVICE_ENTRY,
  2100. SiblingEntry);
  2101. CurrentEntry = CurrentEntry->Next;
  2102. DeviceRemovalCascadeRemoveHelper(ChildEntry, RootEntry->DeviceToken);
  2103. }
  2104. DeviceRemovalDetachDevice(RootEntry);
  2105. IoNotifyDeviceTopologyChange(ParentDeviceToken);
  2106. return;
  2107. }
  2108. VOID
  2109. DeviceRemovalTestRandom (
  2110. VOID
  2111. )
  2112. /*++
  2113. Routine Description:
  2114. This routine walks the device tree and marks some devices as detached.
  2115. Arguments:
  2116. Parameter - Supplies an optional parameter for the work item routine.
  2117. Return Value:
  2118. None.
  2119. --*/
  2120. {
  2121. PREMOVAL_DEVICE_ENTRY DetachEntry;
  2122. PREMOVAL_DEVICE_ENTRY NewEntry;
  2123. PREMOVAL_DEVICE_ENTRY ParentEntry;
  2124. BOOL QueueFailure;
  2125. BOOL TopologyChanged;
  2126. ASSERT(KeGetRunLevel() == RunLevelLow);
  2127. ASSERT(RemovalDeviceTree != NULL);
  2128. TopologyChanged = FALSE;
  2129. //
  2130. // Acquire the tree lock before operating on the tree and the random test's
  2131. // variables.
  2132. //
  2133. KeAcquireSpinLock(&DeviceTreeLock);
  2134. //
  2135. // Clean up the device tree's lingering test structures based on the clean
  2136. // up rate.
  2137. //
  2138. RandomTestCount += 1;
  2139. if ((RandomTestCount % RANDOM_TEST_CLEAN_TREE_RATE) == 0) {
  2140. DeviceRemovalCleanTree(RemovalDeviceTree, NULL);
  2141. }
  2142. //
  2143. // Record that a device queue failure should be added after the system
  2144. // is notified of the change.
  2145. //
  2146. if ((RandomTestCount % DEVICE_QUEUE_FAILURE_RATE) == 0) {
  2147. QueueFailure = TRUE;
  2148. } else {
  2149. QueueFailure = FALSE;
  2150. }
  2151. //
  2152. // This test alternates between adding and removing a device from the tree.
  2153. //
  2154. ParentEntry = NULL;
  2155. if (RandomRemoveDevice != FALSE) {
  2156. RandomRemoveDevice = FALSE;
  2157. ASSERT((RandomRemoveLevel <= RANDOM_REMOVE_END_LEVEL) &&
  2158. (RandomRemoveLevel >= RANDOM_REMOVE_START_LEVEL));
  2159. //
  2160. // Pick a device at the current removal level and detach it.
  2161. //
  2162. DetachEntry = DeviceRemovalFindDeviceAndDetach(
  2163. RemovalDeviceTree,
  2164. &ParentEntry,
  2165. RANDOM_REMOVE_START_LEVEL);
  2166. if (DetachEntry != NULL) {
  2167. ASSERT(DetachEntry->Attached == FALSE);
  2168. ASSERT(ParentEntry != NULL);
  2169. TopologyChanged = TRUE;
  2170. }
  2171. if (RandomRemoveLevel == RANDOM_REMOVE_END_LEVEL) {
  2172. RandomRemoveLevel = RANDOM_REMOVE_START_LEVEL;
  2173. } else {
  2174. RandomRemoveLevel += 1;
  2175. }
  2176. //
  2177. // Add a new device tree at some layer within the existing tree.
  2178. //
  2179. } else {
  2180. RandomRemoveDevice = TRUE;
  2181. ASSERT(RandomAddLevel <= RANDOM_ADD_END_LEVEL);
  2182. NewEntry = DeviceRemovalFindDeviceAndAddChild(RemovalDeviceTree,
  2183. &ParentEntry,
  2184. RANDOM_ADD_START_LEVEL);
  2185. if (NewEntry != NULL) {
  2186. ASSERT(ParentEntry != NULL);
  2187. TopologyChanged = TRUE;
  2188. }
  2189. if (RandomAddLevel == RANDOM_ADD_END_LEVEL) {
  2190. RandomAddLevel = RANDOM_ADD_START_LEVEL;
  2191. } else {
  2192. RandomAddLevel += 1;
  2193. }
  2194. }
  2195. KeReleaseSpinLock(&DeviceTreeLock);
  2196. if (TopologyChanged != FALSE) {
  2197. ASSERT(ParentEntry != NULL);
  2198. //
  2199. // Inform the system that it might want to check the device tree again.
  2200. // This is simulating the actions a bus driver might take when it
  2201. // notices that a child has been detached.
  2202. //
  2203. IoNotifyDeviceTopologyChange(ParentEntry->DeviceToken);
  2204. if (QueueFailure != FALSE) {
  2205. IoSetTestHook(IO_FAIL_QUEUE_DEVICE_WORK);
  2206. }
  2207. }
  2208. return;
  2209. }
  2210. PREMOVAL_DEVICE_ENTRY
  2211. DeviceRemovalFindDeviceAndDetach (
  2212. PREMOVAL_DEVICE_ENTRY Entry,
  2213. PREMOVAL_DEVICE_ENTRY *ParentEntry,
  2214. ULONG Level
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. This routine recurses over the device tree looking for a device to detach
  2219. at the current removal level. It detaches the device if it finds one.
  2220. Arguments:
  2221. Entry - Supplies a pointer to the entry currently being evaluated for
  2222. removal.
  2223. ParentEntry - Supplies a pointer that receives the parent device of the
  2224. device marked for removal.
  2225. Level - Supplies the current tree level of the search.
  2226. Return Value:
  2227. Returns a tree entry if the level matches the removal level and the device
  2228. is attached or if a child of the tree entry matches the requirements.
  2229. Returns NULL if the above requirements are not met by the device or any of
  2230. the devices in its tree.
  2231. --*/
  2232. {
  2233. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2234. PLIST_ENTRY CurrentEntry;
  2235. PREMOVAL_DEVICE_ENTRY DetachEntry;
  2236. //
  2237. // Recurse over each child looking for a device to remove from the
  2238. // appropriate level.
  2239. //
  2240. DetachEntry = NULL;
  2241. CurrentEntry = Entry->ChildListHead.Next;
  2242. while (CurrentEntry != &(Entry->ChildListHead)) {
  2243. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2244. REMOVAL_DEVICE_ENTRY,
  2245. SiblingEntry);
  2246. //
  2247. // If the current device fits the criteria, return it.
  2248. //
  2249. if ((Level == RandomRemoveLevel) && (ChildEntry->Attached != FALSE)) {
  2250. DeviceRemovalDetachDevice(ChildEntry);
  2251. *ParentEntry = Entry;
  2252. return ChildEntry;
  2253. }
  2254. //
  2255. // Otherwise recurse on the device.
  2256. //
  2257. DetachEntry = DeviceRemovalFindDeviceAndDetach(ChildEntry,
  2258. ParentEntry,
  2259. Level + 1);
  2260. if (DetachEntry != NULL) {
  2261. break;
  2262. }
  2263. CurrentEntry = CurrentEntry->Next;
  2264. }
  2265. return DetachEntry;
  2266. }
  2267. PREMOVAL_DEVICE_ENTRY
  2268. DeviceRemovalFindDeviceAndAddChild (
  2269. PREMOVAL_DEVICE_ENTRY Entry,
  2270. PREMOVAL_DEVICE_ENTRY *ParentEntry,
  2271. ULONG Level
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. This routine recurses over the device tree looking for a device to which it
  2276. will add a child. The requirement is that the device is fully initialized
  2277. and remains attached.
  2278. Arguments:
  2279. Entry - Supplies a pointer to the entry currently being evaluated for
  2280. child addition.
  2281. ParentEntry - Supplies a pointer that receives the parent entry of the new
  2282. device tree entry.
  2283. Level - Supplies the current tree level of the search.
  2284. Return Value:
  2285. Returns a new device that was attached to the current entry. Or NULL if no
  2286. device could be found that are prepared for new children.
  2287. --*/
  2288. {
  2289. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2290. PLIST_ENTRY CurrentEntry;
  2291. PDEVICE Device;
  2292. PREMOVAL_DEVICE_ENTRY NewEntry;
  2293. //
  2294. // If the current device fits the criteria, then add a child and return the
  2295. // new child.
  2296. //
  2297. Device = (PDEVICE)Entry->DeviceToken;
  2298. if ((Level == RandomAddLevel) &&
  2299. (Entry->Attached != FALSE) &&
  2300. (Entry->BusContext != NULL) &&
  2301. (IoIsDeviceStarted(Device) != FALSE)) {
  2302. ASSERT(Entry->RemovalIrp == FALSE);
  2303. NewEntry = DeviceRemovalAttachChildDeviceHelper(Entry->BusContext);
  2304. *ParentEntry = Entry;
  2305. return NewEntry;
  2306. }
  2307. //
  2308. // Recurse over each child looking for a device to which to add a child.
  2309. //
  2310. NewEntry = NULL;
  2311. CurrentEntry = Entry->ChildListHead.Next;
  2312. while (CurrentEntry != &(Entry->ChildListHead)) {
  2313. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2314. REMOVAL_DEVICE_ENTRY,
  2315. SiblingEntry);
  2316. NewEntry = DeviceRemovalFindDeviceAndAddChild(ChildEntry,
  2317. ParentEntry,
  2318. Level + 1);
  2319. if (NewEntry != NULL) {
  2320. break;
  2321. }
  2322. CurrentEntry = CurrentEntry->Next;
  2323. }
  2324. return NewEntry;
  2325. }
  2326. VOID
  2327. DeviceRemovalDestroyTree (
  2328. PREMOVAL_DEVICE_ENTRY RootEntry
  2329. )
  2330. /*++
  2331. Routine Description:
  2332. This routine destroys the device removal tree tracking structures.
  2333. Arguments:
  2334. RootEntry - Supplies a pointer to the root of the tree that needs ot be
  2335. destroyed.
  2336. Return Value:
  2337. None.
  2338. --*/
  2339. {
  2340. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2341. PLIST_ENTRY CurrentEntry;
  2342. CurrentEntry = RootEntry->ChildListHead.Next;
  2343. while (CurrentEntry != &(RootEntry->ChildListHead)) {
  2344. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2345. REMOVAL_DEVICE_ENTRY,
  2346. SiblingEntry);
  2347. CurrentEntry = CurrentEntry->Next;
  2348. DeviceRemovalDestroyTree(ChildEntry);
  2349. }
  2350. ASSERT(RootEntry->Attached == FALSE);
  2351. ASSERT(RootEntry->RemovalIrp != FALSE);
  2352. DeviceRemovalDeleteTreeEntry(RootEntry);
  2353. return;
  2354. }
  2355. VOID
  2356. DeviceRemovalCleanTree (
  2357. PREMOVAL_DEVICE_ENTRY Entry,
  2358. PREMOVAL_DEVICE_ENTRY ParentEntry
  2359. )
  2360. /*++
  2361. Routine Description:
  2362. This routine destroys the device removal tree tracking structures if they
  2363. have received the removal IRP and their parent has received the removal
  2364. IRP.
  2365. Arguments:
  2366. Entry - Supplies a pointer to the local root of the tree that needs ot be
  2367. destroyed.
  2368. ParentEntry - Supplies a pointer to the parent of the local tree root that
  2369. needs to be destroyed.
  2370. Return Value:
  2371. None.
  2372. --*/
  2373. {
  2374. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2375. PLIST_ENTRY CurrentEntry;
  2376. CurrentEntry = Entry->ChildListHead.Next;
  2377. while (CurrentEntry != &(Entry->ChildListHead)) {
  2378. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2379. REMOVAL_DEVICE_ENTRY,
  2380. SiblingEntry);
  2381. CurrentEntry = CurrentEntry->Next;
  2382. DeviceRemovalCleanTree(ChildEntry, Entry);
  2383. }
  2384. //
  2385. // If both the entry and the parent entry have received the removal IRP,
  2386. // then this structure can be cleaned up. Or if the parent is the root
  2387. // device.
  2388. //
  2389. if ((Entry->RemovalIrp != FALSE) &&
  2390. (ParentEntry != NULL) &&
  2391. ((ParentEntry->RemovalIrp != FALSE) ||
  2392. (ParentEntry == RemovalDeviceTree))) {
  2393. ASSERT(LIST_EMPTY(&(Entry->ChildListHead)) != FALSE);
  2394. DeviceRemovalDeleteTreeEntry(Entry);
  2395. }
  2396. return;
  2397. }
  2398. VOID
  2399. DeviceRemovalNukeTree (
  2400. VOID
  2401. )
  2402. /*++
  2403. Routine Description:
  2404. This routine removes all the subtrees from the root device. It current
  2405. cannot remove the root because it is attached to the root device which
  2406. doesn't accept query children commands.
  2407. Arguments:
  2408. None.
  2409. Return Value:
  2410. None.
  2411. --*/
  2412. {
  2413. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2414. PLIST_ENTRY CurrentEntry;
  2415. //
  2416. // Acquire the tree lock before traversing the tree.
  2417. //
  2418. KeAcquireSpinLock(&DeviceTreeLock);
  2419. //
  2420. // Disable IRP and queue failures before nuking the tree.
  2421. //
  2422. RemovalIrpFailEnabled = FALSE;
  2423. DeviceQueueFailEnabled = FALSE;
  2424. IoClearTestHook(IO_FAIL_QUEUE_DEVICE_WORK);
  2425. //
  2426. // Mark each one of the root device's children as detached.
  2427. //
  2428. CurrentEntry = RemovalDeviceTree->ChildListHead.Next;
  2429. while (CurrentEntry != &(RemovalDeviceTree->ChildListHead)) {
  2430. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2431. REMOVAL_DEVICE_ENTRY,
  2432. SiblingEntry);
  2433. DeviceRemovalDetachDevice(ChildEntry);
  2434. CurrentEntry = CurrentEntry->Next;
  2435. }
  2436. //
  2437. // Notify the root device that its device topology has changed.
  2438. //
  2439. IoNotifyDeviceTopologyChange((PDEVICE)RemovalDeviceTree->DeviceToken);
  2440. //
  2441. // Wait for the root's children to all receive removal IRPs. Destroy the
  2442. // test tracking tree for each child.
  2443. //
  2444. CurrentEntry = RemovalDeviceTree->ChildListHead.Next;
  2445. while (CurrentEntry != &(RemovalDeviceTree->ChildListHead)) {
  2446. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2447. REMOVAL_DEVICE_ENTRY,
  2448. SiblingEntry);
  2449. while (ChildEntry->RemovalIrp == FALSE) {
  2450. KeReleaseSpinLock(&DeviceTreeLock);
  2451. KeYield();
  2452. KeAcquireSpinLock(&DeviceTreeLock);
  2453. }
  2454. DeviceRemovalDestroyTree(ChildEntry);
  2455. CurrentEntry = CurrentEntry->Next;
  2456. }
  2457. KeReleaseSpinLock(&DeviceTreeLock);
  2458. return;
  2459. }
  2460. PREMOVAL_DEVICE_ENTRY
  2461. DeviceRemovalInitializeTreeForTest (
  2462. VOID
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. This routine initializes a tree for device removal testing. It attaches a
  2467. device to the root node, notifies the system, and then waits for the
  2468. children beneath the tree to be fully created.
  2469. Arguments:
  2470. None.
  2471. Return Value:
  2472. Returns the a pointer to the root device of the tree created, or NULL on
  2473. failure.
  2474. --*/
  2475. {
  2476. PREMOVAL_DEVICE_ENTRY TreeEntry;
  2477. //
  2478. // Add a tree of 1->2->4 beneath the root, notify the system, and wait
  2479. // until it is enumerated.
  2480. //
  2481. TreeEntry = DeviceRemovalAttachChildDevice(RootDevice);
  2482. if (TreeEntry == NULL) {
  2483. return NULL;
  2484. }
  2485. IoNotifyDeviceTopologyChange(RootDevice->TreeEntry->DeviceToken);
  2486. DeviceRemovalWaitForTreeCreation(TreeEntry);
  2487. return TreeEntry;
  2488. }
  2489. VOID
  2490. DeviceRemovalWaitForTreeCreation (
  2491. PREMOVAL_DEVICE_ENTRY RootEntry
  2492. )
  2493. /*++
  2494. Routine Description:
  2495. This routine waits for a device tree to be fully attached. It is used as a
  2496. blocking mechanism to wait for device enumeration to finish before testing.
  2497. It will yield the processor if the tree is not complete.
  2498. Arguments:
  2499. RootEntry - Supplies a pointer to the root of the device tree that needs
  2500. to be evaluated.
  2501. Return Value:
  2502. None.
  2503. --*/
  2504. {
  2505. ULONG ChildCount;
  2506. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2507. PLIST_ENTRY CurrentEntry;
  2508. PDEVICE Device;
  2509. //
  2510. // Wait for the device to hit the started state. If it does not, then exit.
  2511. //
  2512. Device = RootEntry->DeviceToken;
  2513. ObWaitOnObject(Device, 0, WAIT_TIME_INDEFINITE);
  2514. if (IoIsDeviceStarted(Device) == FALSE) {
  2515. return;
  2516. }
  2517. //
  2518. // The bus context should be filled by now.
  2519. //
  2520. ASSERT(RootEntry->BusContext != NULL);
  2521. //
  2522. // Now the child count should be filled in, exit if there are no children.
  2523. //
  2524. if (RootEntry->BusContext->ChildCount == 0) {
  2525. return;
  2526. }
  2527. //
  2528. // Wait for the children tree entries to appear.
  2529. //
  2530. do {
  2531. ChildCount = 0;
  2532. KeAcquireSpinLock(&DeviceTreeLock);
  2533. CurrentEntry = RootEntry->ChildListHead.Next;
  2534. while (CurrentEntry != &(RootEntry->ChildListHead)) {
  2535. ChildCount += 1;
  2536. CurrentEntry = CurrentEntry->Next;
  2537. }
  2538. KeReleaseSpinLock(&DeviceTreeLock);
  2539. KeYield();
  2540. } while (ChildCount != RootEntry->BusContext->ChildCount);
  2541. //
  2542. // Recurse on each child of this device.
  2543. //
  2544. CurrentEntry = RootEntry->ChildListHead.Next;
  2545. while (CurrentEntry != &(RootEntry->ChildListHead)) {
  2546. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2547. REMOVAL_DEVICE_ENTRY,
  2548. SiblingEntry);
  2549. DeviceRemovalWaitForTreeCreation(ChildEntry);
  2550. CurrentEntry = CurrentEntry->Next;
  2551. }
  2552. return;
  2553. }
  2554. VOID
  2555. DeviceRemovalDetachDevice (
  2556. PREMOVAL_DEVICE_ENTRY DeviceEntry
  2557. )
  2558. /*++
  2559. Routine Description:
  2560. This routine detachs a device from the system.
  2561. Arguments:
  2562. DeviceEntry - Supplies a pointer to the device that will be detached.
  2563. Return Value:
  2564. None.
  2565. --*/
  2566. {
  2567. ASSERT(DeviceEntry != NULL);
  2568. DeviceEntry->Attached = FALSE;
  2569. return;
  2570. }
  2571. PREMOVAL_DEVICE_ENTRY
  2572. DeviceRemovalAttachChildDevice (
  2573. PREMOVAL_DEVICE Device
  2574. )
  2575. /*++
  2576. Routine Description:
  2577. This routine attaches a child device to the given device.
  2578. Arguments:
  2579. Device - Supplies a pointer to the device to whom a child device will be
  2580. attached.
  2581. Return Value:
  2582. Returns the newly created child device, or NULL on failure.
  2583. --*/
  2584. {
  2585. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2586. KeAcquireSpinLock(&DeviceTreeLock);
  2587. ChildEntry = DeviceRemovalAttachChildDeviceHelper(Device);
  2588. KeReleaseSpinLock(&DeviceTreeLock);
  2589. return ChildEntry;
  2590. }
  2591. PREMOVAL_DEVICE_ENTRY
  2592. DeviceRemovalAttachChildDeviceHelper (
  2593. PREMOVAL_DEVICE Device
  2594. )
  2595. /*++
  2596. Routine Description:
  2597. This routine attaches a child device to the given device.
  2598. Arguments:
  2599. Device - Supplies a pointer to the device to whom a child device will be
  2600. attached.
  2601. Return Value:
  2602. Returns the newly created child device, or NULL on failure.
  2603. --*/
  2604. {
  2605. ULONG ChildCount;
  2606. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2607. ULONG ChildIndex;
  2608. CHAR ClassId[DEVR_CLASS_ID_SIZE];
  2609. PDEVICE *NewChildren;
  2610. PREMOVAL_DEVICE NewContext;
  2611. ULONG OldChildCount;
  2612. PDEVICE *OldChildren;
  2613. KSTATUS Status;
  2614. NewChildren = NULL;
  2615. NewContext = NULL;
  2616. ChildEntry = NULL;
  2617. //
  2618. // Allocate an array for child device pointers.
  2619. //
  2620. ChildCount = Device->ChildCount + 1;
  2621. NewChildren = MmAllocatePagedPool(sizeof(PDEVICE) * ChildCount,
  2622. DEVR_ALLOCATION_TAG);
  2623. if (NewChildren == NULL) {
  2624. Status = STATUS_INSUFFICIENT_RESOURCES;
  2625. goto AttachChildDeviceEnd;
  2626. }
  2627. //
  2628. // Copy the current childen to the new array.
  2629. //
  2630. ASSERT(((Device->ChildCount == 0) && (Device->Children == NULL)) ||
  2631. ((Device->ChildCount != 0) && (Device->Children != NULL)));
  2632. OldChildCount = Device->ChildCount;
  2633. RtlZeroMemory(NewChildren, sizeof(PDEVICE) * ChildCount);
  2634. for (ChildIndex = 0; ChildIndex < OldChildCount; ChildIndex += 1) {
  2635. NewChildren[ChildIndex] = Device->Children[ChildIndex];
  2636. }
  2637. OldChildren = Device->Children;
  2638. //
  2639. // Create the class ID for the children.
  2640. //
  2641. RtlPrintToString(ClassId,
  2642. DEVR_CLASS_ID_SIZE,
  2643. CharacterEncodingDefault,
  2644. DEVR_CLASS_ID_FORMAT,
  2645. (Device->Level + 1));
  2646. //
  2647. // Create a new device and track it in the global device tree.
  2648. //
  2649. NewContext = MmAllocateNonPagedPool(sizeof(REMOVAL_DEVICE),
  2650. DEVR_ALLOCATION_TAG);
  2651. if (NewContext == NULL) {
  2652. Status = STATUS_INSUFFICIENT_RESOURCES;
  2653. goto AttachChildDeviceEnd;
  2654. }
  2655. RtlAtomicAdd32(&FunctionDeviceCount, 1);
  2656. RtlZeroMemory(NewContext, sizeof(REMOVAL_DEVICE));
  2657. NewContext->Type = DeviceRemovalFunction;
  2658. NewContext->Root = FALSE;
  2659. //
  2660. // Create a tree entry for the child device and initialize it.
  2661. //
  2662. ChildEntry = DeviceRemovalCreateTreeEntry(NewContext,
  2663. Device->TreeEntry);
  2664. if (ChildEntry == NULL) {
  2665. Status = STATUS_INSUFFICIENT_RESOURCES;
  2666. goto AttachChildDeviceEnd;
  2667. }
  2668. //
  2669. // Create the child device and fill out the accounting structures.
  2670. //
  2671. Status = IoCreateDevice(DeviceRemovalDriver,
  2672. NewContext,
  2673. Device->TreeEntry->DeviceToken,
  2674. DEVR_CHILD_ID,
  2675. ClassId,
  2676. NULL,
  2677. &(NewChildren[ChildCount - 1]));
  2678. if (!KSUCCESS(Status)) {
  2679. RtlDebugPrint("IoCreateDevice failed with status %d.\n", Status);
  2680. goto AttachChildDeviceEnd;
  2681. }
  2682. ChildEntry->DeviceToken = NewChildren[ChildCount - 1];
  2683. //
  2684. // Update the devices children now that the routine will be successful.
  2685. //
  2686. Device->Children = NewChildren;
  2687. Device->ChildCount = ChildCount;
  2688. if (OldChildren != NULL) {
  2689. MmFreePagedPool(OldChildren);
  2690. }
  2691. AttachChildDeviceEnd:
  2692. if (!KSUCCESS(Status)) {
  2693. if (NewChildren != NULL) {
  2694. MmFreePagedPool(NewChildren);
  2695. }
  2696. if (NewContext != NULL) {
  2697. MmFreeNonPagedPool(NewContext);
  2698. RtlAtomicAdd32(&FunctionDeviceCount, (ULONG)-1);
  2699. }
  2700. if (ChildEntry != NULL) {
  2701. DeviceRemovalDeleteTreeEntry(ChildEntry);
  2702. }
  2703. }
  2704. return ChildEntry;
  2705. }
  2706. PREMOVAL_DEVICE_ENTRY
  2707. DeviceRemovalCreateTreeEntry (
  2708. PREMOVAL_DEVICE DeviceContext,
  2709. PREMOVAL_DEVICE_ENTRY ParentEntry
  2710. )
  2711. /*++
  2712. Routine Description:
  2713. This routine allocates and initializes a removal device tree entry.
  2714. Arguments:
  2715. DeviceContext - Supplies a pointer to one of two device contexts associated
  2716. with the tree entry.
  2717. ParentEntry - Supplies a pointer to the parent device tree entry.
  2718. Return Value:
  2719. Returns a pointer to the tree entry on success, or NULL on failure.
  2720. --*/
  2721. {
  2722. PREMOVAL_DEVICE_ENTRY DeviceEntry;
  2723. ASSERT(DeviceContext != NULL);
  2724. DeviceEntry = MmAllocatePagedPool(sizeof(REMOVAL_DEVICE_ENTRY),
  2725. DEVR_ALLOCATION_TAG);
  2726. if (DeviceEntry == NULL) {
  2727. return NULL;
  2728. }
  2729. RtlZeroMemory(DeviceEntry, sizeof(REMOVAL_DEVICE_ENTRY));
  2730. if (DeviceContext->Type == DeviceRemovalFunction) {
  2731. DeviceEntry->FunctionContext = DeviceContext;
  2732. } else {
  2733. DeviceEntry->BusContext = DeviceContext;
  2734. }
  2735. INITIALIZE_LIST_HEAD(&(DeviceEntry->ChildListHead));
  2736. if (ParentEntry == NULL) {
  2737. INITIALIZE_LIST_HEAD(&(DeviceEntry->SiblingEntry));
  2738. } else {
  2739. INSERT_AFTER(&(DeviceEntry->SiblingEntry),
  2740. &(ParentEntry->ChildListHead));
  2741. }
  2742. DeviceContext->TreeEntry = DeviceEntry;
  2743. DeviceEntry->Attached = TRUE;
  2744. DeviceEntry->RemovalIrp = FALSE;
  2745. RtlAtomicAdd32(&DeviceEntryCount, 1);
  2746. return DeviceEntry;
  2747. }
  2748. VOID
  2749. DeviceRemovalDeleteTreeEntry (
  2750. PREMOVAL_DEVICE_ENTRY Entry
  2751. )
  2752. /*++
  2753. Routine Description:
  2754. This routine removes and deletes a device tree entry.
  2755. Arguments:
  2756. Entry - Supplies a pointer to the tree entry to be deleted.
  2757. Return Value:
  2758. None.
  2759. --*/
  2760. {
  2761. LIST_REMOVE(&(Entry->SiblingEntry));
  2762. MmFreePagedPool(Entry);
  2763. RtlAtomicAdd32(&DeviceEntryCount, (ULONG)-1);
  2764. return;
  2765. }
  2766. PREMOVAL_DEVICE_ENTRY
  2767. DeviceRemovalFindChildByToken (
  2768. PREMOVAL_DEVICE_ENTRY Root,
  2769. PVOID DeviceToken
  2770. )
  2771. /*++
  2772. Routine Description:
  2773. This routine searches for a device underneath the supplied root.
  2774. Arguments:
  2775. Root - Supplies a pointer to the search's root device entry.
  2776. DeviceToken - Supplies an opaque token used to identify the device.
  2777. Return Value:
  2778. Returns a device entry upon success, NULL on failure.
  2779. --*/
  2780. {
  2781. PREMOVAL_DEVICE_ENTRY ChildEntry;
  2782. PLIST_ENTRY CurrentEntry;
  2783. PREMOVAL_DEVICE_ENTRY ResultEntry;
  2784. ASSERT(KeGetRunLevel() == RunLevelLow);
  2785. //
  2786. // In order to optimize the case where an immediate child is being sought,
  2787. // perform a breadth first search. Look at the root's children first.
  2788. //
  2789. CurrentEntry = Root->ChildListHead.Next;
  2790. while (CurrentEntry != &(Root->ChildListHead)) {
  2791. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2792. REMOVAL_DEVICE_ENTRY,
  2793. SiblingEntry);
  2794. //
  2795. // The token has to match and it cannot yet be removed. Device tokens
  2796. // get reused.
  2797. //
  2798. if ((ChildEntry->DeviceToken == DeviceToken) &&
  2799. (ChildEntry->RemovalIrp == FALSE)) {
  2800. return ChildEntry;
  2801. }
  2802. CurrentEntry = CurrentEntry->Next;
  2803. }
  2804. //
  2805. // Now recurse over each of the children.
  2806. //
  2807. CurrentEntry = Root->ChildListHead.Next;
  2808. while (CurrentEntry != &(Root->ChildListHead)) {
  2809. ChildEntry = (PREMOVAL_DEVICE_ENTRY)LIST_VALUE(CurrentEntry,
  2810. REMOVAL_DEVICE_ENTRY,
  2811. SiblingEntry);
  2812. ResultEntry = DeviceRemovalFindChildByToken(ChildEntry, DeviceToken);
  2813. if (ResultEntry != NULL) {
  2814. return ResultEntry;
  2815. }
  2816. CurrentEntry = CurrentEntry->Next;
  2817. }
  2818. //
  2819. // If nothing is found, then the device does not exist.
  2820. //
  2821. return NULL;
  2822. }
  2823. PREMOVAL_DEVICE_ENTRY
  2824. DeviceRemovalFindEntryByToken (
  2825. PVOID DeviceToken
  2826. )
  2827. /*++
  2828. Routine Description:
  2829. This routine searches for a device underneath the tree root.
  2830. Arguments:
  2831. Root - Supplies a pointer to the search's root device entry.
  2832. DeviceToken - Supplies an opaque token used to identify the device.
  2833. Return Value:
  2834. Returns a device entry upon success, NULL on failure.
  2835. --*/
  2836. {
  2837. PREMOVAL_DEVICE_ENTRY TreeEntry;
  2838. KeAcquireSpinLock(&DeviceTreeLock);
  2839. TreeEntry = DeviceRemovalFindChildByToken(RemovalDeviceTree, DeviceToken);
  2840. KeReleaseSpinLock(&DeviceTreeLock);
  2841. return TreeEntry;
  2842. }