Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Raw called
  7. by the dispatch driver.
  8. Author:
  9. David Goebel [DavidGoe] 18-Mar-91
  10. Revision History:
  11. --*/
  12. #include "RawProcs.h"
  13. //
  14. // Local procedure prototypes
  15. //
  16. NTSTATUS
  17. RawMountVolume (
  18. IN PIO_STACK_LOCATION IrpSp
  19. );
  20. NTSTATUS
  21. RawVerifyVolume (
  22. IN PIO_STACK_LOCATION IrpSp,
  23. IN PVCB Vcb
  24. );
  25. NTSTATUS
  26. RawUserFsCtrl (
  27. IN PIO_STACK_LOCATION IrpSp,
  28. IN PVCB Vcb
  29. );
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, RawMountVolume)
  32. #pragma alloc_text(PAGE, RawUserFsCtrl)
  33. #pragma alloc_text(PAGE, RawFileSystemControl)
  34. #endif
  35. NTSTATUS
  36. RawFileSystemControl (
  37. IN PVCB Vcb,
  38. IN PIRP Irp,
  39. IN PIO_STACK_LOCATION IrpSp
  40. )
  41. /*++
  42. Routine Description:
  43. This routine implements the FileSystem control operations
  44. Arguments:
  45. Vcb - Supplies the volume being queried.
  46. Irp - Supplies the Irp being processed.
  47. IrpSp - Supplies parameters describing the FileSystem control operation.
  48. Return Value:
  49. NTSTATUS - The status for the IRP
  50. --*/
  51. {
  52. NTSTATUS Status;
  53. PAGED_CODE();
  54. //
  55. // We know this is a file system control so we'll case on the
  56. // minor function, and call an internal worker routine.
  57. //
  58. switch (IrpSp->MinorFunction) {
  59. case IRP_MN_USER_FS_REQUEST:
  60. Status = RawUserFsCtrl( IrpSp, Vcb );
  61. break;
  62. case IRP_MN_MOUNT_VOLUME:
  63. Status = RawMountVolume( IrpSp );
  64. break;
  65. case IRP_MN_VERIFY_VOLUME:
  66. Status = RawVerifyVolume( IrpSp, Vcb );
  67. break;
  68. default:
  69. Status = STATUS_INVALID_DEVICE_REQUEST;
  70. break;
  71. }
  72. RawCompleteRequest( Irp, Status );
  73. return Status;
  74. }
  75. //
  76. // Local Support Routine
  77. //
  78. NTSTATUS
  79. RawMountVolume (
  80. IN PIO_STACK_LOCATION IrpSp
  81. )
  82. /*++
  83. Routine Description:
  84. This routine performs the mount volume operation.
  85. Arguments:
  86. IrpSp - Supplies the IrpSp parameters to process
  87. Return Value:
  88. NTSTATUS - The return status for the operation
  89. --*/
  90. {
  91. NTSTATUS Status;
  92. PDEVICE_OBJECT DeviceObjectWeTalkTo;
  93. PVOLUME_DEVICE_OBJECT VolumeDeviceObject;
  94. PAGED_CODE();
  95. //
  96. // Save some references to make our life a little easier
  97. //
  98. DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject;
  99. //
  100. // A mount operation has been requested. Create a
  101. // new device object to represent this volume.
  102. //
  103. Status = IoCreateDevice( IrpSp->DeviceObject->DriverObject,
  104. sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  105. NULL,
  106. FILE_DEVICE_DISK_FILE_SYSTEM,
  107. 0,
  108. FALSE,
  109. (PDEVICE_OBJECT *)&VolumeDeviceObject );
  110. if ( !NT_SUCCESS( Status ) ) {
  111. return Status;
  112. }
  113. //
  114. // Our alignment requirement is the larger of the processor alignment requirement
  115. // already in the volume device object and that in the DeviceObjectWeTalkTo
  116. //
  117. if (DeviceObjectWeTalkTo->AlignmentRequirement > VolumeDeviceObject->DeviceObject.AlignmentRequirement) {
  118. VolumeDeviceObject->DeviceObject.AlignmentRequirement = DeviceObjectWeTalkTo->AlignmentRequirement;
  119. }
  120. //
  121. // Set sector size to the same value as the DeviceObjectWeTalkTo.
  122. //
  123. VolumeDeviceObject->DeviceObject.SectorSize = DeviceObjectWeTalkTo->SectorSize;
  124. VolumeDeviceObject->DeviceObject.Flags |= DO_DIRECT_IO;
  125. //
  126. // Initialize the Vcb for this volume
  127. //
  128. Status = RawInitializeVcb( &VolumeDeviceObject->Vcb,
  129. IrpSp->Parameters.MountVolume.DeviceObject,
  130. IrpSp->Parameters.MountVolume.Vpb );
  131. if ( !NT_SUCCESS( Status ) ) {
  132. //
  133. // Unlike the other points of teardown we do not need to deref the target device
  134. // a iosubsys will automatically do that for a failed mount
  135. //
  136. IoDeleteDevice( (PDEVICE_OBJECT)VolumeDeviceObject );
  137. return Status;
  138. }
  139. //
  140. // Finally, make it look as if the volume has been
  141. // mounted. This includes storing the
  142. // address of this file system's device object (the one
  143. // that was created to handle this volume) in the VPB so
  144. // all requests are directed to this file system from
  145. // now until the volume is initialized with a real file
  146. // structure.
  147. //
  148. VolumeDeviceObject->Vcb.Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDeviceObject;
  149. VolumeDeviceObject->Vcb.Vpb->SerialNumber = 0xFFFFFFFF;
  150. VolumeDeviceObject->Vcb.Vpb->VolumeLabelLength = 0;
  151. VolumeDeviceObject->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
  152. VolumeDeviceObject->DeviceObject.StackSize = (UCHAR) (DeviceObjectWeTalkTo->StackSize + 1);
  153. {
  154. PFILE_OBJECT VolumeFileObject;
  155. //
  156. // We need a file object to do the notification.
  157. //
  158. VolumeFileObject = IoCreateStreamFileObjectLite( NULL, &VolumeDeviceObject->DeviceObject );
  159. //
  160. // We need to bump the count up 2 now so that the close we do in a few lines
  161. // doesn't make the Vcb go away now.
  162. //
  163. VolumeDeviceObject->Vcb.OpenCount += 2;
  164. FsRtlNotifyVolumeEvent( VolumeFileObject, FSRTL_VOLUME_MOUNT );
  165. ObDereferenceObject( VolumeFileObject );
  166. //
  167. // Okay, the close is over, now we can safely decrement the open count again
  168. // (back to 0) so the Vcb can go away when we're really done with it.
  169. //
  170. VolumeDeviceObject->Vcb.OpenCount -= 2;
  171. }
  172. return Status;
  173. }
  174. //
  175. // Local Support Routine
  176. //
  177. NTSTATUS
  178. RawVerifyVolume (
  179. IN PIO_STACK_LOCATION IrpSp,
  180. IN PVCB Vcb
  181. )
  182. /*++
  183. Routine Description:
  184. This routine verifies a volume.
  185. Arguments:
  186. IrpSp - Supplies the IrpSp parameters to process
  187. Return Value:
  188. NTSTATUS - The return status for the operation
  189. --*/
  190. {
  191. NTSTATUS Status;
  192. BOOLEAN DeleteVolume = FALSE;
  193. KIRQL Irql;
  194. PVPB vpb;
  195. BOOLEAN Mounted;
  196. //
  197. // If the volume is somehow stale, dismount. We must synchronize
  198. // our inspection of the close count so we don't rip the volume up
  199. // while racing with a close, for instance. The VPB refcount drops
  200. // *before* the close comes into the filesystem.
  201. //
  202. //
  203. // By this time its possible that the volume has been dismounted by
  204. // RawClose. So check if its mounted. If so, take a reference on the VPB
  205. // The reference on the VPB will prevent close from deleting the device.
  206. //
  207. IoAcquireVpbSpinLock(&Irql);
  208. Mounted = FALSE;
  209. vpb = IrpSp->Parameters.VerifyVolume.Vpb;
  210. if (vpb->Flags & VPB_MOUNTED) {
  211. vpb->ReferenceCount++;
  212. Mounted = TRUE;
  213. }
  214. IoReleaseVpbSpinLock(Irql);
  215. if (!Mounted) {
  216. return STATUS_WRONG_VOLUME;
  217. }
  218. Status = KeWaitForSingleObject( &Vcb->Mutex,
  219. Executive,
  220. KernelMode,
  221. FALSE,
  222. (PLARGE_INTEGER) NULL );
  223. ASSERT( NT_SUCCESS( Status ) );
  224. //
  225. // Since we ignore all verify errors from the disk driver itself,
  226. // this request must have originated from a file system, thus
  227. // since we weren't the originators, we're going to say this isn't
  228. // our volume, and if the open count is zero, dismount the volume.
  229. //
  230. IoAcquireVpbSpinLock(&Irql);
  231. vpb->ReferenceCount--;
  232. IoReleaseVpbSpinLock(Irql);
  233. Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
  234. if (Vcb->OpenCount == 0) {
  235. DeleteVolume = RawCheckForDismount( Vcb, FALSE );
  236. }
  237. if (!DeleteVolume) {
  238. (VOID)KeReleaseMutex( &Vcb->Mutex, FALSE );
  239. }
  240. return STATUS_WRONG_VOLUME;
  241. }
  242. //
  243. // Local Support Routine
  244. //
  245. NTSTATUS
  246. RawUserFsCtrl (
  247. IN PIO_STACK_LOCATION IrpSp,
  248. IN PVCB Vcb
  249. )
  250. /*++
  251. Routine Description:
  252. This is the common routine for implementing the user's requests made
  253. through NtFsControlFile.
  254. Arguments:
  255. IrpSp - Supplies the IrpSp parameters to process
  256. Vcb - Supplies the volume we are working on.
  257. Return Value:
  258. NTSTATUS - The return status for the operation
  259. --*/
  260. {
  261. NTSTATUS Status;
  262. ULONG FsControlCode;
  263. PFILE_OBJECT FileObject;
  264. PAGED_CODE();
  265. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  266. FileObject = IrpSp->FileObject;
  267. //
  268. // Do pre-notification before entering the volume mutex so that we
  269. // can be reentered by good threads cleaning up their resources.
  270. //
  271. switch (FsControlCode) {
  272. case FSCTL_LOCK_VOLUME:
  273. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK );
  274. break;
  275. case FSCTL_DISMOUNT_VOLUME:
  276. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT );
  277. break;
  278. default:
  279. break;
  280. }
  281. Status = KeWaitForSingleObject( &Vcb->Mutex,
  282. Executive,
  283. KernelMode,
  284. FALSE,
  285. (PLARGE_INTEGER) NULL );
  286. ASSERT( NT_SUCCESS( Status ) );
  287. switch ( FsControlCode ) {
  288. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  289. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  290. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  291. case FSCTL_OPLOCK_BREAK_NOTIFY:
  292. Status = STATUS_NOT_IMPLEMENTED;
  293. break;
  294. case FSCTL_LOCK_VOLUME:
  295. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) &&
  296. (Vcb->OpenCount == 1) ) {
  297. Vcb->VcbState |= VCB_STATE_FLAG_LOCKED;
  298. Status = STATUS_SUCCESS;
  299. } else {
  300. Status = STATUS_ACCESS_DENIED;
  301. }
  302. break;
  303. case FSCTL_UNLOCK_VOLUME:
  304. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) ) {
  305. Status = STATUS_NOT_LOCKED;
  306. } else {
  307. Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
  308. Status = STATUS_SUCCESS;
  309. }
  310. break;
  311. case FSCTL_DISMOUNT_VOLUME:
  312. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
  313. Vcb->VcbState |= VCB_STATE_FLAG_DISMOUNTED;
  314. Status = STATUS_SUCCESS;
  315. } else {
  316. Status = STATUS_ACCESS_DENIED;
  317. }
  318. break;
  319. default:
  320. Status = STATUS_INVALID_PARAMETER;
  321. break;
  322. }
  323. (VOID)KeReleaseMutex( &Vcb->Mutex, FALSE );
  324. //
  325. // Now perform post-notification as required.
  326. //
  327. if (NT_SUCCESS( Status )) {
  328. switch ( FsControlCode ) {
  329. case FSCTL_UNLOCK_VOLUME:
  330. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
  331. break;
  332. default:
  333. break;
  334. }
  335. } else {
  336. switch ( FsControlCode ) {
  337. case FSCTL_LOCK_VOLUME:
  338. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK_FAILED );
  339. break;
  340. case FSCTL_DISMOUNT_VOLUME:
  341. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
  342. break;
  343. default:
  344. break;
  345. }
  346. }
  347. return Status;
  348. }