filesys.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. filesys.c
  5. Abstract:
  6. This module implements support for file system drivers.
  7. Author:
  8. Evan Green 25-Sep-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel.h>
  16. #include <minoca/devinfo/part.h>
  17. #include "iop.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // Define the maximum length of a volume name string, including the terminator.
  23. //
  24. #define VOLUME_NAME_LENGTH 11
  25. //
  26. // Define the number of times create or lookup volume is allowed to kick-start
  27. // a failed device.
  28. //
  29. #define VOLUME_START_RETRY_MAX 1
  30. //
  31. // Define the maximum number of supported volumes in the system.
  32. //
  33. #define MAX_VOLUMES 10000
  34. //
  35. // Define the location of the drivers directory, relative to the system root.
  36. //
  37. #define SYSTEM_DRIVERS_DIRECTORY "drivers"
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. /*++
  42. Structure Description:
  43. This structure defines a registered file system.
  44. Members:
  45. ListEntry - Stores pointers to the previous and next registered file
  46. systems.
  47. Driver - Supplies a pointer to the driver object.
  48. --*/
  49. typedef struct _FILE_SYSTEM {
  50. LIST_ENTRY ListEntry;
  51. PDRIVER Driver;
  52. } FILE_SYSTEM, *PFILE_SYSTEM;
  53. //
  54. // ----------------------------------------------- Internal Function Prototypes
  55. //
  56. VOID
  57. IopDestroyVolume (
  58. PVOLUME Volume
  59. );
  60. PSTR
  61. IopGetNewVolumeName (
  62. VOID
  63. );
  64. //
  65. // -------------------------------------------------------------------- Globals
  66. //
  67. //
  68. // Keep the list of registered file systems.
  69. //
  70. LIST_ENTRY IoFileSystemList;
  71. //
  72. // This lock synchronizes access to the list of file systems.
  73. //
  74. PQUEUED_LOCK IoFileSystemListLock = NULL;
  75. //
  76. // Store a pointer to the volumes directory and the number of volumes in the
  77. // system.
  78. //
  79. POBJECT_HEADER IoVolumeDirectory = NULL;
  80. //
  81. // Define the path from the system volume to the system directory. Set it to a
  82. // default in case there is no boot entry (which there should really always be).
  83. //
  84. PSTR IoSystemDirectoryPath = "minoca";
  85. //
  86. // Store a pointer to the system volumes.
  87. //
  88. PVOLUME IoSystemVolume = NULL;
  89. UUID IoPartitionDeviceInformationUuid = PARTITION_DEVICE_INFORMATION_UUID;
  90. //
  91. // ------------------------------------------------------------------ Functions
  92. //
  93. KERNEL_API
  94. KSTATUS
  95. IoRegisterFileSystem (
  96. PDRIVER Driver
  97. )
  98. /*++
  99. Routine Description:
  100. This routine registers the given driver as a file system driver.
  101. Arguments:
  102. Driver - Supplies a pointer to the driver registering the file system
  103. support.
  104. Return Value:
  105. Status code.
  106. --*/
  107. {
  108. PFILE_SYSTEM NewFileSystem;
  109. KSTATUS Status;
  110. //
  111. // Allocate and initialize the new file system.
  112. //
  113. NewFileSystem = MmAllocatePagedPool(sizeof(FILE_SYSTEM), FI_ALLOCATION_TAG);
  114. if (NewFileSystem == NULL) {
  115. Status = STATUS_NO_MEMORY;
  116. goto RegisterFileSystemEnd;
  117. }
  118. RtlZeroMemory(NewFileSystem, sizeof(FILE_SYSTEM));
  119. NewFileSystem->Driver = Driver;
  120. //
  121. // Add it to the list.
  122. //
  123. KeAcquireQueuedLock(IoFileSystemListLock);
  124. INSERT_AFTER(&(NewFileSystem->ListEntry), &IoFileSystemList);
  125. KeReleaseQueuedLock(IoFileSystemListLock);
  126. Status = STATUS_SUCCESS;
  127. RegisterFileSystemEnd:
  128. return Status;
  129. }
  130. KSTATUS
  131. IopAddFileSystem (
  132. PDEVICE Device
  133. )
  134. /*++
  135. Routine Description:
  136. This routine adds a file system to the given volume.
  137. Arguments:
  138. Device - Supplies a pointer to the volume to attach a file system to.
  139. Return Value:
  140. Status code.
  141. --*/
  142. {
  143. PDRIVER_ADD_DEVICE AddDevice;
  144. PLIST_ENTRY CurrentEntry;
  145. PFILE_SYSTEM CurrentFileSystem;
  146. PDRIVER Driver;
  147. ULONG OriginalStackSize;
  148. KSTATUS Status;
  149. ASSERT(Device->Header.Type == ObjectVolume);
  150. OriginalStackSize = Device->DriverStackSize;
  151. Status = STATUS_NO_DRIVERS;
  152. //
  153. // Loop through all file systems, calling AddDevice until a driver
  154. // attaches.
  155. //
  156. KeAcquireQueuedLock(IoFileSystemListLock);
  157. CurrentEntry = IoFileSystemList.Next;
  158. while (CurrentEntry != &IoFileSystemList) {
  159. CurrentFileSystem = LIST_VALUE(CurrentEntry, FILE_SYSTEM, ListEntry);
  160. Driver = CurrentFileSystem->Driver;
  161. //
  162. // Call the driver's AddDevice. The return value of AddDevice is
  163. // ignored, success is implied if the driver attached itself. Note that
  164. // the file system list lock is held as Add Device is called. Thus
  165. // a file system driver's Add Device routine cannot depend on any other
  166. // volume enumerations to complete, otherwise a deadlock would occur.
  167. //
  168. if ((Driver->Flags & DRIVER_FLAG_FAILED_DRIVER_ENTRY) == 0) {
  169. if (Driver->FunctionTable.AddDevice != NULL) {
  170. AddDevice = Driver->FunctionTable.AddDevice;
  171. AddDevice(Driver,
  172. IoGetDeviceId(Device),
  173. Device->ClassId,
  174. Device->CompatibleIds,
  175. Device);
  176. if (Device->DriverStackSize != OriginalStackSize) {
  177. Status = STATUS_SUCCESS;
  178. break;
  179. }
  180. } else {
  181. Status = STATUS_DRIVER_FUNCTION_MISSING;
  182. IopSetDeviceProblem(Device, DeviceProblemNoAddDevice, Status);
  183. goto AddFileSystemEnd;
  184. }
  185. }
  186. CurrentEntry = CurrentEntry->Next;
  187. }
  188. if (!KSUCCESS(Status)) {
  189. IopSetDeviceProblem(Device, DeviceProblemNoFileSystem, Status);
  190. goto AddFileSystemEnd;
  191. }
  192. AddFileSystemEnd:
  193. KeReleaseQueuedLock(IoFileSystemListLock);
  194. return Status;
  195. }
  196. KSTATUS
  197. IoCreateVolume (
  198. PDEVICE Device,
  199. PVOLUME *Volume
  200. )
  201. /*++
  202. Routine Description:
  203. This routine creates a new volume to be mounted by a file system.
  204. Arguments:
  205. Device - Supplies a pointer to the physical device upon which the file
  206. system should be mounted.
  207. Volume - Supplies a pointer that receives a pointer to the newly created
  208. volume.
  209. Return Value:
  210. Status code.
  211. --*/
  212. {
  213. BOOL LockHeld;
  214. PSTR NewName;
  215. PVOLUME NewVolume;
  216. KSTATUS Status;
  217. BOOL TargetAttached;
  218. ASSERT((Device->Flags & DEVICE_FLAG_MOUNTABLE) != 0);
  219. LockHeld = FALSE;
  220. TargetAttached = FALSE;
  221. //
  222. // Allocate the next available name for the volume.
  223. //
  224. NewName = IopGetNewVolumeName();
  225. if (NewName == NULL) {
  226. Status = STATUS_INSUFFICIENT_RESOURCES;
  227. goto CreateVolumeEnd;
  228. }
  229. //
  230. // Create the volume.
  231. //
  232. Status = IopCreateDevice(NULL,
  233. NULL,
  234. (PDEVICE)IoVolumeDirectory,
  235. NewName,
  236. NULL,
  237. NULL,
  238. ObjectVolume,
  239. sizeof(VOLUME),
  240. (PDEVICE *)&NewVolume);
  241. if (!KSUCCESS(Status)) {
  242. goto CreateVolumeEnd;
  243. }
  244. //
  245. // Now acquire the physical device's lock exclusively and attach the volume
  246. // to it. If the physical device is awaiting removal or removed, abort the
  247. // process.
  248. //
  249. KeAcquireSharedExclusiveLockExclusive(Device->Lock);
  250. LockHeld = TRUE;
  251. if ((Device->State == DeviceAwaitingRemoval) ||
  252. (Device->State == DeviceRemoved)) {
  253. Status = STATUS_PARENT_AWAITING_REMOVAL;
  254. goto CreateVolumeEnd;
  255. }
  256. //
  257. // Only allow one volume to be mounted per device.
  258. //
  259. if ((Device->Flags & DEVICE_FLAG_MOUNTED) != 0) {
  260. Status = STATUS_TOO_LATE;
  261. goto CreateVolumeEnd;
  262. }
  263. //
  264. // Reference the backing device, attach it to the volume and add the volume
  265. // to the device's active child list.
  266. //
  267. ObAddReference(Device);
  268. NewVolume->Device.TargetDevice = Device;
  269. INSERT_BEFORE(&(NewVolume->Device.ActiveListEntry),
  270. &(Device->ActiveChildListHead));
  271. //
  272. // Set the volume specific referencee count to 1 or 2 depending on whether
  273. // or not the caller wants a pointer to the volume. Also add an object
  274. // manager reference that will be released when the volume reference drops
  275. // to 0.
  276. //
  277. ObAddReference(NewVolume);
  278. if (Volume == NULL) {
  279. NewVolume->ReferenceCount = 1;
  280. } else {
  281. NewVolume->ReferenceCount = 2;
  282. }
  283. TargetAttached = TRUE;
  284. Device->Flags |= DEVICE_FLAG_MOUNTED;
  285. KeReleaseSharedExclusiveLockExclusive(Device->Lock);
  286. LockHeld = FALSE;
  287. //
  288. // TODO: Determine if this volume should contain the page file.
  289. //
  290. NewVolume->Device.Flags |= DEVICE_FLAG_PAGING_DEVICE;
  291. //
  292. // Queue the work item to start the volume.
  293. //
  294. Status = IopQueueDeviceWork((PDEVICE)NewVolume, DeviceActionStart, NULL, 0);
  295. if (!KSUCCESS(Status)) {
  296. IopSetDeviceProblem((PDEVICE)NewVolume,
  297. DeviceProblemFailedToQueueStart,
  298. Status);
  299. goto CreateVolumeEnd;
  300. }
  301. CreateVolumeEnd:
  302. if (LockHeld != FALSE) {
  303. KeReleaseSharedExclusiveLockExclusive(Device->Lock);
  304. }
  305. if (!KSUCCESS(Status)) {
  306. //
  307. // If the volume failed to attach, but was created, then release it.
  308. //
  309. if (TargetAttached == FALSE) {
  310. if (NewVolume != NULL) {
  311. ObReleaseReference(NewVolume);
  312. }
  313. //
  314. // Otherwise if the caller requested the new volume, release the second
  315. // reference taken. This will actually attempt to destroy the volume.
  316. // It may succeed, but it may not. Not much to do about this.
  317. //
  318. } else if (Volume != NULL) {
  319. ASSERT(TargetAttached != FALSE);
  320. IoVolumeReleaseReference(NewVolume);
  321. }
  322. } else {
  323. //
  324. // If the caller wanted a pointer to the volume, send it off.
  325. //
  326. if (Volume != NULL) {
  327. *Volume = NewVolume;
  328. }
  329. }
  330. if (NewName != NULL) {
  331. MmFreePagedPool(NewName);
  332. }
  333. return Status;
  334. }
  335. KSTATUS
  336. IopCreateOrLookupVolume (
  337. PDEVICE Device,
  338. PVOLUME *Volume
  339. )
  340. /*++
  341. Routine Description:
  342. This routine returns the volume associated with the given device, if such
  343. a volume exists. A reference is taken on the volume, which the caller is
  344. expected to release.
  345. Arguments:
  346. Device - Supplies a pointer to the device whose volume is to be returned.
  347. Volume - Supplies a pointer that receives a pointer to the created or found
  348. volume.
  349. VolumeCreated - Supplies a pointer that receives a boolean indicating
  350. whether or not the volume was created.
  351. Return Value:
  352. Status code.
  353. --*/
  354. {
  355. PDEVICE Child;
  356. PLIST_ENTRY CurrentEntry;
  357. PVOLUME FoundVolume;
  358. PVOLUME NewVolume;
  359. ULONG RetryCount;
  360. KSTATUS Status;
  361. ASSERT(Device != NULL);
  362. ASSERT(Volume != NULL);
  363. ASSERT((Device->Flags & DEVICE_FLAG_MOUNTABLE) != 0);
  364. FoundVolume = NULL;
  365. //
  366. // Loop until a volume is found or created.
  367. //
  368. while (TRUE) {
  369. //
  370. // If the OS has not already mounted a volume on the device, then try
  371. // to create a volume.
  372. //
  373. if ((Device->Flags & DEVICE_FLAG_MOUNTED) == 0) {
  374. //
  375. // Create a volume on the device. If this successfully creates a
  376. // volume, then it takes a reference on it. If it finds out that
  377. // someone else beat it to the punch, it returns a "too late"
  378. // status. If it fails outright, just exit.
  379. //
  380. Status = IoCreateVolume(Device, &NewVolume);
  381. if (!KSUCCESS(Status) && (Status != STATUS_TOO_LATE)) {
  382. goto CreateOrLookupVolumeEnd;
  383. }
  384. //
  385. // If a volume was successfully created, wait for the volume to
  386. // signal on ready or on failure.
  387. //
  388. if (KSUCCESS(Status)) {
  389. ObWaitOnObject(NewVolume, 0, WAIT_TIME_INDEFINITE);
  390. //
  391. // After the signal, if the volume is in the started state,
  392. // then this is a success. If the volume is not started, then
  393. // either there was a problem initializing the volume or it
  394. // was removed because of user interaction. Either way, fail.
  395. //
  396. FoundVolume = NewVolume;
  397. if (NewVolume->Device.State == DeviceStarted) {
  398. Status = STATUS_SUCCESS;
  399. } else {
  400. Status = STATUS_UNSUCCESSFUL;
  401. }
  402. goto CreateOrLookupVolumeEnd;
  403. }
  404. }
  405. //
  406. // A volume was already mounted when this routine was called or someone
  407. // else beat this routine to the punch. Lookup the volume.
  408. //
  409. FoundVolume = NULL;
  410. KeAcquireSharedExclusiveLockShared(Device->Lock);
  411. //
  412. // If the volume still remains, then search for it. If it has been
  413. // unmounted since the check above, there are a few options: (1) the
  414. // device is in the middle of removal - the next volume create will
  415. // fail; (2) the volume got removed - the next volume create should
  416. // succeed. This routine loops to try again either way.
  417. //
  418. if ((Device->Flags & DEVICE_FLAG_MOUNTED) != 0) {
  419. CurrentEntry = Device->ActiveChildListHead.Next;
  420. //
  421. // Search through the active children for the first volume. There
  422. // should only be one volume per device. Add a reference to this
  423. // volume and return it.
  424. //
  425. while (CurrentEntry != &(Device->ActiveChildListHead)) {
  426. Child = LIST_VALUE(CurrentEntry, DEVICE, ActiveListEntry);
  427. if (Child->Header.Type == ObjectVolume) {
  428. FoundVolume = (PVOLUME)Child;
  429. IoVolumeAddReference(FoundVolume);
  430. break;
  431. }
  432. CurrentEntry = CurrentEntry->Next;
  433. }
  434. }
  435. KeReleaseSharedExclusiveLockShared(Device->Lock);
  436. //
  437. // If a volume was found, wait on it. If it signals from the start
  438. // state, proceed. If it signals from the removed state, then try
  439. // again. If it signals from any other state, try to kick-start it
  440. // once before giving up.
  441. //
  442. if (FoundVolume != NULL) {
  443. RetryCount = 0;
  444. while (TRUE) {
  445. ObWaitOnObject(FoundVolume, 0, WAIT_TIME_INDEFINITE);
  446. if (FoundVolume->Device.State == DeviceStarted) {
  447. Status = STATUS_SUCCESS;
  448. goto CreateOrLookupVolumeEnd;
  449. }
  450. //
  451. // Try to find or create the volume again if the volume has
  452. // been removed.
  453. //
  454. if (FoundVolume->Device.State == DeviceRemoved) {
  455. IoVolumeReleaseReference(FoundVolume);
  456. FoundVolume = NULL;
  457. break;
  458. }
  459. if (RetryCount >= VOLUME_START_RETRY_MAX) {
  460. Status = STATUS_UNSUCCESSFUL;
  461. goto CreateOrLookupVolumeEnd;
  462. }
  463. //
  464. // Otherwise, kick it to see if it will come up.
  465. //
  466. ObSignalObject(FoundVolume, SignalOptionUnsignal);
  467. Status = IopQueueDeviceWork((PDEVICE)FoundVolume,
  468. DeviceActionStart,
  469. NULL,
  470. 0);
  471. if (!KSUCCESS(Status)) {
  472. IopSetDeviceProblem((PDEVICE)NewVolume,
  473. DeviceProblemFailedToQueueStart,
  474. Status);
  475. goto CreateOrLookupVolumeEnd;
  476. }
  477. RetryCount += 1;
  478. }
  479. }
  480. }
  481. CreateOrLookupVolumeEnd:
  482. if (!KSUCCESS(Status)) {
  483. if (FoundVolume != NULL) {
  484. IoVolumeReleaseReference(FoundVolume);
  485. }
  486. } else {
  487. *Volume = FoundVolume;
  488. }
  489. return Status;
  490. }
  491. VOID
  492. IopVolumeArrival (
  493. PVOID Parameter
  494. )
  495. /*++
  496. Routine Description:
  497. This routine performs work associated with a new volume coming online.
  498. Arguments:
  499. Parameter - Supplies a pointer to the arriving volume.
  500. Return Value:
  501. None.
  502. --*/
  503. {
  504. IO_BOOT_INFORMATION BootInformation;
  505. UINTN BootInformationSize;
  506. BOOL Created;
  507. PSTR DeviceName;
  508. ULONG DeviceNameLength;
  509. PIO_HANDLE DriversDirectoryHandle;
  510. PFILE_OBJECT FileObject;
  511. ULONG FileObjectFlags;
  512. PKPROCESS KernelProcess;
  513. BOOL Match;
  514. PARTITION_DEVICE_INFORMATION PartitionInformation;
  515. UINTN PartitionInformationSize;
  516. PPATH_POINT PathPoint;
  517. FILE_PROPERTIES Properties;
  518. ULONG RootLookupFlags;
  519. KSTATUS Status;
  520. PIO_HANDLE SystemDirectoryHandle;
  521. BOOL SystemVolume;
  522. PDEVICE TargetDevice;
  523. PVOLUME Volume;
  524. PIO_HANDLE VolumeHandle;
  525. PSTR VolumeName;
  526. ULONG VolumeNameLength;
  527. DeviceName = NULL;
  528. DriversDirectoryHandle = NULL;
  529. FileObject = NULL;
  530. SystemDirectoryHandle = NULL;
  531. SystemVolume = FALSE;
  532. Volume = (PVOLUME)Parameter;
  533. VolumeHandle = NULL;
  534. ASSERT(Volume != NULL);
  535. ASSERT(Volume->Device.Header.Type == ObjectVolume);
  536. //
  537. // Get the partition information for the volume.
  538. //
  539. TargetDevice = IoGetTargetDevice((PDEVICE)Volume);
  540. ASSERT(TargetDevice != NULL);
  541. VolumeName = ObGetFullPath(Volume, IO_ALLOCATION_TAG);
  542. if (VolumeName == NULL) {
  543. Status = STATUS_INSUFFICIENT_RESOURCES;
  544. goto VolumeArrivalEnd;
  545. }
  546. DeviceName = ObGetFullPath(TargetDevice, IO_ALLOCATION_TAG);
  547. if (DeviceName == NULL) {
  548. Status = STATUS_INSUFFICIENT_RESOURCES;
  549. goto VolumeArrivalEnd;
  550. }
  551. DeviceNameLength = RtlStringLength(DeviceName) + 1;
  552. VolumeNameLength = RtlStringLength(VolumeName) + 1;
  553. //
  554. // Get the root path entry for the volume. Start by sending a root lookup
  555. // request to the volume. If it does not succeed, then the volume isn't
  556. // participating in the file system and there is nothing to do, really.
  557. //
  558. Status = IopSendRootLookupRequest(&(Volume->Device),
  559. &Properties,
  560. &RootLookupFlags);
  561. if (!KSUCCESS(Status)) {
  562. goto VolumeArrivalEnd;
  563. }
  564. Properties.DeviceId = Volume->Device.DeviceId;
  565. FileObjectFlags = 0;
  566. if ((RootLookupFlags & LOOKUP_FLAG_NON_CACHED) != 0) {
  567. FileObjectFlags |= FILE_OBJECT_FLAG_NON_CACHED;
  568. }
  569. //
  570. // Create or lookup a file object for the volume.
  571. //
  572. Status = IopCreateOrLookupFileObject(&Properties,
  573. &(Volume->Device),
  574. FileObjectFlags,
  575. &FileObject,
  576. &Created);
  577. if (!KSUCCESS(Status)) {
  578. goto VolumeArrivalEnd;
  579. }
  580. ASSERT(Created != FALSE);
  581. ASSERT(Volume->PathEntry == NULL);
  582. //
  583. // Make a path entry with the found file object. This does not take an
  584. // additional reference on the file object.
  585. //
  586. Volume->PathEntry = IopCreateAnonymousPathEntry(FileObject);
  587. if (Volume->PathEntry == NULL) {
  588. Status = STATUS_INSUFFICIENT_RESOURCES;
  589. goto VolumeArrivalEnd;
  590. }
  591. FileObject = NULL;
  592. //
  593. // The volume is completely set up now, so signal it as ready. This can
  594. // potentially race with the device removal sequence unsignalling the
  595. // volume. The worst is that something sneaks through with a short-lived
  596. // reference to the device. It won't be very useful once the remove IRP
  597. // is sent.
  598. //
  599. ObSignalObject(Volume, SignalOptionSignalAll);
  600. //
  601. // Mount the device on the volume. During this call, the mount code should
  602. // look up and find this volume as an active child of the given device.
  603. //
  604. Status = IoMount(TRUE,
  605. VolumeName,
  606. VolumeNameLength,
  607. DeviceName,
  608. DeviceNameLength,
  609. MOUNT_FLAG_LINKED,
  610. IO_ACCESS_READ | IO_ACCESS_WRITE);
  611. if (!KSUCCESS(Status)) {
  612. goto VolumeArrivalEnd;
  613. }
  614. //
  615. // Determine whether or not this is the system volume.
  616. //
  617. PartitionInformationSize = sizeof(PARTITION_DEVICE_INFORMATION);
  618. Status = IoGetSetDeviceInformation(TargetDevice->DeviceId,
  619. &IoPartitionDeviceInformationUuid,
  620. &PartitionInformation,
  621. &PartitionInformationSize,
  622. FALSE);
  623. if ((KSUCCESS(Status)) &&
  624. (PartitionInformationSize == sizeof(PARTITION_DEVICE_INFORMATION))) {
  625. //
  626. // Get the boot partition identifiers.
  627. //
  628. BootInformationSize = sizeof(IO_BOOT_INFORMATION);
  629. Status = KeGetSetSystemInformation(SystemInformationIo,
  630. IoInformationBoot,
  631. &BootInformation,
  632. &BootInformationSize,
  633. FALSE);
  634. if ((KSUCCESS(Status)) &&
  635. (BootInformationSize == sizeof(IO_BOOT_INFORMATION))) {
  636. ASSERT(sizeof(BootInformation.SystemPartitionIdentifier) ==
  637. sizeof(PartitionInformation.PartitionId));
  638. Match = RtlCompareMemory(
  639. BootInformation.SystemPartitionIdentifier,
  640. PartitionInformation.PartitionId,
  641. sizeof(BootInformation.SystemPartitionIdentifier));
  642. if ((Match != FALSE) && (IoSystemVolume == NULL)) {
  643. IoSystemVolume = Volume;
  644. SystemVolume = TRUE;
  645. }
  646. }
  647. }
  648. //
  649. // If this is the system volume, then open the drivers directory and change
  650. // the kernel's current directory to the driver's directory.
  651. //
  652. if (SystemVolume != FALSE) {
  653. //
  654. // Copy the system volume path. Synchronization would be needed if this
  655. // path changes.
  656. //
  657. ASSERT(VolumeNameLength != 0);
  658. Status = IoOpen(TRUE,
  659. NULL,
  660. VolumeName,
  661. VolumeNameLength,
  662. IO_ACCESS_READ,
  663. OPEN_FLAG_DIRECTORY,
  664. 0,
  665. &VolumeHandle);
  666. if (!KSUCCESS(Status)) {
  667. RtlDebugPrint("Failed to open system volume: %x\n", Status);
  668. goto VolumeArrivalEnd;
  669. }
  670. //
  671. // Attempt to open the system directory.
  672. //
  673. Status = IoOpen(TRUE,
  674. VolumeHandle,
  675. IoSystemDirectoryPath,
  676. RtlStringLength(IoSystemDirectoryPath) + 1,
  677. IO_ACCESS_READ,
  678. OPEN_FLAG_DIRECTORY,
  679. 0,
  680. &SystemDirectoryHandle);
  681. if (!KSUCCESS(Status)) {
  682. RtlDebugPrint("Failed to open system directory '%s': %x\n",
  683. IoSystemDirectoryPath,
  684. Status);
  685. goto VolumeArrivalEnd;
  686. }
  687. //
  688. // Attempt to open the driver directory.
  689. //
  690. Status = IoOpen(TRUE,
  691. SystemDirectoryHandle,
  692. SYSTEM_DRIVERS_DIRECTORY,
  693. sizeof(SYSTEM_DRIVERS_DIRECTORY),
  694. IO_ACCESS_READ,
  695. OPEN_FLAG_DIRECTORY,
  696. 0,
  697. &DriversDirectoryHandle);
  698. if (!KSUCCESS(Status)) {
  699. RtlDebugPrint("Failed to open driver directory '%s/%s': %x\n",
  700. IoSystemDirectoryPath,
  701. SYSTEM_DRIVERS_DIRECTORY,
  702. Status);
  703. goto VolumeArrivalEnd;
  704. }
  705. //
  706. // Now set the kernel's current working directory to the drivers
  707. // directory.
  708. //
  709. KernelProcess = PsGetKernelProcess();
  710. ASSERT(KernelProcess == PsGetCurrentProcess());
  711. PathPoint = &(DriversDirectoryHandle->PathPoint);
  712. IO_PATH_POINT_ADD_REFERENCE(PathPoint);
  713. KeAcquireQueuedLock(KernelProcess->Paths.Lock);
  714. ASSERT(KernelProcess->Paths.CurrentDirectory.PathEntry == NULL);
  715. ASSERT(KernelProcess->Paths.CurrentDirectory.MountPoint == NULL);
  716. IO_COPY_PATH_POINT(&(KernelProcess->Paths.CurrentDirectory), PathPoint);
  717. KeReleaseQueuedLock(KernelProcess->Paths.Lock);
  718. }
  719. //
  720. // Tell the memory manager about volumes that can contain page files.
  721. //
  722. if ((Volume->Device.Flags & DEVICE_FLAG_PAGING_DEVICE) != 0) {
  723. MmVolumeArrival(VolumeName, VolumeNameLength, SystemVolume);
  724. }
  725. //
  726. // Tell the process library about the new volume.
  727. //
  728. PsVolumeArrival(VolumeName, VolumeNameLength, SystemVolume);
  729. //
  730. // Attempt to start any devices that had previously failed as a volume with
  731. // more drivers is potentially here.
  732. //
  733. if (SystemVolume != FALSE) {
  734. IopQueueDeviceWork(IoRootDevice,
  735. DeviceActionStart,
  736. NULL,
  737. DEVICE_ACTION_SEND_TO_SUBTREE);
  738. }
  739. Status = STATUS_SUCCESS;
  740. VolumeArrivalEnd:
  741. if (VolumeName != NULL) {
  742. MmFreePagedPool(VolumeName);
  743. }
  744. if (DeviceName != NULL) {
  745. MmFreePagedPool(DeviceName);
  746. }
  747. if (FileObject != NULL) {
  748. IopFileObjectReleaseReference(FileObject);
  749. }
  750. if (VolumeHandle != NULL) {
  751. IoClose(VolumeHandle);
  752. }
  753. if (SystemDirectoryHandle != NULL) {
  754. IoClose(SystemDirectoryHandle);
  755. }
  756. if (DriversDirectoryHandle != NULL) {
  757. IoClose(DriversDirectoryHandle);
  758. }
  759. if (!KSUCCESS(Status)) {
  760. IopSetDeviceProblem((PDEVICE)Volume,
  761. DeviceProblemFailedVolumeArrival,
  762. Status);
  763. }
  764. //
  765. // Relase the reference on the volume taken when this work item was
  766. // scheduled.
  767. //
  768. ObReleaseReference(Volume);
  769. return;
  770. }
  771. VOID
  772. IoVolumeAddReference (
  773. PVOLUME Volume
  774. )
  775. /*++
  776. Routine Description:
  777. This routine increments a volume's reference count.
  778. Arguments:
  779. Volume - Supplies a pointer to a volume device.
  780. Return Value:
  781. None.
  782. --*/
  783. {
  784. ULONG OldReferenceCount;
  785. OldReferenceCount = RtlAtomicAdd32(&(Volume->ReferenceCount), 1);
  786. ASSERT(OldReferenceCount < 0x10000000);
  787. return;
  788. }
  789. VOID
  790. IoVolumeReleaseReference (
  791. PVOLUME Volume
  792. )
  793. /*++
  794. Routine Description:
  795. This routine decrements a volume's reference count.
  796. Arguments:
  797. Volume - Supplies a pointer to a volume device.
  798. Return Value:
  799. None.
  800. --*/
  801. {
  802. BOOL DestroyVolume;
  803. ULONG OldReferenceCount;
  804. PDEVICE TargetDevice;
  805. TargetDevice = Volume->Device.TargetDevice;
  806. KeAcquireSharedExclusiveLockExclusive(TargetDevice->Lock);
  807. OldReferenceCount = RtlAtomicAdd32(&(Volume->ReferenceCount), (ULONG)-1);
  808. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  809. if (OldReferenceCount == 2) {
  810. DestroyVolume = TRUE;
  811. KeAcquireSharedExclusiveLockExclusive(Volume->Device.Lock);
  812. //
  813. // If the volume is already removed or in the process of being
  814. // unmounted there is no work to do. It's too late.
  815. //
  816. if ((Volume->Device.State == DeviceRemoved) ||
  817. ((Volume->Flags & VOLUME_FLAG_UNMOUNTING) != 0)) {
  818. DestroyVolume = FALSE;
  819. //
  820. // Prepare the volume for the destruction path.
  821. //
  822. } else {
  823. //
  824. // Mark that the volume is in the middle of the unmounting process
  825. // in order to prevent new path walks from succeeding.
  826. //
  827. Volume->Flags |= VOLUME_FLAG_UNMOUNTING;
  828. //
  829. // Before proceeding through the removal process, unsignal the
  830. // volume. The volume lookup routine waits on the device for its
  831. // state to settle.
  832. //
  833. ObSignalObject(Volume, SignalOptionUnsignal);
  834. //
  835. // Take a object manager reference on the volume. As soon as the
  836. // locks are released, another thread could come through and
  837. // release the last volume reference and, in turn, the last object
  838. // reference.
  839. //
  840. ObAddReference(Volume);
  841. }
  842. KeReleaseSharedExclusiveLockExclusive(Volume->Device.Lock);
  843. KeReleaseSharedExclusiveLockExclusive(TargetDevice->Lock);
  844. if (DestroyVolume != FALSE) {
  845. IopDestroyVolume(Volume);
  846. ObReleaseReference(Volume);
  847. }
  848. } else if (OldReferenceCount == 1) {
  849. KeReleaseSharedExclusiveLockExclusive(TargetDevice->Lock);
  850. //
  851. // Release the volume path entry if the volume is about to be taken out
  852. // of comission.
  853. //
  854. if (Volume->PathEntry != NULL) {
  855. ASSERT(Volume->PathEntry->Parent == NULL);
  856. IoPathEntryReleaseReference(Volume->PathEntry);
  857. }
  858. ObReleaseReference(Volume);
  859. } else {
  860. KeReleaseSharedExclusiveLockExclusive(TargetDevice->Lock);
  861. }
  862. return;
  863. }
  864. KSTATUS
  865. IopRemoveDevicePaths (
  866. PDEVICE Device
  867. )
  868. /*++
  869. Routine Description:
  870. This routine takes the device's paths offline.
  871. Arguments:
  872. Device - Supplies a pointer to the departing device.
  873. Return Value:
  874. Status code.
  875. --*/
  876. {
  877. PSTR DevicePath;
  878. PSTR Path;
  879. ULONG PathSize;
  880. PATH_POINT RootPathPoint;
  881. KSTATUS Status;
  882. ASSERT(IS_DEVICE_OR_VOLUME(Device));
  883. //
  884. // If it's a volume, it should be unmounting.
  885. //
  886. ASSERT((Device->Header.Type != ObjectVolume) ||
  887. ((((PVOLUME)Device)->Flags & VOLUME_FLAG_UNMOUNTING) != 0));
  888. ASSERT((Device->State == DeviceAwaitingRemoval) ||
  889. (Device->State == DeviceRemoved));
  890. DevicePath = NULL;
  891. RootPathPoint.PathEntry = NULL;
  892. //
  893. // If the device is a volume, it might have contained a page file, notify
  894. // the memory is volume is being removed.
  895. //
  896. if ((Device->Flags & DEVICE_FLAG_PAGING_DEVICE) != 0) {
  897. Status = MmVolumeRemoval(Device);
  898. if (!KSUCCESS(Status)) {
  899. goto RemoveDevicePathsEnd;
  900. }
  901. }
  902. //
  903. // Retrieve a path to the device's root. If this fails, then the
  904. // removal process needs to be rolled back. The system cannot close any
  905. // opens paths or remove mount points correctly.
  906. //
  907. DevicePath = ObGetFullPath(Device, IO_ALLOCATION_TAG);
  908. if (DevicePath == NULL) {
  909. Status = STATUS_INSUFFICIENT_RESOURCES;
  910. goto RemoveDevicePathsEnd;
  911. }
  912. //
  913. // Open a path to the device root. If this fails, it should be because
  914. // the parent path is marked closing, or the root lookup call never
  915. // went through because the volume is set as "unmounting". In either
  916. // case, there are no paths or mount points to destroy. Count it as
  917. // success.
  918. //
  919. Path = DevicePath;
  920. PathSize = RtlStringLength(Path) + 1;
  921. Status = IopPathWalk(TRUE,
  922. NULL,
  923. &Path,
  924. &PathSize,
  925. OPEN_FLAG_DIRECTORY,
  926. IoObjectInvalid,
  927. NULL,
  928. FILE_PERMISSION_NONE,
  929. &RootPathPoint);
  930. if (!KSUCCESS(Status)) {
  931. ASSERT((Status == STATUS_PATH_NOT_FOUND) ||
  932. (Status == STATUS_DEVICE_NOT_CONNECTED));
  933. Status = STATUS_SUCCESS;
  934. goto RemoveDevicePathsEnd;
  935. }
  936. //
  937. // Forcefully remove all mount points that exist under the root.
  938. //
  939. IopRemoveMountPoints(&RootPathPoint);
  940. //
  941. // Clean the cached path entries. Do this after removing mount points as
  942. // the work above closed a bunch of path entries.
  943. //
  944. IopPathCleanCache(RootPathPoint.PathEntry);
  945. Status = STATUS_SUCCESS;
  946. RemoveDevicePathsEnd:
  947. if (DevicePath != NULL) {
  948. MmFreePagedPool(DevicePath);
  949. }
  950. if (RootPathPoint.PathEntry != NULL) {
  951. IO_PATH_POINT_RELEASE_REFERENCE(&RootPathPoint);
  952. }
  953. return Status;
  954. }
  955. //
  956. // --------------------------------------------------------- Internal Functions
  957. //
  958. VOID
  959. IopDestroyVolume (
  960. PVOLUME Volume
  961. )
  962. /*++
  963. Routine Description:
  964. This routine attempts to destroy the given volume by queuing its removal.
  965. Remove is not queued if the volume is busy.
  966. Arguments:
  967. Volume - Supplies a pointer to the volume to be destroyed.
  968. Return Value:
  969. Status code.
  970. --*/
  971. {
  972. ULONG Flags;
  973. KSTATUS Status;
  974. PDEVICE TargetDevice;
  975. ASSERT(Volume->Device.Header.Type == ObjectVolume);
  976. ASSERT((Volume->Flags & VOLUME_FLAG_UNMOUNTING) != 0);
  977. TargetDevice = Volume->Device.TargetDevice;
  978. //
  979. // Flush the volume. This does not need to be synchronized, because the
  980. // underlying device is explicitly flushed after in hope of batching writes
  981. // to the device.
  982. //
  983. Status = IopFlushFileObjects(Volume->Device.DeviceId, 0, NULL);
  984. if (!KSUCCESS(Status)) {
  985. Volume->Flags &= ~VOLUME_FLAG_UNMOUNTING;
  986. IopSetDeviceProblem(&(Volume->Device),
  987. DeviceProblemFailedVolumeRemoval,
  988. Status);
  989. goto DestroyVolumeEnd;
  990. }
  991. //
  992. // Since volumes and their target devices are 1:1, flush the device's
  993. // cache entries now that the volume has been closed and flushed. In the
  994. // future, the partition manager will have to trigger the device cache
  995. // flush once all the volumes are unmounted.
  996. //
  997. Status = IopFlushFileObjects(TargetDevice->DeviceId, 0, NULL);
  998. if (!KSUCCESS(Status)) {
  999. Volume->Flags &= ~VOLUME_FLAG_UNMOUNTING;
  1000. IopSetDeviceProblem(&(Volume->Device),
  1001. DeviceProblemFailedVolumeRemoval,
  1002. Status);
  1003. goto DestroyVolumeEnd;
  1004. }
  1005. //
  1006. // TODO: Notify the user that the device is now safe to remove.
  1007. //
  1008. //
  1009. // Remove any cached path entries that are below the volume root.
  1010. //
  1011. if (Volume->PathEntry != NULL) {
  1012. IopPathCleanCache(Volume->PathEntry);
  1013. }
  1014. //
  1015. // Start the removal process for this volume. There isn't much recourse if
  1016. // this fails other than to roll it back and let the caller know.
  1017. //
  1018. Flags = DEVICE_ACTION_SEND_TO_SUBTREE | DEVICE_ACTION_OPEN_QUEUE;
  1019. Status = IopQueueDeviceWork(&(Volume->Device),
  1020. DeviceActionPrepareRemove,
  1021. NULL,
  1022. Flags);
  1023. //
  1024. // If there was a queue failure, set the problem state. Do not call the
  1025. // queue failure handler as that might incorrectly roll back the device
  1026. // tree state. Just assume that no parent is waiting on this device's state
  1027. // and that is is safe to ignore the failure.
  1028. //
  1029. if (!KSUCCESS(Status) && (Status != STATUS_DEVICE_QUEUE_CLOSING)) {
  1030. Volume->Flags &= ~VOLUME_FLAG_UNMOUNTING;
  1031. IopSetDeviceProblem(&(Volume->Device),
  1032. DeviceProblemFailedToQueuePrepareRemove,
  1033. Status);
  1034. goto DestroyVolumeEnd;
  1035. }
  1036. //
  1037. // If this was the system volume, unset the global variable.
  1038. //
  1039. if (Volume == IoSystemVolume) {
  1040. IoSystemVolume = NULL;
  1041. }
  1042. DestroyVolumeEnd:
  1043. return;
  1044. }
  1045. PSTR
  1046. IopGetNewVolumeName (
  1047. VOID
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This routine returns a name for a volume that does not collide with any
  1052. existing volume names.
  1053. Arguments:
  1054. None.
  1055. Return Value:
  1056. Returns a new volume name on success, allocated from paged pool.
  1057. NULL on failure.
  1058. --*/
  1059. {
  1060. PVOID ExistingVolume;
  1061. PSTR NewName;
  1062. ULONG NewNameLength;
  1063. ULONG VolumeIndex;
  1064. NewName = MmAllocatePagedPool(VOLUME_NAME_LENGTH, FI_ALLOCATION_TAG);
  1065. if (NewName == NULL) {
  1066. goto GetNewVolumeNameEnd;
  1067. }
  1068. //
  1069. // Iterate through possible volume names. If the volume doesn't exist,
  1070. // return it.
  1071. //
  1072. for (VolumeIndex = 0; VolumeIndex < MAX_VOLUMES; VolumeIndex += 1) {
  1073. NewNameLength = RtlPrintToString(NewName,
  1074. VOLUME_NAME_LENGTH,
  1075. CharacterEncodingDefault,
  1076. "Volume%d",
  1077. VolumeIndex);
  1078. if (NewNameLength > VOLUME_NAME_LENGTH) {
  1079. NewNameLength = VOLUME_NAME_LENGTH;
  1080. }
  1081. ExistingVolume = ObFindObject(NewName,
  1082. NewNameLength,
  1083. IoVolumeDirectory);
  1084. if (ExistingVolume == NULL) {
  1085. goto GetNewVolumeNameEnd;
  1086. }
  1087. //
  1088. // The object exists, release the extra reference added by "finding" it.
  1089. //
  1090. ObReleaseReference(ExistingVolume);
  1091. ExistingVolume = NULL;
  1092. }
  1093. //
  1094. // There are too many volumes in the system! Give up.
  1095. //
  1096. MmFreePagedPool(NewName);
  1097. NewName = NULL;
  1098. GetNewVolumeNameEnd:
  1099. return NewName;
  1100. }