Leaked source code of windows server 2003
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.

534 lines
12 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 = NULL;
  155. //
  156. // We need a file object to do the notification.
  157. //
  158. try {
  159. VolumeFileObject = IoCreateStreamFileObjectLite( NULL, &VolumeDeviceObject->DeviceObject );
  160. } except (EXCEPTION_EXECUTE_HANDLER) {
  161. Status = GetExceptionCode();
  162. }
  163. if (!NT_SUCCESS(Status)) {
  164. IoDeleteDevice( (PDEVICE_OBJECT)VolumeDeviceObject );
  165. return Status;
  166. }
  167. //
  168. // We need to bump the count up 2 now so that the close we do in a few lines
  169. // doesn't make the Vcb go away now.
  170. //
  171. VolumeDeviceObject->Vcb.OpenCount += 2;
  172. FsRtlNotifyVolumeEvent( VolumeFileObject, FSRTL_VOLUME_MOUNT );
  173. ObDereferenceObject( VolumeFileObject );
  174. //
  175. // Okay, the close is over, now we can safely decrement the open count again
  176. // (back to 0) so the Vcb can go away when we're really done with it.
  177. //
  178. VolumeDeviceObject->Vcb.OpenCount -= 2;
  179. }
  180. return Status;
  181. }
  182. //
  183. // Local Support Routine
  184. //
  185. NTSTATUS
  186. RawVerifyVolume (
  187. IN PIO_STACK_LOCATION IrpSp,
  188. IN PVCB Vcb
  189. )
  190. /*++
  191. Routine Description:
  192. This routine verifies a volume.
  193. Arguments:
  194. IrpSp - Supplies the IrpSp parameters to process
  195. Return Value:
  196. NTSTATUS - The return status for the operation
  197. --*/
  198. {
  199. NTSTATUS Status;
  200. BOOLEAN DeleteVolume = FALSE;
  201. KIRQL Irql;
  202. PVPB vpb;
  203. BOOLEAN Mounted;
  204. //
  205. // If the volume is somehow stale, dismount. We must synchronize
  206. // our inspection of the close count so we don't rip the volume up
  207. // while racing with a close, for instance. The VPB refcount drops
  208. // *before* the close comes into the filesystem.
  209. //
  210. //
  211. // By this time its possible that the volume has been dismounted by
  212. // RawClose. So check if its mounted. If so, take a reference on the VPB
  213. // The reference on the VPB will prevent close from deleting the device.
  214. //
  215. IoAcquireVpbSpinLock(&Irql);
  216. Mounted = FALSE;
  217. vpb = IrpSp->Parameters.VerifyVolume.Vpb;
  218. if (vpb->Flags & VPB_MOUNTED) {
  219. vpb->ReferenceCount++;
  220. Mounted = TRUE;
  221. }
  222. IoReleaseVpbSpinLock(Irql);
  223. if (!Mounted) {
  224. return STATUS_WRONG_VOLUME;
  225. }
  226. Status = KeWaitForSingleObject( &Vcb->Mutex,
  227. Executive,
  228. KernelMode,
  229. FALSE,
  230. (PLARGE_INTEGER) NULL );
  231. ASSERT( NT_SUCCESS( Status ) );
  232. //
  233. // Since we ignore all verify errors from the disk driver itself,
  234. // this request must have originated from a file system, thus
  235. // since we weren't the originators, we're going to say this isn't
  236. // our volume, and if the open count is zero, dismount the volume.
  237. //
  238. IoAcquireVpbSpinLock(&Irql);
  239. vpb->ReferenceCount--;
  240. IoReleaseVpbSpinLock(Irql);
  241. Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
  242. if (Vcb->OpenCount == 0) {
  243. DeleteVolume = RawCheckForDismount( Vcb, FALSE );
  244. }
  245. if (!DeleteVolume) {
  246. (VOID)KeReleaseMutex( &Vcb->Mutex, FALSE );
  247. }
  248. return STATUS_WRONG_VOLUME;
  249. }
  250. //
  251. // Local Support Routine
  252. //
  253. NTSTATUS
  254. RawUserFsCtrl (
  255. IN PIO_STACK_LOCATION IrpSp,
  256. IN PVCB Vcb
  257. )
  258. /*++
  259. Routine Description:
  260. This is the common routine for implementing the user's requests made
  261. through NtFsControlFile.
  262. Arguments:
  263. IrpSp - Supplies the IrpSp parameters to process
  264. Vcb - Supplies the volume we are working on.
  265. Return Value:
  266. NTSTATUS - The return status for the operation
  267. --*/
  268. {
  269. NTSTATUS Status;
  270. ULONG FsControlCode;
  271. PFILE_OBJECT FileObject;
  272. PAGED_CODE();
  273. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  274. FileObject = IrpSp->FileObject;
  275. //
  276. // Do pre-notification before entering the volume mutex so that we
  277. // can be reentered by good threads cleaning up their resources.
  278. //
  279. switch (FsControlCode) {
  280. case FSCTL_LOCK_VOLUME:
  281. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK );
  282. break;
  283. case FSCTL_DISMOUNT_VOLUME:
  284. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT );
  285. break;
  286. default:
  287. break;
  288. }
  289. Status = KeWaitForSingleObject( &Vcb->Mutex,
  290. Executive,
  291. KernelMode,
  292. FALSE,
  293. (PLARGE_INTEGER) NULL );
  294. ASSERT( NT_SUCCESS( Status ) );
  295. switch ( FsControlCode ) {
  296. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  297. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  298. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  299. case FSCTL_OPLOCK_BREAK_NOTIFY:
  300. Status = STATUS_NOT_IMPLEMENTED;
  301. break;
  302. case FSCTL_LOCK_VOLUME:
  303. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) &&
  304. (Vcb->OpenCount == 1) ) {
  305. Vcb->VcbState |= VCB_STATE_FLAG_LOCKED;
  306. Status = STATUS_SUCCESS;
  307. } else {
  308. Status = STATUS_ACCESS_DENIED;
  309. }
  310. break;
  311. case FSCTL_UNLOCK_VOLUME:
  312. if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) ) {
  313. Status = STATUS_NOT_LOCKED;
  314. } else {
  315. Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
  316. Status = STATUS_SUCCESS;
  317. }
  318. break;
  319. case FSCTL_DISMOUNT_VOLUME:
  320. //
  321. // Right now the logic in cleanup.c assumes that there can
  322. // only be one handle on the volume if locked. The code
  323. // there needs to be fixed if forced dismounts are allowed.
  324. //
  325. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
  326. Vcb->VcbState |= VCB_STATE_FLAG_DISMOUNTED;
  327. Status = STATUS_SUCCESS;
  328. } else {
  329. Status = STATUS_ACCESS_DENIED;
  330. }
  331. break;
  332. default:
  333. Status = STATUS_INVALID_PARAMETER;
  334. break;
  335. }
  336. (VOID)KeReleaseMutex( &Vcb->Mutex, FALSE );
  337. //
  338. // Now perform post-notification as required.
  339. //
  340. if (NT_SUCCESS( Status )) {
  341. switch ( FsControlCode ) {
  342. case FSCTL_UNLOCK_VOLUME:
  343. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
  344. break;
  345. default:
  346. break;
  347. }
  348. } else {
  349. switch ( FsControlCode ) {
  350. case FSCTL_LOCK_VOLUME:
  351. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_LOCK_FAILED );
  352. break;
  353. case FSCTL_DISMOUNT_VOLUME:
  354. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_DISMOUNT_FAILED );
  355. break;
  356. default:
  357. break;
  358. }
  359. }
  360. return Status;
  361. }