fileobj.c 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. fileobj.c
  5. Abstract:
  6. This module implements support routines for working with file objects.
  7. Author:
  8. Evan Green 25-Apr-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "iop.h"
  17. #include "pagecach.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define FILE_OBJECT_ALLOCATION_TAG 0x624F6946 // 'bOiF'
  22. #define FILE_OBJECT_MAX_REFERENCE_COUNT 0x10000000
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. KSTATUS
  30. IopFlushFileObjectProperties (
  31. PFILE_OBJECT FileObject,
  32. ULONG Flags
  33. );
  34. COMPARISON_RESULT
  35. IopCompareFileObjectNodes (
  36. PRED_BLACK_TREE Tree,
  37. PRED_BLACK_TREE_NODE FirstNode,
  38. PRED_BLACK_TREE_NODE SecondNode
  39. );
  40. PFILE_OBJECT
  41. IopLookupFileObjectByProperties (
  42. PFILE_PROPERTIES Properties
  43. );
  44. VOID
  45. IopDestroyAsyncState (
  46. PIO_ASYNC_STATE Async
  47. );
  48. VOID
  49. IopSendIoSignal (
  50. PIO_ASYNC_STATE Async,
  51. ULONG Event
  52. );
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. //
  57. // Store the global tree of file objects.
  58. //
  59. RED_BLACK_TREE IoFileObjectsTree;
  60. //
  61. // Store the global list of dirty file objects.
  62. //
  63. LIST_ENTRY IoFileObjectsDirtyList;
  64. //
  65. // Store the lock synchronizing access to the dirty file objects list.
  66. //
  67. PQUEUED_LOCK IoFileObjectsDirtyListLock;
  68. //
  69. // Store the global list of orphaned file objects.
  70. //
  71. LIST_ENTRY IoFileObjectsOrphanedList;
  72. //
  73. // Store a queued lock that protects both the tree and the list.
  74. //
  75. PQUEUED_LOCK IoFileObjectsLock;
  76. //
  77. // Store a lock that can serialize flush operations.
  78. //
  79. PSHARED_EXCLUSIVE_LOCK IoFlushLock;
  80. //
  81. // ------------------------------------------------------------------ Functions
  82. //
  83. KERNEL_API
  84. VOID
  85. IoSetIoObjectState (
  86. PIO_OBJECT_STATE IoState,
  87. ULONG Events,
  88. BOOL Set
  89. )
  90. /*++
  91. Routine Description:
  92. This routine sets or clears one or more events in the I/O object state.
  93. Arguments:
  94. IoState - Supplies a pointer to the I/O object state to change.
  95. Events - Supplies a mask of poll events to change. See POLL_EVENT_*
  96. definitions.
  97. Set - Supplies a boolean indicating if the event(s) should be set (TRUE) or
  98. cleared (FALSE).
  99. Return Value:
  100. None.
  101. --*/
  102. {
  103. ULONG PreviousEvents;
  104. ULONG RisingEdge;
  105. SIGNAL_OPTION SignalOption;
  106. //
  107. // Prepare to signal the events. The events mask must be updated before an
  108. // event is signaled as it may immediately be read by a waiter.
  109. //
  110. if (Set != FALSE) {
  111. SignalOption = SignalOptionSignalAll;
  112. PreviousEvents = RtlAtomicOr32(&(IoState->Events), Events);
  113. } else {
  114. SignalOption = SignalOptionUnsignal;
  115. PreviousEvents = RtlAtomicAnd32(&(IoState->Events), ~Events);
  116. }
  117. if ((Events & POLL_EVENT_IN) != 0) {
  118. KeSignalEvent(IoState->ReadEvent, SignalOption);
  119. }
  120. if (((Events & POLL_EVENT_IN_HIGH_PRIORITY) != 0) &&
  121. (IoState->ReadHighPriorityEvent != NULL)) {
  122. KeSignalEvent(IoState->ReadHighPriorityEvent, SignalOption);
  123. }
  124. if ((Events & POLL_EVENT_OUT) != 0) {
  125. KeSignalEvent(IoState->WriteEvent, SignalOption);
  126. }
  127. if (((Events & POLL_EVENT_OUT_HIGH_PRIORITY) != 0) &&
  128. (IoState->WriteHighPriorityEvent != NULL)) {
  129. KeSignalEvent(IoState->WriteHighPriorityEvent, SignalOption);
  130. }
  131. if ((Events & POLL_ERROR_EVENTS) != 0) {
  132. KeSignalEvent(IoState->ErrorEvent, SignalOption);
  133. }
  134. //
  135. // If read or write just went high, potentially signal the owner.
  136. //
  137. if ((Set != FALSE) && (IoState->Async != NULL) &&
  138. (IoState->Async->Owner != 0)) {
  139. RisingEdge = (PreviousEvents ^ Events) & Events;
  140. if ((RisingEdge & (POLL_EVENT_IN | POLL_EVENT_OUT)) != 0) {
  141. IopSendIoSignal(IoState->Async, PreviousEvents | Events);
  142. }
  143. }
  144. return;
  145. }
  146. KERNEL_API
  147. KSTATUS
  148. IoWaitForIoObjectState (
  149. PIO_OBJECT_STATE IoState,
  150. ULONG Events,
  151. BOOL Interruptible,
  152. ULONG TimeoutInMilliseconds,
  153. PULONG ReturnedEvents
  154. )
  155. /*++
  156. Routine Description:
  157. This routine waits for the given events to trigger on the I/O object state.
  158. Arguments:
  159. IoState - Supplies a pointer to the I/O object state to wait on.
  160. Events - Supplies a mask of poll events to wait for. See POLL_EVENT_*
  161. definitions. Errors are non-maskable and will always be returned.
  162. Interruptible - Supplies a boolean indicating whether or not the wait can
  163. be interrupted if a signal is sent to the process on which this thread
  164. runs. If TRUE is supplied, the caller must check the return status
  165. code to find out if the wait was really satisfied or just interrupted.
  166. TimeoutInMilliseconds - Supplies the number of milliseconds that the given
  167. objects should be waited on before timing out. Use WAIT_TIME_INDEFINITE
  168. to wait forever on these objects.
  169. ReturnedEvents - Supplies an optional pointer where the poll events that
  170. satisfied the wait will be returned on success. If the wait was
  171. interrupted this will return 0.
  172. Return Value:
  173. Status code.
  174. --*/
  175. {
  176. ULONG ReturnEvents;
  177. KSTATUS Status;
  178. ULONG WaitFlags;
  179. PVOID WaitObjectArray[5];
  180. ULONG WaitObjectCount;
  181. if (ReturnedEvents != NULL) {
  182. *ReturnedEvents = 0;
  183. }
  184. WaitFlags = 0;
  185. if (Interruptible != FALSE) {
  186. WaitFlags |= WAIT_FLAG_INTERRUPTIBLE;
  187. }
  188. //
  189. // Always wait on the error state.
  190. //
  191. WaitObjectArray[0] = IoState->ErrorEvent;
  192. WaitObjectCount = 1;
  193. //
  194. // Determine which I/O state events to wait on.
  195. //
  196. if ((Events & POLL_EVENT_IN) != 0) {
  197. WaitObjectArray[WaitObjectCount] = IoState->ReadEvent;
  198. WaitObjectCount += 1;
  199. }
  200. if ((Events & POLL_EVENT_IN_HIGH_PRIORITY) != 0) {
  201. if (IoState->ReadHighPriorityEvent == NULL) {
  202. Status = STATUS_INVALID_PARAMETER;
  203. goto WaitForIoObjectStateEnd;
  204. }
  205. WaitObjectArray[WaitObjectCount] = IoState->ReadHighPriorityEvent;
  206. WaitObjectCount += 1;
  207. }
  208. if ((Events & POLL_EVENT_OUT) != 0) {
  209. WaitObjectArray[WaitObjectCount] = IoState->WriteEvent;
  210. WaitObjectCount += 1;
  211. }
  212. if ((Events & POLL_EVENT_OUT_HIGH_PRIORITY) != 0) {
  213. if (IoState->WriteHighPriorityEvent == NULL) {
  214. Status = STATUS_INVALID_PARAMETER;
  215. goto WaitForIoObjectStateEnd;
  216. }
  217. WaitObjectArray[WaitObjectCount] = IoState->WriteHighPriorityEvent;
  218. WaitObjectCount += 1;
  219. }
  220. //
  221. // Loop until the event flags agree with the wait.
  222. //
  223. while (TRUE) {
  224. Status = ObWaitOnObjects(WaitObjectArray,
  225. WaitObjectCount,
  226. WaitFlags,
  227. TimeoutInMilliseconds,
  228. NULL,
  229. NULL);
  230. if (!KSUCCESS(Status)) {
  231. goto WaitForIoObjectStateEnd;
  232. }
  233. ReturnEvents = IoState->Events & (Events | POLL_NONMASKABLE_EVENTS);
  234. //
  235. // The I/O object state maintains a bitmask of all the currently
  236. // signaled poll events. AND this with the requested events to get the
  237. // returned events for this descriptor.
  238. //
  239. if (ReturnedEvents != NULL) {
  240. *ReturnedEvents = ReturnEvents;
  241. }
  242. //
  243. // If there were no returned events, then the event fired but the flags
  244. // seem to be out of date. Go back and try again.
  245. //
  246. if (ReturnEvents != 0) {
  247. break;
  248. }
  249. }
  250. WaitForIoObjectStateEnd:
  251. return Status;
  252. }
  253. KERNEL_API
  254. PIO_OBJECT_STATE
  255. IoCreateIoObjectState (
  256. BOOL HighPriority
  257. )
  258. /*++
  259. Routine Description:
  260. This routine creates a new I/O object state structure with a reference
  261. count of one.
  262. Arguments:
  263. HighPriority - Supplies a boolean indicating whether or not the I/O object
  264. state should be prepared for high priority events.
  265. Return Value:
  266. Returns a pointer to the new state structure on success.
  267. NULL on allocation failure.
  268. --*/
  269. {
  270. PIO_OBJECT_STATE NewState;
  271. KSTATUS Status;
  272. //
  273. // Create the I/O state structure.
  274. //
  275. Status = STATUS_INSUFFICIENT_RESOURCES;
  276. NewState = MmAllocatePagedPool(sizeof(IO_OBJECT_STATE),
  277. FILE_OBJECT_ALLOCATION_TAG);
  278. if (NewState == NULL) {
  279. goto CreateIoObjectStateEnd;
  280. }
  281. RtlZeroMemory(NewState, sizeof(IO_OBJECT_STATE));
  282. //
  283. // Create the events and lock.
  284. //
  285. NewState->ReadEvent = KeCreateEvent(NULL);
  286. if (NewState->ReadEvent == NULL) {
  287. goto CreateIoObjectStateEnd;
  288. }
  289. NewState->WriteEvent = KeCreateEvent(NULL);
  290. if (NewState->WriteEvent == NULL) {
  291. goto CreateIoObjectStateEnd;
  292. }
  293. NewState->ErrorEvent = KeCreateEvent(NULL);
  294. if (NewState->ErrorEvent == NULL) {
  295. goto CreateIoObjectStateEnd;
  296. }
  297. if (HighPriority != FALSE) {
  298. NewState->ReadHighPriorityEvent = KeCreateEvent(NULL);
  299. if (NewState->ReadHighPriorityEvent == NULL) {
  300. goto CreateIoObjectStateEnd;
  301. }
  302. NewState->WriteHighPriorityEvent = KeCreateEvent(NULL);
  303. if (NewState->WriteHighPriorityEvent == NULL) {
  304. goto CreateIoObjectStateEnd;
  305. }
  306. }
  307. Status = STATUS_SUCCESS;
  308. CreateIoObjectStateEnd:
  309. if (!KSUCCESS(Status)) {
  310. if (NewState != NULL) {
  311. IoDestroyIoObjectState(NewState);
  312. NewState = NULL;
  313. }
  314. }
  315. return NewState;
  316. }
  317. KERNEL_API
  318. VOID
  319. IoDestroyIoObjectState (
  320. PIO_OBJECT_STATE State
  321. )
  322. /*++
  323. Routine Description:
  324. This routine destroys the given I/O object state.
  325. Arguments:
  326. State - Supplies a pointer to the I/O object state to destroy.
  327. Return Value:
  328. None.
  329. --*/
  330. {
  331. if (State->Async != NULL) {
  332. IopDestroyAsyncState(State->Async);
  333. }
  334. if (State->ReadEvent != NULL) {
  335. KeDestroyEvent(State->ReadEvent);
  336. }
  337. if (State->ReadHighPriorityEvent != NULL) {
  338. KeDestroyEvent(State->ReadHighPriorityEvent);
  339. }
  340. if (State->WriteEvent != NULL) {
  341. KeDestroyEvent(State->WriteEvent);
  342. }
  343. if (State->WriteHighPriorityEvent != NULL) {
  344. KeDestroyEvent(State->WriteHighPriorityEvent);
  345. }
  346. if (State->ErrorEvent != NULL) {
  347. KeDestroyEvent(State->ErrorEvent);
  348. }
  349. MmFreePagedPool(State);
  350. return;
  351. }
  352. PVOID
  353. IoReferenceFileObjectForHandle (
  354. PIO_HANDLE IoHandle
  355. )
  356. /*++
  357. Routine Description:
  358. This routine returns an opaque pointer to the file object opened by the
  359. given handle. It also adds a reference to the file object, which the caller
  360. is responsible for freeing.
  361. Arguments:
  362. IoHandle - Supplies a pointer to the I/O handle whose underlying file
  363. object should be referenced.
  364. Return Value:
  365. Returns an opaque pointer to the file object, with an incremented reference
  366. count. The caller is responsible for releasing this reference.
  367. --*/
  368. {
  369. PFILE_OBJECT FileObject;
  370. FileObject = IoHandle->FileObject;
  371. IopFileObjectAddReference(FileObject);
  372. return FileObject;
  373. }
  374. VOID
  375. IoFileObjectReleaseReference (
  376. PVOID FileObject
  377. )
  378. /*++
  379. Routine Description:
  380. This routine releases an external reference on a file object taken by
  381. referencing the file object for a handle.
  382. Arguments:
  383. FileObject - Supplies the opaque pointer to the file object.
  384. Return Value:
  385. None. The caller should not count on this pointer remaining unique after
  386. this call returns.
  387. --*/
  388. {
  389. KSTATUS Status;
  390. Status = IopFileObjectReleaseReference(FileObject);
  391. ASSERT(KSUCCESS(Status));
  392. return;
  393. }
  394. KSTATUS
  395. IoSetHandleAsynchronous (
  396. PIO_HANDLE IoHandle,
  397. HANDLE Descriptor,
  398. BOOL Asynchronous
  399. )
  400. /*++
  401. Routine Description:
  402. This routine enables or disables asynchronous mode for the given I/O
  403. handle.
  404. Arguments:
  405. IoHandle - Supplies a pointer to the I/O handle.
  406. Descriptor - Supplies the descriptor to associate with the asynchronous
  407. receiver state. This descriptor is passed to the signal information
  408. when an I/O signal occurs. Note that this descriptor may become stale
  409. if the handle is duped and the original closed, so the kernel should
  410. never access it.
  411. Asynchronous - Supplies a boolean indicating whether to set asynchronous
  412. mode (TRUE) or clear it (FALSE).
  413. Return Value:
  414. Status code.
  415. --*/
  416. {
  417. PIO_ASYNC_STATE AsyncState;
  418. PIO_OBJECT_STATE IoState;
  419. PKPROCESS Process;
  420. KSTATUS Status;
  421. IoState = IoHandle->FileObject->IoState;
  422. AsyncState = IopGetAsyncState(IoState);
  423. if (AsyncState == NULL) {
  424. return STATUS_INSUFFICIENT_RESOURCES;
  425. }
  426. KeAcquireQueuedLock(AsyncState->Lock);
  427. if (Asynchronous == FALSE) {
  428. if (IoHandle->Async != NULL) {
  429. if (IoHandle->Async->ListEntry.Next != NULL) {
  430. LIST_REMOVE(&(IoHandle->Async->ListEntry));
  431. IoHandle->Async->ListEntry.Next = NULL;
  432. }
  433. }
  434. IoHandle->OpenFlags &= ~OPEN_FLAG_ASYNCHRONOUS;
  435. //
  436. // Enable asynchronous mode.
  437. //
  438. } else {
  439. if (IoHandle->Async == NULL) {
  440. IoHandle->Async = MmAllocatePagedPool(sizeof(ASYNC_IO_RECEIVER),
  441. FILE_OBJECT_ALLOCATION_TAG);
  442. if (IoHandle->Async == NULL) {
  443. Status = STATUS_INSUFFICIENT_RESOURCES;
  444. goto SetHandleAsynchronousEnd;
  445. }
  446. RtlZeroMemory(IoHandle->Async, sizeof(ASYNC_IO_RECEIVER));
  447. }
  448. IoHandle->Async->Descriptor = Descriptor;
  449. if (IoHandle->Async->ListEntry.Next == NULL) {
  450. INSERT_BEFORE(&(IoHandle->Async->ListEntry),
  451. &(AsyncState->ReceiverList));
  452. }
  453. Process = PsGetCurrentProcess();
  454. IoHandle->Async->ProcessId = Process->Identifiers.ProcessId;
  455. IoHandle->OpenFlags |= OPEN_FLAG_ASYNCHRONOUS;
  456. }
  457. Status = STATUS_SUCCESS;
  458. SetHandleAsynchronousEnd:
  459. KeReleaseQueuedLock(AsyncState->Lock);
  460. return Status;;
  461. }
  462. KSTATUS
  463. IopInitializeFileObjectSupport (
  464. VOID
  465. )
  466. /*++
  467. Routine Description:
  468. This routine performs global initialization for file object support.
  469. Arguments:
  470. None.
  471. Return Value:
  472. Status code.
  473. --*/
  474. {
  475. RtlRedBlackTreeInitialize(&IoFileObjectsTree, 0, IopCompareFileObjectNodes);
  476. INITIALIZE_LIST_HEAD(&IoFileObjectsDirtyList);
  477. INITIALIZE_LIST_HEAD(&IoFileObjectsOrphanedList);
  478. IoFileObjectsLock = KeCreateQueuedLock();
  479. if (IoFileObjectsLock == NULL) {
  480. return STATUS_INSUFFICIENT_RESOURCES;
  481. }
  482. IoFileObjectsDirtyListLock = KeCreateQueuedLock();
  483. if (IoFileObjectsDirtyListLock == NULL) {
  484. return STATUS_INSUFFICIENT_RESOURCES;
  485. }
  486. IoFlushLock = KeCreateSharedExclusiveLock();
  487. if (IoFlushLock == NULL) {
  488. return STATUS_INSUFFICIENT_RESOURCES;
  489. }
  490. return STATUS_SUCCESS;
  491. }
  492. KSTATUS
  493. IopCreateOrLookupFileObject (
  494. PFILE_PROPERTIES Properties,
  495. PDEVICE Device,
  496. ULONG Flags,
  497. PFILE_OBJECT *FileObject,
  498. PBOOL ObjectCreated
  499. )
  500. /*++
  501. Routine Description:
  502. This routine attempts to look up a file object with the given properties
  503. (specifically the I-Node number and volume). If one does not exist, it
  504. is created and inserted in the global list. If a special file object is
  505. created, the ready event is left unsignaled so the remainder of the state
  506. can be created.
  507. Arguments:
  508. Properties - Supplies a pointer to the file object properties.
  509. Device - Supplies a pointer to the device that owns the file serial number.
  510. This may also be a volume or an object directory.
  511. Flags - Supplies a bitmask of file object flags. See FILE_OBJECT_FLAG_* for
  512. definitions.
  513. FileObject - Supplies a pointer where the file object will be returned on
  514. success.
  515. ObjectCreated - Supplies a pointer where a boolean will be returned
  516. indicating whether or not the object was just created. If it was just
  517. created, the caller is responsible for signaling the ready event when
  518. the object is fully set up.
  519. Return Value:
  520. Status code.
  521. --*/
  522. {
  523. BOOL Created;
  524. BOOL LockHeld;
  525. PFILE_OBJECT NewObject;
  526. PFILE_OBJECT Object;
  527. KSTATUS Status;
  528. ASSERT(Properties->DeviceId != 0);
  529. ASSERT(KeGetRunLevel() == RunLevelLow);
  530. Created = FALSE;
  531. LockHeld = FALSE;
  532. NewObject = NULL;
  533. Object = NULL;
  534. while (TRUE) {
  535. //
  536. // See if the file object already exists.
  537. //
  538. KeAcquireQueuedLock(IoFileObjectsLock);
  539. LockHeld = TRUE;
  540. Object = IopLookupFileObjectByProperties(Properties);
  541. if (Object == NULL) {
  542. //
  543. // There's no object, so drop the lock and go allocate one.
  544. //
  545. KeReleaseQueuedLock(IoFileObjectsLock);
  546. LockHeld = FALSE;
  547. if (NewObject == NULL) {
  548. NewObject = MmAllocatePagedPool(sizeof(FILE_OBJECT),
  549. FILE_OBJECT_ALLOCATION_TAG);
  550. if (NewObject == NULL) {
  551. Status = STATUS_INSUFFICIENT_RESOURCES;
  552. goto CreateOrLookupFileObjectEnd;
  553. }
  554. RtlZeroMemory(NewObject, sizeof(FILE_OBJECT));
  555. INITIALIZE_LIST_HEAD(&(NewObject->FileLockList));
  556. INITIALIZE_LIST_HEAD(&(NewObject->DirtyPageList));
  557. RtlRedBlackTreeInitialize(&(NewObject->PageCacheTree),
  558. 0,
  559. IopComparePageCacheEntries);
  560. NewObject->Lock = KeCreateSharedExclusiveLock();
  561. if (NewObject->Lock == NULL) {
  562. Status = STATUS_INSUFFICIENT_RESOURCES;
  563. goto CreateOrLookupFileObjectEnd;
  564. }
  565. if ((Flags & FILE_OBJECT_FLAG_EXTERNAL_IO_STATE) == 0) {
  566. NewObject->IoState = IoCreateIoObjectState(FALSE);
  567. if (NewObject->IoState == NULL) {
  568. Status = STATUS_INSUFFICIENT_RESOURCES;
  569. goto CreateOrLookupFileObjectEnd;
  570. }
  571. }
  572. NewObject->ReadyEvent = KeCreateEvent(NULL);
  573. if (NewObject->ReadyEvent == NULL) {
  574. Status = STATUS_INSUFFICIENT_RESOURCES;
  575. goto CreateOrLookupFileObjectEnd;
  576. }
  577. NewObject->Flags = Flags;
  578. NewObject->Device = Device;
  579. ObAddReference(Device);
  580. //
  581. // If the device is a special device, then more state needs to
  582. // be set up. Don't let additional lookups come in and use the
  583. // object before it's completely set up.
  584. //
  585. switch (Properties->Type) {
  586. case IoObjectPipe:
  587. case IoObjectSocket:
  588. case IoObjectTerminalMaster:
  589. case IoObjectTerminalSlave:
  590. case IoObjectSharedMemoryObject:
  591. break;
  592. default:
  593. KeSignalEvent(NewObject->ReadyEvent, SignalOptionSignalAll);
  594. break;
  595. }
  596. ASSERT(NewObject->ImageSectionList == NULL);
  597. //
  598. // Each file object starts with two references: one for the
  599. // caller, and one for being in the tree. When the reference
  600. // count reaches one, begin the process of flushing the file
  601. // object to disk. When that's done, it's removed from the
  602. // tree, and the second reference is released.
  603. //
  604. NewObject->ReferenceCount = 2;
  605. RtlCopyMemory(&(NewObject->Properties),
  606. Properties,
  607. sizeof(FILE_PROPERTIES));
  608. }
  609. //
  610. // It's time to insert it into the tree. Someone may have already
  611. // added this entry since the lock was dropped, so check once more.
  612. //
  613. KeAcquireQueuedLock(IoFileObjectsLock);
  614. LockHeld = TRUE;
  615. Object = IopLookupFileObjectByProperties(Properties);
  616. if (Object == NULL) {
  617. RtlRedBlackTreeInsert(&IoFileObjectsTree,
  618. &(NewObject->TreeEntry));
  619. ASSERT(NewObject->ListEntry.Next == NULL);
  620. Object = NewObject;
  621. NewObject = NULL;
  622. Created = TRUE;
  623. }
  624. }
  625. KeReleaseQueuedLock(IoFileObjectsLock);
  626. LockHeld = FALSE;
  627. //
  628. // If the object was created, it's the caller's responsibility to get it
  629. // ready, so don't wait on the event.
  630. //
  631. if (Created != FALSE) {
  632. break;
  633. }
  634. //
  635. // Wait on the file object to become ready.
  636. //
  637. KeWaitForEvent(Object->ReadyEvent, FALSE, WAIT_TIME_INDEFINITE);
  638. //
  639. // If the file object is closing, then it's too late. Release this
  640. // reference and try again.
  641. //
  642. if ((Object->Flags & FILE_OBJECT_FLAG_CLOSING) != 0) {
  643. IopFileObjectReleaseReference(Object);
  644. Object = NULL;
  645. continue;
  646. }
  647. break;
  648. }
  649. Status = STATUS_SUCCESS;
  650. ASSERT(Object->Device == Device);
  651. CreateOrLookupFileObjectEnd:
  652. if (LockHeld != FALSE) {
  653. KeReleaseQueuedLock(IoFileObjectsLock);
  654. }
  655. if (!KSUCCESS(Status)) {
  656. if (Object != NULL) {
  657. IopFileObjectReleaseReference(Object);
  658. Object = NULL;
  659. ASSERT(Object != NewObject);
  660. }
  661. }
  662. if (NewObject != NULL) {
  663. ASSERT(NewObject->ListEntry.Next == NULL);
  664. if (NewObject->Lock != NULL) {
  665. KeDestroySharedExclusiveLock(NewObject->Lock);
  666. }
  667. if (NewObject->IoState != NULL) {
  668. IoDestroyIoObjectState(NewObject->IoState);
  669. }
  670. if (NewObject->ReadyEvent != NULL) {
  671. KeDestroyEvent(NewObject->ReadyEvent);
  672. }
  673. ObReleaseReference(NewObject->Device);
  674. MmFreePagedPool(NewObject);
  675. }
  676. *FileObject = Object;
  677. if (ObjectCreated != NULL) {
  678. *ObjectCreated = Created;
  679. }
  680. return Status;
  681. }
  682. ULONG
  683. IopFileObjectAddReference (
  684. PFILE_OBJECT Object
  685. )
  686. /*++
  687. Routine Description:
  688. This routine increments the reference count on a file object.
  689. Arguments:
  690. Object - Supplies a pointer to the object to retain.
  691. Return Value:
  692. Returns the reference count before the addition.
  693. --*/
  694. {
  695. ULONG OldCount;
  696. OldCount = RtlAtomicAdd32(&(Object->ReferenceCount), 1);
  697. ASSERT((OldCount != 0) && (OldCount < FILE_OBJECT_MAX_REFERENCE_COUNT));
  698. return OldCount;
  699. }
  700. KSTATUS
  701. IopFileObjectReleaseReference (
  702. PFILE_OBJECT Object
  703. )
  704. /*++
  705. Routine Description:
  706. This routine decrements the reference count on a file object. If the
  707. reference count hits zero, then the file object will be destroyed.
  708. Arguments:
  709. Object - Supplies a pointer to the object to release.
  710. FailIfLastReference - Supplies a boolean that if set causes the reference
  711. count not to be decremented if this would involve releasing the very
  712. last reference on the file object. Callers that set this flag must be
  713. able to take responsibility for the reference they continue to own in
  714. the failure case. Set this to FALSE.
  715. Return Value:
  716. STATUS_SUCCESS on success.
  717. Other error codes on failure to write out the file properties to the file
  718. system or device.
  719. --*/
  720. {
  721. BOOL Cancelled;
  722. IRP_CLOSE CloseIrp;
  723. PDEVICE Device;
  724. IRP_MINOR_CODE MinorCode;
  725. ULONG OldCount;
  726. KSTATUS Status;
  727. Cancelled = FALSE;
  728. Status = STATUS_SUCCESS;
  729. //
  730. // Acquire the lock before decrementing the reference count. This is needed
  731. // to make the "decrement reference count, signal event, set closing"
  732. // operation atomic. If it weren't, people could increment the reference
  733. // count thinking the file object was good to use, and then this function
  734. // would close it down on them. It's assumed that people calling add
  735. // reference on the file object already had some other valid reference,
  736. // otherwise the global lock would have to be acquired in the add reference
  737. // routine as well.
  738. //
  739. KeAcquireQueuedLock(IoFileObjectsLock);
  740. OldCount = RtlAtomicAdd32(&(Object->ReferenceCount), -1);
  741. ASSERT((OldCount != 0) && (OldCount < FILE_OBJECT_MAX_REFERENCE_COUNT));
  742. //
  743. // If this is the second to last reference, then the only one left is the
  744. // internal one. Begin the cleanup process. Because it is the last
  745. // reference, modification of the file object's flags does not need to use
  746. // the atomic AND and OR operations.
  747. //
  748. if (OldCount == 2) {
  749. //
  750. // If someone else is already in the middle of closing, just roll on
  751. // through, releasing this reference.
  752. //
  753. if ((Object->Flags & FILE_OBJECT_FLAG_CLOSING) != 0) {
  754. KeReleaseQueuedLock(IoFileObjectsLock);
  755. goto FileObjectReleaseReferenceEnd;
  756. }
  757. //
  758. // Unsignal the ready event to pause anyone trying to open this file
  759. // object or delete lingering failed objects.
  760. //
  761. KeSignalEvent(Object->ReadyEvent, SignalOptionUnsignal);
  762. //
  763. // Mark the object as closing and make sure it isn't marked as failed.
  764. // This thread is about to take responsibility of the removal and will
  765. // do the right thing if removal fails.
  766. //
  767. Object->Flags |= FILE_OBJECT_FLAG_CLOSING;
  768. Object->Flags &= ~FILE_OBJECT_FLAG_CLOSE_FAILED;
  769. //
  770. // The file object should not be on the dirty list.
  771. //
  772. ASSERT(Object->ListEntry.Next == NULL);
  773. //
  774. // Release the file object lock.
  775. //
  776. // N.B. Do not reacquire the file object lock before signaling the
  777. // parties waiting on the ready event. Otherwise this might
  778. // deadlock with the failed file clean-up.
  779. //
  780. KeReleaseQueuedLock(IoFileObjectsLock);
  781. //
  782. // As dirty file objects sit on the dirty file object list with a
  783. // reference, only clean file object can make it this far.
  784. //
  785. ASSERT((Object->Properties.HardLinkCount == 0) ||
  786. ((Object->Flags & FILE_OBJECT_FLAG_DIRTY_PROPERTIES) == 0));
  787. //
  788. // The file object is being destroyed, now it is safe to notify the
  789. // driver that the the context is no longer needed. If the file object
  790. // fails to close and gets re-used, the next open path will open the
  791. // file object again.
  792. //
  793. if ((Object->Flags & FILE_OBJECT_FLAG_OPEN) != 0) {
  794. Device = Object->Device;
  795. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  796. CloseIrp.DeviceContext = Object->DeviceContext;
  797. Status = IopSendCloseIrp(Device, &CloseIrp);
  798. if (!KSUCCESS(Status) &&
  799. (Status != STATUS_DEVICE_NOT_CONNECTED)) {
  800. Object->Flags |= FILE_OBJECT_FLAG_CLOSE_FAILED;
  801. goto FileObjectReleaseReferenceEnd;
  802. }
  803. Object->DeviceContext = NULL;
  804. Object->Flags &= ~FILE_OBJECT_FLAG_OPEN;
  805. Status = STATUS_SUCCESS;
  806. }
  807. //
  808. // If the hard link count went to zero then delete the file object now
  809. // that the system can no longer reference it.
  810. //
  811. if (Object->Properties.HardLinkCount == 0) {
  812. MinorCode = IrpMinorSystemControlDelete;
  813. Status = IopSendFileOperationIrp(MinorCode, Object, NULL, 0);
  814. if (!KSUCCESS(Status) &&
  815. (Status != STATUS_DEVICE_NOT_CONNECTED)) {
  816. Object->Flags |= FILE_OBJECT_FLAG_CLOSE_FAILED;
  817. goto FileObjectReleaseReferenceEnd;
  818. }
  819. Status = STATUS_SUCCESS;
  820. }
  821. //
  822. // The file system is officially disengaged from this file object,
  823. // remove the file object from the global tree, allowing new callers to
  824. // recreate the file object.
  825. //
  826. KeAcquireQueuedLock(IoFileObjectsLock);
  827. RtlRedBlackTreeRemove(&IoFileObjectsTree, &(Object->TreeEntry));
  828. KeReleaseQueuedLock(IoFileObjectsLock);
  829. //
  830. // Now release everyone who got stuck while trying to open this closing
  831. // file object, so they can try again for a fresh version. Drop the
  832. // last reference. The failed file clean-up might also be waiting on
  833. // this event to check status.
  834. //
  835. KeSignalEvent(Object->ReadyEvent, SignalOptionSignalAll);
  836. IopFileObjectReleaseReference(Object);
  837. //
  838. // If this is the very last reference, then actually destroy the object.
  839. //
  840. } else if (OldCount == 1) {
  841. KeReleaseQueuedLock(IoFileObjectsLock);
  842. ASSERT(Object->ListEntry.Next == NULL);
  843. ASSERT((Object->Flags & FILE_OBJECT_FLAG_CLOSING) != 0);
  844. ASSERT(Object->PathEntryCount == 0);
  845. ASSERT(LIST_EMPTY(&(Object->FileLockList)) != FALSE);
  846. //
  847. // If this was an object manager object, release the reference on the
  848. // file. The only exception here is sockets, which are not official
  849. // object manager objects. They get destroyed differently.
  850. //
  851. if (Object->Properties.DeviceId == OBJECT_MANAGER_DEVICE_ID) {
  852. if (Object->Properties.Type != IoObjectSocket) {
  853. ObReleaseReference((PVOID)(UINTN)Object->Properties.FileId);
  854. }
  855. }
  856. if (Object->SpecialIo != NULL) {
  857. switch (Object->Properties.Type) {
  858. case IoObjectSocket:
  859. IoSocketReleaseReference(Object->SpecialIo);
  860. break;
  861. case IoObjectPipe:
  862. case IoObjectTerminalMaster:
  863. case IoObjectTerminalSlave:
  864. case IoObjectSharedMemoryObject:
  865. ObReleaseReference(Object->SpecialIo);
  866. break;
  867. default:
  868. ASSERT(FALSE);
  869. break;
  870. }
  871. }
  872. //
  873. // Release the reference on the device.
  874. //
  875. ObReleaseReference(Object->Device);
  876. if (Object->ImageSectionList != NULL) {
  877. MmDestroyImageSectionList(Object->ImageSectionList);
  878. }
  879. ASSERT(RED_BLACK_TREE_EMPTY(&(Object->PageCacheTree)));
  880. ASSERT(LIST_EMPTY(&(Object->DirtyPageList)));
  881. if (Object->Lock != NULL) {
  882. KeDestroySharedExclusiveLock(Object->Lock);
  883. }
  884. if (((Object->Flags & FILE_OBJECT_FLAG_EXTERNAL_IO_STATE) == 0) &&
  885. (Object->IoState != NULL)) {
  886. IoDestroyIoObjectState(Object->IoState);
  887. }
  888. if (Object->ReadyEvent != NULL) {
  889. KeDestroyEvent(Object->ReadyEvent);
  890. }
  891. if (Object->FileLockEvent != NULL) {
  892. KeDestroyEvent(Object->FileLockEvent);
  893. }
  894. MmFreePagedPool(Object);
  895. Object = NULL;
  896. //
  897. // This is not the last reference to this file in the system. Just release
  898. // the lock, and feel a little silly for holding it in the first place.
  899. //
  900. } else {
  901. KeReleaseQueuedLock(IoFileObjectsLock);
  902. }
  903. FileObjectReleaseReferenceEnd:
  904. //
  905. // This routine should only fail if the device fails to write or delete the
  906. // file object. Let anyone waiting on this file object know that it is
  907. // free to use.
  908. //
  909. if ((!KSUCCESS(Status)) && (Cancelled == FALSE)) {
  910. ASSERT((Object->Flags & FILE_OBJECT_FLAG_CLOSE_FAILED) != 0);
  911. ASSERT(Object->ListEntry.Next == NULL);
  912. //
  913. // If the object's reference count is still 1, add it to the list of
  914. // orphaned objects.
  915. //
  916. KeAcquireQueuedLock(IoFileObjectsLock);
  917. if (Object->ReferenceCount == 1) {
  918. INSERT_BEFORE(&(Object->ListEntry), &IoFileObjectsOrphanedList);
  919. }
  920. KeReleaseQueuedLock(IoFileObjectsLock);
  921. //
  922. // The signal event acts as a memory barrier still protecting this
  923. // non-atomic AND.
  924. //
  925. Object->Flags &= ~FILE_OBJECT_FLAG_CLOSING;
  926. KeSignalEvent(Object->ReadyEvent, SignalOptionSignalAll);
  927. }
  928. return Status;
  929. }
  930. VOID
  931. IopFileObjectAddPathEntryReference (
  932. PFILE_OBJECT FileObject
  933. )
  934. /*++
  935. Routine Description:
  936. This routine increments the path entry reference count on a file object.
  937. Arguments:
  938. FileObject - Supplies a pointer to a file object.
  939. Return Value:
  940. None.
  941. --*/
  942. {
  943. RtlAtomicAdd32(&(FileObject->PathEntryCount), 1);
  944. return;
  945. }
  946. VOID
  947. IopFileObjectReleasePathEntryReference (
  948. PFILE_OBJECT FileObject
  949. )
  950. /*++
  951. Routine Description:
  952. This routine decrements the path entry reference count on a file object.
  953. Arguments:
  954. FileObject - Supplies a pointer to a file object.
  955. Return Value:
  956. None.
  957. --*/
  958. {
  959. ULONG OldCount;
  960. OldCount = RtlAtomicAdd32(&(FileObject->PathEntryCount), (ULONG)-1);
  961. //
  962. // If this file object was deleted and this was the last path entry
  963. // reference then notify the page cache. It might want to evict the
  964. // entries.
  965. //
  966. if ((OldCount == 1) &&
  967. (FileObject->Properties.HardLinkCount == 0) &&
  968. (IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE)) {
  969. IopMarkFileObjectDirty(FileObject);
  970. }
  971. return;
  972. }
  973. KSTATUS
  974. IopFlushFileObject (
  975. PFILE_OBJECT FileObject,
  976. IO_OFFSET Offset,
  977. ULONGLONG Size,
  978. ULONG Flags,
  979. BOOL FlushExclusive,
  980. PUINTN PageCount
  981. )
  982. /*++
  983. Routine Description:
  984. This routine flushes all file object data to the next lowest cache layer.
  985. If the flags request synchronized I/O, then all file data and meta-data
  986. will be flushed to the backing media.
  987. Arguments:
  988. FileObject - Supplies a pointer to a file object for the device or file.
  989. Offset - Supplies the offset from the beginning of the file or device where
  990. the flush should be done.
  991. Size - Supplies the size, in bytes, of the region to flush. Supply a value
  992. of -1 to flush from the given offset to the end of the file.
  993. Flags - Supplies a bitmask of I/O flags. See IO_FLAG_* for definitions.
  994. FlushExclusive - Supplies a boolean indicating if this was an explicit
  995. flush. If so, then the flush lock is acquired exclusively to prevent
  996. partial flushes due to dirty page cache entries being on a local list.
  997. PageCount - Supplies an optional pointer describing how many pages to flush.
  998. On output this value will be decreased by the number of pages actually
  999. flushed. Supply NULL to flush all pages in the size range.
  1000. Return Value:
  1001. Status code.
  1002. --*/
  1003. {
  1004. ULONG ClearFlags;
  1005. BOOL Exclusive;
  1006. KSTATUS Status;
  1007. if (FlushExclusive != FALSE) {
  1008. KeAcquireSharedExclusiveLockExclusive(IoFlushLock);
  1009. } else {
  1010. KeAcquireSharedExclusiveLockShared(IoFlushLock);
  1011. }
  1012. Exclusive = FALSE;
  1013. KeAcquireSharedExclusiveLockShared(FileObject->Lock);
  1014. if ((FileObject->Properties.HardLinkCount == 0) &&
  1015. (FileObject->PathEntryCount == 0)) {
  1016. KeSharedExclusiveLockConvertToExclusive(FileObject->Lock);
  1017. Exclusive = TRUE;
  1018. IopEvictPageCacheEntries(FileObject,
  1019. 0,
  1020. PAGE_CACHE_EVICTION_FLAG_REMOVE);
  1021. ClearFlags = FILE_OBJECT_FLAG_DIRTY_PROPERTIES |
  1022. FILE_OBJECT_FLAG_DIRTY_DATA;
  1023. RtlAtomicAnd32(&(FileObject->Flags), ~ClearFlags);
  1024. } else {
  1025. Status = IopFlushPageCacheEntries(FileObject,
  1026. Offset,
  1027. Size,
  1028. Flags,
  1029. PageCount);
  1030. if (!KSUCCESS(Status)) {
  1031. goto FlushFileObjectEnd;
  1032. }
  1033. Status = IopFlushFileObjectProperties(FileObject, Flags);
  1034. if (!KSUCCESS(Status)) {
  1035. goto FlushFileObjectEnd;
  1036. }
  1037. }
  1038. Status = STATUS_SUCCESS;
  1039. FlushFileObjectEnd:
  1040. if (Exclusive != FALSE) {
  1041. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1042. } else {
  1043. KeReleaseSharedExclusiveLockShared(FileObject->Lock);
  1044. }
  1045. if (FlushExclusive != FALSE) {
  1046. KeReleaseSharedExclusiveLockExclusive(IoFlushLock);
  1047. } else {
  1048. KeReleaseSharedExclusiveLockShared(IoFlushLock);
  1049. }
  1050. return Status;
  1051. }
  1052. KSTATUS
  1053. IopFlushFileObjects (
  1054. DEVICE_ID DeviceId,
  1055. ULONG Flags,
  1056. PUINTN PageCount
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine iterates over file objects in the global dirty file objects
  1061. list, flushing each one that belongs to the given device or to all entries
  1062. if a device ID of 0 is specified.
  1063. Arguments:
  1064. DeviceId - Supplies an optional device ID filter. Supply 0 to iterate over
  1065. dirty file objects for all devices.
  1066. Flags - Supplies a bitmask of I/O flags. See IO_FLAG_* for definitions.
  1067. PageCount - Supplies an optional pointer describing how many pages to flush.
  1068. On output this value will be decreased by the number of pages actually
  1069. flushed. Supply NULL to flush all pages.
  1070. Return Value:
  1071. STATUS_SUCCESS if all file object were successfully iterated.
  1072. STATUS_TRY_AGAIN if the iteration quit early for some reason (i.e. the page
  1073. cache was found to be too dirty when flushing file objects).
  1074. Other status codes for other errors.
  1075. --*/
  1076. {
  1077. PLIST_ENTRY CurrentEntry;
  1078. PFILE_OBJECT CurrentObject;
  1079. ULONG FlushCount;
  1080. BOOL FlushExclusive;
  1081. ULONG FlushIndex;
  1082. PFILE_OBJECT NextObject;
  1083. KSTATUS Status;
  1084. KSTATUS TotalStatus;
  1085. CurrentObject = NULL;
  1086. TotalStatus = STATUS_SUCCESS;
  1087. //
  1088. // Synchronized flushes need to guarantee that all the data is out to disk
  1089. // before returning.
  1090. //
  1091. FlushCount = 1;
  1092. FlushExclusive = FALSE;
  1093. if ((Flags & IO_FLAG_DATA_SYNCHRONIZED) != 0) {
  1094. FlushExclusive = TRUE;
  1095. //
  1096. // If the goal is to flush the entire cache, then don't actually
  1097. // perform the flush synchronized. Just loop twice so that the first
  1098. // round gets all dirty data from the upper layers to the disk layer
  1099. // and the second loop will flush it to disk. This allows for larger,
  1100. // faster writes to disk.
  1101. //
  1102. if (DeviceId == 0) {
  1103. Flags &= ~(IO_FLAG_DATA_SYNCHRONIZED |
  1104. IO_FLAG_METADATA_SYNCHRONIZED);
  1105. FlushCount = 2;
  1106. }
  1107. //
  1108. // Non-synchronized flushes that encounter an empty list can just exit. Any
  1109. // necessary work is already being done. But if a specific device is
  1110. // supplied acquire the lock to make sure any other thread has finished
  1111. // flushing the device's data.
  1112. //
  1113. } else if ((DeviceId == 0) &&
  1114. (LIST_EMPTY(&IoFileObjectsDirtyList) != FALSE)) {
  1115. return STATUS_SUCCESS;
  1116. }
  1117. //
  1118. // Now make several attempts at performing the requested clean operation.
  1119. //
  1120. Status = STATUS_SUCCESS;
  1121. for (FlushIndex = 0; FlushIndex < FlushCount; FlushIndex += 1) {
  1122. //
  1123. // Get the first entry on the list, or the specific device in question.
  1124. //
  1125. KeAcquireQueuedLock(IoFileObjectsDirtyListLock);
  1126. CurrentEntry = IoFileObjectsDirtyList.Next;
  1127. if (DeviceId == 0) {
  1128. CurrentObject = LIST_VALUE(CurrentEntry, FILE_OBJECT, ListEntry);
  1129. } else {
  1130. while (CurrentEntry != &IoFileObjectsDirtyList) {
  1131. CurrentObject = LIST_VALUE(CurrentEntry,
  1132. FILE_OBJECT,
  1133. ListEntry);
  1134. if (CurrentObject->Properties.DeviceId == DeviceId) {
  1135. break;
  1136. }
  1137. CurrentEntry = CurrentEntry->Next;
  1138. }
  1139. }
  1140. if (CurrentEntry == &IoFileObjectsDirtyList) {
  1141. CurrentObject = NULL;
  1142. } else {
  1143. IopFileObjectAddReference(CurrentObject);
  1144. }
  1145. KeReleaseQueuedLock(IoFileObjectsDirtyListLock);
  1146. if ((CurrentObject == NULL) && (DeviceId != 0)) {
  1147. TotalStatus = STATUS_NO_SUCH_DEVICE;
  1148. break;
  1149. }
  1150. //
  1151. // Loop cleaning file objects.
  1152. //
  1153. while (CurrentObject != NULL) {
  1154. Status = IopFlushFileObject(CurrentObject,
  1155. 0,
  1156. -1,
  1157. Flags,
  1158. FlushExclusive,
  1159. PageCount);
  1160. if (!KSUCCESS(Status)) {
  1161. if (KSUCCESS(TotalStatus)) {
  1162. TotalStatus = Status;
  1163. }
  1164. }
  1165. if ((DeviceId != 0) || ((PageCount != NULL) && (*PageCount == 0))) {
  1166. break;
  1167. }
  1168. //
  1169. // Re-lock the list, and get the next object.
  1170. //
  1171. KeAcquireQueuedLock(IoFileObjectsDirtyListLock);
  1172. NextObject = NULL;
  1173. if (DeviceId == 0) {
  1174. if (CurrentObject->ListEntry.Next != NULL) {
  1175. CurrentEntry = CurrentObject->ListEntry.Next;
  1176. } else {
  1177. CurrentEntry = IoFileObjectsDirtyList.Next;
  1178. }
  1179. if (CurrentEntry != &IoFileObjectsDirtyList) {
  1180. NextObject = LIST_VALUE(CurrentEntry,
  1181. FILE_OBJECT,
  1182. ListEntry);
  1183. }
  1184. }
  1185. //
  1186. // Remove the file object from the list if it is clean now.
  1187. //
  1188. if (IS_FILE_OBJECT_CLEAN(CurrentObject)) {
  1189. if (CurrentObject->ListEntry.Next != NULL) {
  1190. LIST_REMOVE(&(CurrentObject->ListEntry));
  1191. CurrentObject->ListEntry.Next = NULL;
  1192. IopFileObjectReleaseReference(CurrentObject);
  1193. }
  1194. }
  1195. if (NextObject != NULL) {
  1196. IopFileObjectAddReference(NextObject);
  1197. }
  1198. KeReleaseQueuedLock(IoFileObjectsDirtyListLock);
  1199. IopFileObjectReleaseReference(CurrentObject);
  1200. CurrentObject = NextObject;
  1201. }
  1202. }
  1203. return TotalStatus;
  1204. }
  1205. VOID
  1206. IopEvictFileObjects (
  1207. DEVICE_ID DeviceId,
  1208. ULONG Flags
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine iterates over all file objects evicting page cache entries for
  1213. each one that belongs to the given device.
  1214. Arguments:
  1215. DeviceId - Supplies an optional device ID filter. Supply 0 to iterate over
  1216. file objects for all devices.
  1217. Flags - Supplies a bitmask of eviction flags. See
  1218. PAGE_CACHE_EVICTION_FLAG_* for definitions.
  1219. Return Value:
  1220. None.
  1221. --*/
  1222. {
  1223. PFILE_OBJECT CurrentObject;
  1224. PRED_BLACK_TREE_NODE Node;
  1225. PFILE_OBJECT ReleaseObject;
  1226. ASSERT(DeviceId != 0);
  1227. ReleaseObject = NULL;
  1228. //
  1229. // Grab the global file objects lock and iterate over the file objects that
  1230. // belong to the given device.
  1231. //
  1232. KeAcquireQueuedLock(IoFileObjectsLock);
  1233. Node = RtlRedBlackTreeGetLowestNode(&IoFileObjectsTree);
  1234. while (Node != NULL) {
  1235. CurrentObject = RED_BLACK_TREE_VALUE(Node, FILE_OBJECT, TreeEntry);
  1236. //
  1237. // Skip file objects that do not match the device ID. Also skip any
  1238. // file objects that only have 1 reference. This means that they are
  1239. // about to get removed from the tree if close/delete are successful.
  1240. // As such, they don't have any page cache entries, as a page cache
  1241. // entry takes a reference on the file object.
  1242. //
  1243. if ((CurrentObject->Properties.DeviceId != DeviceId) ||
  1244. (CurrentObject->ReferenceCount == 1)) {
  1245. Node = RtlRedBlackTreeGetNextNode(&(IoFileObjectsTree),
  1246. FALSE,
  1247. Node);
  1248. CurrentObject = NULL;
  1249. continue;
  1250. }
  1251. //
  1252. // Take a reference on this object so it does not disappear when the
  1253. // lock is released.
  1254. //
  1255. IopFileObjectAddReference(CurrentObject);
  1256. KeReleaseQueuedLock(IoFileObjectsLock);
  1257. KeAcquireSharedExclusiveLockExclusive(CurrentObject->Lock);
  1258. //
  1259. // Call the eviction routine for the current file object.
  1260. //
  1261. IopEvictPageCacheEntries(CurrentObject, 0, Flags);
  1262. //
  1263. // Release the reference taken on the release object.
  1264. //
  1265. if (ReleaseObject != NULL) {
  1266. ASSERT(ReleaseObject->ReferenceCount >= 2);
  1267. IopFileObjectReleaseReference(ReleaseObject);
  1268. ReleaseObject = NULL;
  1269. }
  1270. KeReleaseSharedExclusiveLockExclusive(CurrentObject->Lock);
  1271. KeAcquireQueuedLock(IoFileObjectsLock);
  1272. //
  1273. // The current object and node should match.
  1274. //
  1275. ASSERT(&(CurrentObject->TreeEntry) == Node);
  1276. Node = RtlRedBlackTreeGetNextNode(&(IoFileObjectsTree),
  1277. FALSE,
  1278. Node);
  1279. ReleaseObject = CurrentObject;
  1280. CurrentObject = NULL;
  1281. }
  1282. KeReleaseQueuedLock(IoFileObjectsLock);
  1283. //
  1284. // Release any lingering references.
  1285. //
  1286. if (ReleaseObject != NULL) {
  1287. ASSERT(ReleaseObject->ReferenceCount >= 2);
  1288. IopFileObjectReleaseReference(ReleaseObject);
  1289. }
  1290. if (CurrentObject != NULL) {
  1291. ASSERT(ReleaseObject->ReferenceCount >= 2);
  1292. IopFileObjectReleaseReference(CurrentObject);
  1293. }
  1294. return;
  1295. }
  1296. VOID
  1297. IopUpdateFileObjectTime (
  1298. PFILE_OBJECT FileObject,
  1299. FILE_OBJECT_TIME_TYPE TimeType
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. This routine updates the given file object's access and modified times. The
  1304. latter is only updated upon request.
  1305. Arguments:
  1306. FileObject - Supplies a pointer to a file object.
  1307. TimeType - Supplies the type of time to update. Updating modified time also
  1308. updates status change time.
  1309. Return Value:
  1310. None.
  1311. --*/
  1312. {
  1313. SYSTEM_TIME CurrentTime;
  1314. ASSERT(KeIsSharedExclusiveLockHeldExclusive(FileObject->Lock));
  1315. KeGetSystemTime(&CurrentTime);
  1316. if (TimeType == FileObjectAccessTime) {
  1317. FileObject->Properties.AccessTime = CurrentTime;
  1318. } else if (TimeType == FileObjectModifiedTime) {
  1319. FileObject->Properties.ModifiedTime = CurrentTime;
  1320. FileObject->Properties.StatusChangeTime = CurrentTime;
  1321. } else if (TimeType == FileObjectStatusTime) {
  1322. FileObject->Properties.StatusChangeTime = CurrentTime;
  1323. } else {
  1324. ASSERT(FALSE);
  1325. }
  1326. IopMarkFileObjectPropertiesDirty(FileObject);
  1327. return;
  1328. }
  1329. VOID
  1330. IopUpdateFileObjectFileSize (
  1331. PFILE_OBJECT FileObject,
  1332. ULONGLONG NewSize
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This routine will make sure the file object file size is at least the
  1337. given size. If it is not, it will be set to the given size. If it is, no
  1338. change will be performed. Use the modify file object size function to
  1339. forcibly set a new size (eg for truncate).
  1340. Arguments:
  1341. FileObject - Supplies a pointer to a file object.
  1342. NewSize - Supplies the new file size.
  1343. Return Value:
  1344. None.
  1345. --*/
  1346. {
  1347. ULONG BlockSize;
  1348. ULONGLONG FileSize;
  1349. BOOL Updated;
  1350. Updated = FALSE;
  1351. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
  1352. if (FileSize < NewSize) {
  1353. ASSERT(KeIsSharedExclusiveLockHeldExclusive(FileObject->Lock));
  1354. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
  1355. if (FileSize < NewSize) {
  1356. WRITE_INT64_SYNC(&(FileObject->Properties.FileSize), NewSize);
  1357. //
  1358. // TODO: Block count should be managed by the file system.
  1359. //
  1360. BlockSize = FileObject->Properties.BlockSize;
  1361. FileObject->Properties.BlockCount =
  1362. ALIGN_RANGE_UP(NewSize, BlockSize) / BlockSize;
  1363. Updated = TRUE;
  1364. }
  1365. }
  1366. if (Updated != FALSE) {
  1367. IopMarkFileObjectPropertiesDirty(FileObject);
  1368. }
  1369. return;
  1370. }
  1371. KSTATUS
  1372. IopModifyFileObjectSize (
  1373. PFILE_OBJECT FileObject,
  1374. PVOID DeviceContext,
  1375. ULONGLONG NewFileSize
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. This routine modifies the given file object's size. It will either increase
  1380. or decrease the file size. If the size is decreased then the file object's
  1381. driver will be notified, any existing page cache entries for the file will
  1382. be evicted and any image sections that map the file will be unmapped.
  1383. Arguments:
  1384. FileObject - Supplies a pointer to the file object whose size will be
  1385. modified.
  1386. DeviceContext - Supplies an optional pointer to the device context to use
  1387. when doing file operations. Not every file object has a built-in device
  1388. context.
  1389. NewFileSize - Supplies the desired new size of the file object.
  1390. Return Value:
  1391. Status code.
  1392. --*/
  1393. {
  1394. ULONG BlockSize;
  1395. ULONG EvictionFlags;
  1396. IO_OFFSET EvictionOffset;
  1397. ULONGLONG FileSize;
  1398. ULONG PageSize;
  1399. SYSTEM_CONTROL_TRUNCATE Request;
  1400. KSTATUS Status;
  1401. IO_OFFSET UnmapOffset;
  1402. ULONGLONG UnmapSize;
  1403. KeAcquireSharedExclusiveLockExclusive(FileObject->Lock);
  1404. //
  1405. // If the new size is the same as the old file size then just exit.
  1406. //
  1407. READ_INT64_SYNC(&(FileObject->Properties.FileSize), &FileSize);
  1408. if (FileSize == NewFileSize) {
  1409. Status = STATUS_SUCCESS;
  1410. goto ModifyFileObjectSizeEnd;
  1411. }
  1412. BlockSize = FileObject->Properties.BlockSize;
  1413. //
  1414. // TODO: Block size should be managed by the file system.
  1415. //
  1416. FileObject->Properties.BlockCount =
  1417. ALIGN_RANGE_UP(NewFileSize, BlockSize) / BlockSize;
  1418. //
  1419. // If this is a shared memory object, then handle that separately.
  1420. //
  1421. if (FileObject->Properties.Type == IoObjectSharedMemoryObject) {
  1422. Status = IopTruncateSharedMemoryObject(FileObject, NewFileSize);
  1423. //
  1424. // Otherwise call the driver to truncate the file or device. The
  1425. // driver will check the file size and truncate the file down to
  1426. // the new size.
  1427. //
  1428. } else {
  1429. if (DeviceContext == NULL) {
  1430. DeviceContext = FileObject->DeviceContext;
  1431. }
  1432. Request.FileProperties = &(FileObject->Properties);
  1433. Request.DeviceContext = DeviceContext;
  1434. Request.NewSize = NewFileSize;
  1435. Status = IopSendSystemControlIrp(FileObject->Device,
  1436. IrpMinorSystemControlTruncate,
  1437. &Request);
  1438. }
  1439. IopMarkFileObjectPropertiesDirty(FileObject);
  1440. if (!KSUCCESS(Status)) {
  1441. goto ModifyFileObjectSizeEnd;
  1442. }
  1443. //
  1444. // If the new size is less than the current size, then work needs to be
  1445. // done to make sure the system isn't using any of the truncated data.
  1446. //
  1447. if (NewFileSize < FileSize) {
  1448. //
  1449. // Unmap all image sections that might have mapped portions of this
  1450. // file.
  1451. //
  1452. if (FileObject->ImageSectionList != NULL) {
  1453. PageSize = MmPageSize();
  1454. UnmapOffset = ALIGN_RANGE_UP(NewFileSize, PageSize);
  1455. UnmapSize = ALIGN_RANGE_UP((FileSize - UnmapOffset), PageSize);
  1456. MmUnmapImageSectionList(FileObject->ImageSectionList,
  1457. UnmapOffset,
  1458. UnmapSize,
  1459. IMAGE_SECTION_UNMAP_FLAG_TRUNCATE,
  1460. NULL);
  1461. }
  1462. //
  1463. // Evict all full page cache entries beyond the new file size for this
  1464. // file object if it is cacheable.
  1465. //
  1466. if (IO_IS_FILE_OBJECT_CACHEABLE(FileObject) != FALSE) {
  1467. EvictionFlags = PAGE_CACHE_EVICTION_FLAG_TRUNCATE;
  1468. EvictionOffset = ALIGN_RANGE_UP(NewFileSize,
  1469. IoGetCacheEntryDataSize());
  1470. IopEvictPageCacheEntries(FileObject, EvictionOffset, EvictionFlags);
  1471. }
  1472. }
  1473. ModifyFileObjectSizeEnd:
  1474. //
  1475. // Release the lock if it exists.
  1476. //
  1477. KeReleaseSharedExclusiveLockExclusive(FileObject->Lock);
  1478. return Status;
  1479. }
  1480. VOID
  1481. IopFileObjectIncrementHardLinkCount (
  1482. PFILE_OBJECT FileObject
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. This routine decrements the hard link count for a file object.
  1487. Arguments:
  1488. FileObject - Supplies a pointer to a file object.
  1489. Return Value:
  1490. None.
  1491. --*/
  1492. {
  1493. FileObject->Properties.HardLinkCount += 1;
  1494. IopUpdateFileObjectTime(FileObject, FileObjectStatusTime);
  1495. return;
  1496. }
  1497. VOID
  1498. IopFileObjectDecrementHardLinkCount (
  1499. PFILE_OBJECT FileObject
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This routine decrements the hard link count for a file object.
  1504. Arguments:
  1505. FileObject - Supplies a pointer to a file object.
  1506. Return Value:
  1507. None.
  1508. --*/
  1509. {
  1510. ASSERT(FileObject->Properties.HardLinkCount != 0);
  1511. FileObject->Properties.HardLinkCount -= 1;
  1512. IopUpdateFileObjectTime(FileObject, FileObjectStatusTime);
  1513. return;
  1514. }
  1515. VOID
  1516. IopCleanupFileObjects (
  1517. VOID
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. This routine releases any lingering file objects that were left around as a
  1522. result of I/O failures during the orignal release attempt.
  1523. Arguments:
  1524. None.
  1525. Return Value:
  1526. None.
  1527. --*/
  1528. {
  1529. PFILE_OBJECT CurrentObject;
  1530. LIST_ENTRY LocalList;
  1531. //
  1532. // Exit immediately if there are no orphaned file objects.
  1533. //
  1534. if (LIST_EMPTY(&IoFileObjectsOrphanedList) != FALSE) {
  1535. return;
  1536. }
  1537. //
  1538. // Grab the global file objects lock, migrate the global orphaned file
  1539. // object list to a local list head and iterate over it. All objects on the
  1540. // list should have only 1 reference. If another thread resurrects any
  1541. // object during iteration, it will remove it from the local list and this
  1542. // routine will not see it. For those file objects processed, just add an
  1543. // extra reference with the lock held and release it with the lock released.
  1544. // This should kick off another attempt at closing out the file object.
  1545. //
  1546. INITIALIZE_LIST_HEAD(&LocalList);
  1547. KeAcquireQueuedLock(IoFileObjectsLock);
  1548. MOVE_LIST(&IoFileObjectsOrphanedList, &LocalList);
  1549. INITIALIZE_LIST_HEAD(&IoFileObjectsOrphanedList);
  1550. while (LIST_EMPTY(&LocalList) == FALSE) {
  1551. CurrentObject = LIST_VALUE(LocalList.Next, FILE_OBJECT, ListEntry);
  1552. LIST_REMOVE(&(CurrentObject->ListEntry));
  1553. CurrentObject->ListEntry.Next = NULL;
  1554. ASSERT(CurrentObject->ReferenceCount == 1);
  1555. IopFileObjectAddReference(CurrentObject);
  1556. KeReleaseQueuedLock(IoFileObjectsLock);
  1557. IopFileObjectReleaseReference(CurrentObject);
  1558. KeAcquireQueuedLock(IoFileObjectsLock);
  1559. }
  1560. KeReleaseQueuedLock(IoFileObjectsLock);
  1561. return;
  1562. }
  1563. VOID
  1564. IopAcquireFileObjectLocksExclusive (
  1565. PFILE_OBJECT Object1,
  1566. PFILE_OBJECT Object2
  1567. )
  1568. /*++
  1569. Routine Description:
  1570. This routine acquires two file object locks exclusive in the right order.
  1571. The order is to sort first by file object type, then by file object pointer.
  1572. Arguments:
  1573. Object1 - Supplies a pointer to the first file object.
  1574. Object2 - Supplies a pointer to the second file object.
  1575. Return Value:
  1576. None.
  1577. --*/
  1578. {
  1579. PFILE_OBJECT Swap;
  1580. if (Object1 == Object2) {
  1581. KeAcquireSharedExclusiveLockExclusive(Object1->Lock);
  1582. return;
  1583. }
  1584. //
  1585. // If the types are in the wrong order, swap them.
  1586. //
  1587. if (Object1->Properties.Type > Object2->Properties.Type) {
  1588. Swap = Object1;
  1589. Object1 = Object2;
  1590. Object2 = Swap;
  1591. //
  1592. // Otherwise, if they're equal, compare pointers.
  1593. //
  1594. } else if (Object1->Properties.Type == Object2->Properties.Type) {
  1595. if (Object1 > Object2) {
  1596. Swap = Object1;
  1597. Object1 = Object2;
  1598. Object2 = Swap;
  1599. }
  1600. }
  1601. KeAcquireSharedExclusiveLockExclusive(Object1->Lock);
  1602. KeAcquireSharedExclusiveLockExclusive(Object2->Lock);
  1603. return;
  1604. }
  1605. PIMAGE_SECTION_LIST
  1606. IopGetImageSectionListFromFileObject (
  1607. PFILE_OBJECT FileObject
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. This routine gets the image section for the given file object.
  1612. Arguments:
  1613. FileObject - Supplies a pointer to a file object.
  1614. Return Value:
  1615. Returns a pointer to the file object's image section list or NULL on
  1616. failure.
  1617. --*/
  1618. {
  1619. PIMAGE_SECTION_LIST ImageSectionList;
  1620. PIMAGE_SECTION_LIST OldList;
  1621. //
  1622. // If there is no image section list, then allocate one and try to set it
  1623. // in the file object.
  1624. //
  1625. if (FileObject->ImageSectionList == NULL) {
  1626. ImageSectionList = MmCreateImageSectionList();
  1627. if (ImageSectionList == NULL) {
  1628. goto GetImageSectionListFromFileObjectEnd;
  1629. }
  1630. OldList = (PVOID)RtlAtomicCompareExchange(
  1631. (volatile UINTN *)&(FileObject->ImageSectionList),
  1632. (UINTN)ImageSectionList,
  1633. (UINTN)NULL);
  1634. if (OldList != NULL) {
  1635. MmDestroyImageSectionList(ImageSectionList);
  1636. }
  1637. }
  1638. ASSERT(FileObject->ImageSectionList != NULL);
  1639. ImageSectionList = FileObject->ImageSectionList;
  1640. GetImageSectionListFromFileObjectEnd:
  1641. return ImageSectionList;
  1642. }
  1643. VOID
  1644. IopMarkFileObjectDirty (
  1645. PFILE_OBJECT FileObject
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. This routine marks the given file object as dirty, moving it to the list of
  1650. dirty file objects if it is not already on a list.
  1651. Arguments:
  1652. FileObject - Supplies a pointer to the dirty file object.
  1653. Return Value:
  1654. None.
  1655. --*/
  1656. {
  1657. if ((FileObject->Flags & FILE_OBJECT_FLAG_DIRTY_DATA) == 0) {
  1658. KeAcquireQueuedLock(IoFileObjectsDirtyListLock);
  1659. RtlAtomicOr32(&(FileObject->Flags), FILE_OBJECT_FLAG_DIRTY_DATA);
  1660. if (FileObject->ListEntry.Next == NULL) {
  1661. IopFileObjectAddReference(FileObject);
  1662. //
  1663. // The lower layer file objects go at the end of the list. This
  1664. // allows flush to only traverse the list once to get all the data
  1665. // out to the block devices.
  1666. //
  1667. if (FileObject->Properties.Type == IoObjectBlockDevice) {
  1668. INSERT_BEFORE(&(FileObject->ListEntry),
  1669. &IoFileObjectsDirtyList);
  1670. } else {
  1671. INSERT_AFTER(&(FileObject->ListEntry), &IoFileObjectsDirtyList);
  1672. }
  1673. }
  1674. KeReleaseQueuedLock(IoFileObjectsDirtyListLock);
  1675. IopSchedulePageCacheThread();
  1676. }
  1677. return;
  1678. }
  1679. VOID
  1680. IopMarkFileObjectPropertiesDirty (
  1681. PFILE_OBJECT FileObject
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. This routine marks that the given file object's properties are dirty.
  1686. Arguments:
  1687. FileObject - Supplies a pointer to the file object whose properties are
  1688. dirty.
  1689. Return Value:
  1690. None.
  1691. --*/
  1692. {
  1693. ULONG OldFlags;
  1694. if ((FileObject->Flags & FILE_OBJECT_FLAG_DIRTY_PROPERTIES) == 0) {
  1695. OldFlags = RtlAtomicOr32(&(FileObject->Flags),
  1696. FILE_OBJECT_FLAG_DIRTY_PROPERTIES);
  1697. //
  1698. // If this operation just transitioned the file properties from clean to
  1699. // dirty and the file object has a hard link, add the file object to the
  1700. // dirty list and let the page cache know so it can flush out this file
  1701. // object data.
  1702. //
  1703. if (((OldFlags & FILE_OBJECT_FLAG_DIRTY_PROPERTIES) == 0) &&
  1704. (FileObject->Properties.HardLinkCount != 0)) {
  1705. IopMarkFileObjectDirty(FileObject);
  1706. }
  1707. }
  1708. return;
  1709. }
  1710. VOID
  1711. IopCheckDirtyFileObjectsList (
  1712. VOID
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This routine iterates over all file objects, checking to make sure they're
  1717. properly marked dirty and in the dirty list if they have dirty entries.
  1718. This routine is slow and should only be used while actively debugging
  1719. dirty data that won't flush.
  1720. Arguments:
  1721. None.
  1722. Return Value:
  1723. None.
  1724. --*/
  1725. {
  1726. PFILE_OBJECT FileObject;
  1727. PRED_BLACK_TREE_NODE Node;
  1728. KeAcquireQueuedLock(IoFileObjectsLock);
  1729. KeAcquireQueuedLock(IoFileObjectsDirtyListLock);
  1730. Node = RtlRedBlackTreeGetLowestNode(&IoFileObjectsTree);
  1731. while (Node != NULL) {
  1732. FileObject = RED_BLACK_TREE_VALUE(Node, FILE_OBJECT, TreeEntry);
  1733. if (!LIST_EMPTY(&(FileObject->DirtyPageList))) {
  1734. if (IS_FILE_OBJECT_CLEAN(FileObject)) {
  1735. RtlDebugPrint("FILE_OBJECT 0x%x marked as clean with "
  1736. "non-empty dirty list.\n",
  1737. FileObject);
  1738. }
  1739. if (FileObject->ListEntry.Next == NULL) {
  1740. RtlDebugPrint("FILE_OBJECT 0x%x dirty but not in dirty list.\n",
  1741. FileObject);
  1742. }
  1743. }
  1744. Node = RtlRedBlackTreeGetNextNode(&IoFileObjectsTree, FALSE, Node);
  1745. }
  1746. KeReleaseQueuedLock(IoFileObjectsDirtyListLock);
  1747. KeReleaseQueuedLock(IoFileObjectsLock);
  1748. return;
  1749. }
  1750. PIO_ASYNC_STATE
  1751. IopGetAsyncState (
  1752. PIO_OBJECT_STATE State
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. This routine returns or attempts to create the asynchronous state for an
  1757. I/O object state.
  1758. Arguments:
  1759. State - Supplies a pointer to the I/O object state.
  1760. Return Value:
  1761. Returns a pointer to the async state on success. This may have just been
  1762. created.
  1763. NULL if no async state exists and none could be created.
  1764. --*/
  1765. {
  1766. PIO_ASYNC_STATE Async;
  1767. PIO_ASYNC_STATE OldValue;
  1768. if (State->Async != NULL) {
  1769. return State->Async;
  1770. }
  1771. Async = MmAllocatePagedPool(sizeof(IO_ASYNC_STATE),
  1772. FILE_OBJECT_ALLOCATION_TAG);
  1773. if (Async == NULL) {
  1774. return NULL;
  1775. }
  1776. RtlZeroMemory(Async, sizeof(IO_ASYNC_STATE));
  1777. INITIALIZE_LIST_HEAD(&(Async->ReceiverList));
  1778. Async->Lock = KeCreateQueuedLock();
  1779. if (Async->Lock == NULL) {
  1780. goto GetAsyncStateEnd;
  1781. }
  1782. //
  1783. // Try to atomically set the async state. Someone else may race and win.
  1784. //
  1785. OldValue = (PIO_ASYNC_STATE)RtlAtomicCompareExchange(
  1786. (PUINTN)&(State->Async),
  1787. (UINTN)Async,
  1788. (UINTN)NULL);
  1789. if (OldValue == NULL) {
  1790. Async = NULL;
  1791. }
  1792. GetAsyncStateEnd:
  1793. if (Async != NULL) {
  1794. IopDestroyAsyncState(Async);
  1795. }
  1796. return State->Async;
  1797. }
  1798. //
  1799. // --------------------------------------------------------- Internal Functions
  1800. //
  1801. KSTATUS
  1802. IopFlushFileObjectProperties (
  1803. PFILE_OBJECT FileObject,
  1804. ULONG Flags
  1805. )
  1806. /*++
  1807. Routine Description:
  1808. This routine flushes the file properties for the given file object. The
  1809. file object lock must already be held at least shared.
  1810. Arguments:
  1811. FileObject - Supplies a pointer to a file object.
  1812. Flags - Supplies a bitmask of I/O flags. See IO_FLAG_* for definitions.
  1813. Return Value:
  1814. Status code.
  1815. --*/
  1816. {
  1817. IRP_MINOR_CODE MinorCode;
  1818. ULONG OldFlags;
  1819. KSTATUS Status;
  1820. ASSERT(KeIsSharedExclusiveLockHeld(FileObject->Lock));
  1821. //
  1822. // Write out the file properties if a flush is required. A flush is
  1823. // required if the file properties are dirty and the hard link count is not
  1824. // zero.
  1825. //
  1826. OldFlags = RtlAtomicAnd32(&(FileObject->Flags),
  1827. ~FILE_OBJECT_FLAG_DIRTY_PROPERTIES);
  1828. if (((OldFlags & FILE_OBJECT_FLAG_DIRTY_PROPERTIES) != 0) &&
  1829. (FileObject->Properties.HardLinkCount != 0)) {
  1830. //
  1831. // Write out the file properties. Don't report a failure if the device
  1832. // got yanked in the middle of this operation. Other failures should
  1833. // reset the properties as dirty. Something else may have marked them
  1834. // dirty already and they may already have been cleaned successfully.
  1835. // But this at least guarantees it will be tried again.
  1836. //
  1837. MinorCode = IrpMinorSystemControlWriteFileProperties;
  1838. Status = IopSendFileOperationIrp(MinorCode, FileObject, NULL, Flags);
  1839. if ((!KSUCCESS(Status)) && (Status != STATUS_DEVICE_NOT_CONNECTED)) {
  1840. IopMarkFileObjectPropertiesDirty(FileObject);
  1841. goto FlushFilePropertiesEnd;
  1842. }
  1843. }
  1844. Status = STATUS_SUCCESS;
  1845. FlushFilePropertiesEnd:
  1846. return Status;
  1847. }
  1848. COMPARISON_RESULT
  1849. IopCompareFileObjectNodes (
  1850. PRED_BLACK_TREE Tree,
  1851. PRED_BLACK_TREE_NODE FirstNode,
  1852. PRED_BLACK_TREE_NODE SecondNode
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. This routine compares two Red-Black tree nodes contained inside file
  1857. objects.
  1858. Arguments:
  1859. Tree - Supplies a pointer to the Red-Black tree that owns both nodes.
  1860. FirstNode - Supplies a pointer to the left side of the comparison.
  1861. SecondNode - Supplies a pointer to the second side of the comparison.
  1862. Return Value:
  1863. Same if the two nodes have the same value.
  1864. Ascending if the first node is less than the second node.
  1865. Descending if the second node is less than the first node.
  1866. --*/
  1867. {
  1868. PFILE_OBJECT FirstObject;
  1869. PFILE_OBJECT SecondObject;
  1870. FirstObject = RED_BLACK_TREE_VALUE(FirstNode, FILE_OBJECT, TreeEntry);
  1871. SecondObject = RED_BLACK_TREE_VALUE(SecondNode, FILE_OBJECT, TreeEntry);
  1872. //
  1873. // First check the file IDs, which are most likely to be different.
  1874. //
  1875. if (FirstObject->Properties.FileId > SecondObject->Properties.FileId) {
  1876. return ComparisonResultDescending;
  1877. }
  1878. if (FirstObject->Properties.FileId < SecondObject->Properties.FileId) {
  1879. return ComparisonResultAscending;
  1880. }
  1881. //
  1882. // The File IDs are equal, also compare the volumes.
  1883. //
  1884. if (FirstObject->Properties.DeviceId > SecondObject->Properties.DeviceId) {
  1885. return ComparisonResultDescending;
  1886. }
  1887. if (FirstObject->Properties.DeviceId < SecondObject->Properties.DeviceId) {
  1888. return ComparisonResultAscending;
  1889. }
  1890. //
  1891. // Both the File ID and the volume are equal, these nodes are the
  1892. // same.
  1893. //
  1894. return ComparisonResultSame;
  1895. }
  1896. PFILE_OBJECT
  1897. IopLookupFileObjectByProperties (
  1898. PFILE_PROPERTIES Properties
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. This routine attempts to look up a file object with the given properties
  1903. (specifically the device and file IDs). It assumes the global file objects
  1904. lock is already held.
  1905. Arguments:
  1906. Properties - Supplies a pointer to the file object properties.
  1907. Return Value:
  1908. Returns a pointer to the found file object, with an incremented reference
  1909. count on success. The caller is responsible for releasing this reference.
  1910. NULL if the file object could not be found.
  1911. --*/
  1912. {
  1913. PRED_BLACK_TREE_NODE FoundNode;
  1914. PFILE_OBJECT Object;
  1915. ULONG OldReferenceCount;
  1916. FILE_OBJECT SearchObject;
  1917. ASSERT(Properties->DeviceId != 0);
  1918. Object = NULL;
  1919. SearchObject.Properties.FileId = Properties->FileId;
  1920. SearchObject.Properties.DeviceId = Properties->DeviceId;
  1921. FoundNode = RtlRedBlackTreeSearch(&IoFileObjectsTree,
  1922. &(SearchObject.TreeEntry));
  1923. if (FoundNode != NULL) {
  1924. Object = RED_BLACK_TREE_VALUE(FoundNode, FILE_OBJECT, TreeEntry);
  1925. //
  1926. // Increment the reference count. If this ends up resurrecting an
  1927. // orphaned or about to be closed file object, then make sure it is not
  1928. // on the orphaned list (or any list for that matter) as it could be
  1929. // used and made dirty.
  1930. //
  1931. OldReferenceCount = IopFileObjectAddReference(Object);
  1932. if (OldReferenceCount == 1) {
  1933. if (Object->ListEntry.Next != NULL) {
  1934. LIST_REMOVE(&(Object->ListEntry));
  1935. Object->ListEntry.Next = NULL;
  1936. }
  1937. }
  1938. }
  1939. return Object;
  1940. }
  1941. VOID
  1942. IopDestroyAsyncState (
  1943. PIO_ASYNC_STATE Async
  1944. )
  1945. /*++
  1946. Routine Description:
  1947. This routine destroys the given asynchronous state.
  1948. Arguments:
  1949. Async - Supplies a pointer to the state to destroy.
  1950. Return Value:
  1951. None.
  1952. --*/
  1953. {
  1954. ASSERT(LIST_EMPTY(&(Async->ReceiverList)));
  1955. if (Async->Lock != NULL) {
  1956. KeDestroyQueuedLock(Async->Lock);
  1957. }
  1958. MmFreePagedPool(Async);
  1959. return;
  1960. }
  1961. VOID
  1962. IopSendIoSignal (
  1963. PIO_ASYNC_STATE Async,
  1964. ULONG Event
  1965. )
  1966. /*++
  1967. Routine Description:
  1968. This routine sends an IO signal to the given process or process group.
  1969. Arguments:
  1970. Async - Supplies a pointer to the async state.
  1971. Event - Supplies the event code to include.
  1972. Return Value:
  1973. None.
  1974. --*/
  1975. {
  1976. PLIST_ENTRY CurrentEntry;
  1977. THREAD_IDENTITY Destination;
  1978. PROCESS_ID ProcessId;
  1979. PSIGNAL_QUEUE_ENTRY QueueEntry;
  1980. PASYNC_IO_RECEIVER Receiver;
  1981. ULONG Signal;
  1982. KSTATUS Status;
  1983. //
  1984. // Currently, the signal can only be sent to a single process. To support
  1985. // process groups, the appropriate permission checking would need to be
  1986. // done for each process in the group.
  1987. //
  1988. ProcessId = Async->Owner;
  1989. if (ProcessId <= 0) {
  1990. return;
  1991. }
  1992. KeAcquireQueuedLock(Async->Lock);
  1993. //
  1994. // Ensure that whoever set the owner has permission to send a signal to
  1995. // the owner.
  1996. //
  1997. Status = PsGetProcessIdentity(ProcessId, &Destination);
  1998. if (!KSUCCESS(Status)) {
  1999. goto SendIoSignalEnd;
  2000. }
  2001. if ((!PERMISSION_CHECK(Async->SetterPermissions, PERMISSION_KILL)) &&
  2002. (Async->SetterUserId != Destination.RealUserId) &&
  2003. (Async->SetterUserId != Destination.SavedUserId) &&
  2004. (Async->SetterEffectiveUserId != Destination.RealUserId) &&
  2005. (Async->SetterEffectiveUserId != Destination.SavedUserId)) {
  2006. goto SendIoSignalEnd;
  2007. }
  2008. //
  2009. // Find the receiver to ensure the caller has in fact signed up for
  2010. // asynchronous I/O signals.
  2011. //
  2012. CurrentEntry = Async->ReceiverList.Next;
  2013. while (CurrentEntry != &(Async->ReceiverList)) {
  2014. Receiver = LIST_VALUE(CurrentEntry, ASYNC_IO_RECEIVER, ListEntry);
  2015. if (Receiver->ProcessId == ProcessId) {
  2016. break;
  2017. }
  2018. CurrentEntry = CurrentEntry->Next;
  2019. }
  2020. if (CurrentEntry == &(Async->ReceiverList)) {
  2021. goto SendIoSignalEnd;
  2022. }
  2023. if (Async->Signal == 0) {
  2024. Signal = SIGNAL_ASYNCHRONOUS_IO_COMPLETE;
  2025. } else {
  2026. Signal = Async->Signal;
  2027. }
  2028. QueueEntry = MmAllocatePagedPool(sizeof(SIGNAL_QUEUE_ENTRY),
  2029. FILE_OBJECT_ALLOCATION_TAG);
  2030. if (QueueEntry != NULL) {
  2031. RtlZeroMemory(QueueEntry, sizeof(SIGNAL_QUEUE_ENTRY));
  2032. QueueEntry->Parameters.SignalNumber = Signal;
  2033. QueueEntry->Parameters.SignalCode = Event;
  2034. QueueEntry->CompletionRoutine = PsDefaultSignalCompletionRoutine;
  2035. }
  2036. Status = PsSignalProcessId(ProcessId, Signal, QueueEntry);
  2037. if (!KSUCCESS(Status)) {
  2038. MmFreePagedPool(QueueEntry);
  2039. goto SendIoSignalEnd;
  2040. }
  2041. QueueEntry = NULL;
  2042. SendIoSignalEnd:
  2043. KeReleaseQueuedLock(Async->Lock);
  2044. return;
  2045. }