Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / reiserfs / src / blockio.c
1 /*
2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
4 * FILE: blockio.c
5 * PURPOSE:
6 * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
7 * HOMEPAGE:
8 * UPDATE HISTORY:
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "rfsd.h"
14
15 /* GLOBALS ***************************************************************/
16
17 extern PRFSD_GLOBAL RfsdGlobal;
18
19 /* DEFINITIONS *************************************************************/
20
21 typedef struct _RFSD_RW_CONTEXT {
22 PIRP MasterIrp;
23 KEVENT Event;
24 BOOLEAN Wait;
25 ULONG Blocks;
26 ULONG Length;
27 } RFSD_RW_CONTEXT, *PRFSD_RW_CONTEXT;
28
29 #ifdef _PREFAST_
30 IO_COMPLETION_ROUTINE RfsdReadWriteBlockSyncCompletionRoutine;
31 IO_COMPLETION_ROUTINE RfsdReadWriteBlockAsyncCompletionRoutine;
32 IO_COMPLETION_ROUTINE RfsdMediaEjectControlCompletion;
33 #endif // _PREFAST_
34
35 NTSTATUS NTAPI
36 RfsdReadWriteBlockSyncCompletionRoutine (
37 IN PDEVICE_OBJECT DeviceObject,
38 IN PIRP Irp,
39 IN PVOID Context );
40
41 NTSTATUS NTAPI
42 RfsdReadWriteBlockAsyncCompletionRoutine (
43 IN PDEVICE_OBJECT DeviceObject,
44 IN PIRP Irp,
45 IN PVOID Context );
46
47 NTSTATUS NTAPI
48 RfsdMediaEjectControlCompletion (
49 IN PDEVICE_OBJECT DeviceObject,
50 IN PIRP Irp,
51 IN PVOID Contxt );
52
53 #ifdef ALLOC_PRAGMA
54 #pragma alloc_text(PAGE, RfsdLockUserBuffer)
55 #pragma alloc_text(PAGE, RfsdGetUserBuffer)
56 #pragma alloc_text(PAGE, RfsdReadSync)
57 #pragma alloc_text(PAGE, RfsdReadDisk)
58 #pragma alloc_text(PAGE, RfsdDiskIoControl)
59 #pragma alloc_text(PAGE, RfsdReadWriteBlocks)
60 #pragma alloc_text(PAGE, RfsdMediaEjectControl)
61 #pragma alloc_text(PAGE, RfsdDiskShutDown)
62 #endif
63
64 /* FUNCTIONS ***************************************************************/
65
66 NTSTATUS
67 RfsdLockUserBuffer (IN PIRP Irp,
68 IN ULONG Length,
69 IN LOCK_OPERATION Operation)
70 {
71 NTSTATUS Status;
72
73 PAGED_CODE();
74
75 ASSERT(Irp != NULL);
76
77 if (Irp->MdlAddress != NULL) {
78
79 return STATUS_SUCCESS;
80 }
81
82 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
83
84 if (Irp->MdlAddress == NULL) {
85
86 return STATUS_INSUFFICIENT_RESOURCES;
87 }
88
89 _SEH2_TRY {
90
91 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
92
93 Status = STATUS_SUCCESS;
94 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
95
96 IoFreeMdl(Irp->MdlAddress);
97
98 Irp->MdlAddress = NULL;
99
100 DbgBreak();
101
102 Status = STATUS_INVALID_USER_BUFFER;
103 } _SEH2_END;
104
105 return Status;
106 }
107
108 PVOID
109 RfsdGetUserBuffer (IN PIRP Irp )
110 {
111 PAGED_CODE();
112
113 ASSERT(Irp != NULL);
114
115 if (Irp->MdlAddress) {
116
117 #if (_WIN32_WINNT >= 0x0500)
118 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
119 #else
120 return MmGetSystemAddressForMdl(Irp->MdlAddress);
121 #endif
122 } else {
123
124 return Irp->UserBuffer;
125 }
126 }
127
128 NTSTATUS NTAPI
129 RfsdReadWriteBlockSyncCompletionRoutine (
130 IN PDEVICE_OBJECT DeviceObject,
131 IN PIRP Irp,
132 IN PVOID Context )
133 {
134 PRFSD_RW_CONTEXT pContext = (PRFSD_RW_CONTEXT)Context;
135
136 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
137 DbgBreak(); // [mark]
138 pContext->MasterIrp->IoStatus = Irp->IoStatus;
139 }
140
141 IoFreeMdl( Irp->MdlAddress );
142 IoFreeIrp( Irp );
143
144 if (InterlockedDecrement(&pContext->Blocks) == 0) {
145
146 pContext->MasterIrp->IoStatus.Information = 0;
147
148 if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status)) {
149
150 pContext->MasterIrp->IoStatus.Information =
151 pContext->Length;
152 }
153
154 KeSetEvent( &pContext->Event, 0, FALSE );
155 }
156
157 UNREFERENCED_PARAMETER( DeviceObject );
158
159 return STATUS_MORE_PROCESSING_REQUIRED;
160 }
161
162 NTSTATUS NTAPI
163 RfsdReadWriteBlockAsyncCompletionRoutine (
164 IN PDEVICE_OBJECT DeviceObject,
165 IN PIRP Irp,
166 IN PVOID Context
167 )
168 {
169 PRFSD_RW_CONTEXT pContext = (PRFSD_RW_CONTEXT)Context;
170
171 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
172 DbgBreak(); // [mark]
173 pContext->MasterIrp->IoStatus = Irp->IoStatus;
174 }
175
176 if (InterlockedDecrement(&pContext->Blocks) == 0) {
177
178 pContext->MasterIrp->IoStatus.Information = 0;
179
180 if (NT_SUCCESS(pContext->MasterIrp->IoStatus.Status)) {
181
182 pContext->MasterIrp->IoStatus.Information =
183 pContext->Length;
184 }
185
186 IoMarkIrpPending( pContext->MasterIrp );
187
188 ExFreePool(pContext);
189 }
190
191 UNREFERENCED_PARAMETER( DeviceObject );
192
193 return STATUS_SUCCESS;
194 }
195
196 // Looks like this is really just getting an MDL (memory descriptor list) from the MM and doing its business...
197 // ... but IoCallDriver is what will actually read from the disk device to furnish non-chached or paging IO operations!
198 // NOTE: It is vital that IoCallDriver use sector-aligned offset and length (otherwise, 0xc000000d = STATUS_INVALID_PARAMETER) will result!
199 NTSTATUS
200 RfsdReadWriteBlocks(
201 IN PRFSD_IRP_CONTEXT IrpContext,
202 IN PRFSD_VCB Vcb,
203 IN PRFSD_BDL RfsdBDL, // The block-description list
204 IN ULONG Length, // Length of data to read
205 IN ULONG Count, // Count of blocks inside the BDL
206 IN BOOLEAN bVerify )
207 {
208 PMDL Mdl;
209 PIRP Irp;
210 PIRP MasterIrp = IrpContext->Irp;
211 PIO_STACK_LOCATION IrpSp;
212 NTSTATUS Status = STATUS_SUCCESS;
213 PRFSD_RW_CONTEXT pContext = NULL;
214 ULONG i;
215 BOOLEAN bBugCheck = FALSE;
216
217 PAGED_CODE();
218
219 ASSERT(MasterIrp);
220
221 _SEH2_TRY {
222
223 pContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(RFSD_RW_CONTEXT), RFSD_POOL_TAG);
224
225 if (!pContext) {
226 Status = STATUS_INSUFFICIENT_RESOURCES;
227 _SEH2_LEAVE;
228 }
229
230 RtlZeroMemory(pContext, sizeof(RFSD_RW_CONTEXT));
231
232 pContext->Wait = IrpContext->IsSynchronous;
233 pContext->MasterIrp = MasterIrp;
234 pContext->Blocks = Count;
235 pContext->Length = 0;
236
237 if (pContext->Wait) {
238 KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE);
239 }
240
241 for (i = 0; i < Count; i++) {
242
243 Irp = IoMakeAssociatedIrp(
244 MasterIrp,
245 (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );
246
247 if (!Irp) {
248 Status = STATUS_INSUFFICIENT_RESOURCES;
249 _SEH2_LEAVE;
250 }
251
252 Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
253 RfsdBDL[i].Offset,
254 RfsdBDL[i].Length,
255 FALSE,
256 FALSE,
257 Irp );
258
259 if (!Mdl) {
260 Status = STATUS_INSUFFICIENT_RESOURCES;
261 _SEH2_LEAVE;
262 }
263
264 IoBuildPartialMdl( MasterIrp->MdlAddress,
265 Mdl,
266 (PCHAR)MasterIrp->UserBuffer + RfsdBDL[i].Offset,
267 RfsdBDL[i].Length );
268
269 IoSetNextIrpStackLocation( Irp );
270 IrpSp = IoGetCurrentIrpStackLocation( Irp );
271
272
273 IrpSp->MajorFunction = IrpContext->MajorFunction;
274 IrpSp->Parameters.Read.Length = RfsdBDL[i].Length;
275 IrpSp->Parameters.Read.ByteOffset.QuadPart = RfsdBDL[i].Lba;
276
277 IoSetCompletionRoutine(
278 Irp,
279 ((IrpContext->IsSynchronous) ?
280 (&RfsdReadWriteBlockSyncCompletionRoutine) :
281 (&RfsdReadWriteBlockAsyncCompletionRoutine)),
282 (PVOID) pContext,
283 TRUE,
284 TRUE,
285 TRUE );
286
287 IrpSp = IoGetNextIrpStackLocation( Irp );
288
289 IrpSp->MajorFunction = IrpContext->MajorFunction;
290 IrpSp->Parameters.Read.Length = RfsdBDL[i].Length;
291 IrpSp->Parameters.Read.ByteOffset.QuadPart = RfsdBDL[i].Lba;
292
293 if (bVerify) {
294 SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
295 }
296
297 RfsdBDL[i].Irp = Irp;
298 }
299
300 MasterIrp->AssociatedIrp.IrpCount = Count;
301
302 if (IrpContext->IsSynchronous) {
303 MasterIrp->AssociatedIrp.IrpCount += 1;
304 }
305
306 pContext->Length = Length;
307
308 bBugCheck = TRUE;
309
310 for (i = 0; i < Count; i++) {
311 Status = IoCallDriver ( Vcb->TargetDeviceObject,
312 RfsdBDL[i].Irp);
313 }
314
315 if (IrpContext->IsSynchronous) {
316 KeWaitForSingleObject( &(pContext->Event),
317 Executive, KernelMode, FALSE, NULL );
318
319 KeClearEvent( &(pContext->Event) );
320 }
321
322 } _SEH2_FINALLY {
323
324 if (IrpContext->IsSynchronous) {
325 if (MasterIrp)
326 Status = MasterIrp->IoStatus.Status;
327
328 if (pContext)
329 ExFreePool(pContext);
330
331 } else {
332 IrpContext->Irp = NULL;
333 Status = STATUS_PENDING;
334 }
335
336 if (_SEH2_AbnormalTermination()) {
337 if (bBugCheck) {
338 RfsdBugCheck(RFSD_BUGCHK_BLOCK, 0, 0, 0);
339 }
340
341 for (i = 0; i < Count; i++) {
342 if (RfsdBDL[i].Irp != NULL ) {
343 if ( RfsdBDL[i].Irp->MdlAddress != NULL ) {
344 IoFreeMdl( RfsdBDL[i].Irp->MdlAddress );
345 }
346
347 IoFreeIrp( RfsdBDL[i].Irp );
348 }
349 }
350 }
351 } _SEH2_END;
352
353 return Status;
354 }
355
356 NTSTATUS
357 RfsdReadSync(
358 IN PRFSD_VCB Vcb,
359 IN ULONGLONG Offset,
360 IN ULONG Length,
361 OUT PVOID Buffer,
362 BOOLEAN bVerify
363 )
364 {
365 PKEVENT Event = NULL;
366 PIRP Irp;
367 IO_STATUS_BLOCK IoStatus;
368 NTSTATUS Status;
369
370 PAGED_CODE();
371
372 ASSERT(Vcb != NULL);
373 ASSERT(Vcb->TargetDeviceObject != NULL);
374 ASSERT(Buffer != NULL);
375
376 _SEH2_TRY {
377
378 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), RFSD_POOL_TAG);
379
380 if (NULL == Event) {
381 _SEH2_LEAVE;
382 }
383
384 KeInitializeEvent(Event, NotificationEvent, FALSE);
385
386 Irp = IoBuildSynchronousFsdRequest(
387 IRP_MJ_READ,
388 Vcb->TargetDeviceObject,
389 Buffer,
390 Length,
391 (PLARGE_INTEGER)(&Offset),
392 Event,
393 &IoStatus
394 );
395
396 if (!Irp) {
397 Status = STATUS_INSUFFICIENT_RESOURCES;
398 _SEH2_LEAVE;
399 }
400
401 if (bVerify) {
402 SetFlag( IoGetNextIrpStackLocation(Irp)->Flags,
403 SL_OVERRIDE_VERIFY_VOLUME );
404 }
405
406 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
407
408 if (Status == STATUS_PENDING) {
409 KeWaitForSingleObject(
410 Event,
411 Suspended,
412 KernelMode,
413 FALSE,
414 NULL
415 );
416
417 Status = IoStatus.Status;
418 }
419
420 } _SEH2_FINALLY {
421
422 if (Event) {
423 ExFreePool(Event);
424 }
425 } _SEH2_END;
426
427 return Status;
428 }
429
430 NTSTATUS
431 RfsdReadDisk(
432 IN PRFSD_VCB Vcb,
433 IN ULONGLONG Offset, // Byte offset (relative to disk) to read from (need not be sector-aligned!)
434 IN ULONG Size,
435 IN OUT PVOID Buffer,
436 IN BOOLEAN bVerify ) // True if the volume should be verified before reading
437 {
438 NTSTATUS Status;
439 PUCHAR Buf;
440 ULONG Length;
441 ULONGLONG Lba;
442
443 PAGED_CODE();
444
445 // Align the offset and length to the sector boundaries
446 Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
447 Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) &
448 (~((ULONG)SECTOR_SIZE - 1));
449
450 // Allocate a temporary buffer to read the sector-aligned data into
451 Buf = ExAllocatePoolWithTag(PagedPool, Length, RFSD_POOL_TAG);
452 if (!Buf) {
453 RfsdPrint((DBG_ERROR, "RfsdReadDisk: no enough memory.\n"));
454 Status = STATUS_INSUFFICIENT_RESOURCES;
455
456 goto errorout;
457 }
458
459 // Read the data
460 Status = RfsdReadSync( Vcb,
461 Lba,
462 Length,
463 Buf,
464 FALSE );
465
466 if (!NT_SUCCESS(Status)) {
467 RfsdPrint((DBG_ERROR, "RfsdReadDisk: Read Block Device error.\n"));
468
469 goto errorout;
470 }
471
472 // Copy the requested data into the user's buffer
473 RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size);
474
475 errorout:
476
477 if (Buf)
478 ExFreePool(Buf);
479
480 return Status;
481 }
482
483 NTSTATUS
484 RfsdDiskIoControl (
485 IN PDEVICE_OBJECT DeviceObject,
486 IN ULONG IoctlCode,
487 IN PVOID InputBuffer,
488 IN ULONG InputBufferSize,
489 IN OUT PVOID OutputBuffer,
490 IN OUT PULONG OutputBufferSize)
491 {
492 ULONG OutBufferSize = 0;
493 KEVENT Event;
494 PIRP Irp;
495 IO_STATUS_BLOCK IoStatus;
496 NTSTATUS Status;
497
498 PAGED_CODE();
499
500 ASSERT(DeviceObject != NULL);
501
502 if (OutputBufferSize)
503 {
504 OutBufferSize = *OutputBufferSize;
505 }
506
507 KeInitializeEvent(&Event, NotificationEvent, FALSE);
508
509 Irp = IoBuildDeviceIoControlRequest(
510 IoctlCode,
511 DeviceObject,
512 InputBuffer,
513 InputBufferSize,
514 OutputBuffer,
515 OutBufferSize,
516 FALSE,
517 &Event,
518 &IoStatus
519 );
520
521 if (Irp == NULL) {
522 RfsdPrint((DBG_ERROR, "RfsdDiskIoControl: Building IRQ error!\n"));
523 return STATUS_INSUFFICIENT_RESOURCES;
524 }
525
526 Status = IoCallDriver(DeviceObject, Irp);
527
528 if (Status == STATUS_PENDING) {
529 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
530 Status = IoStatus.Status;
531 }
532
533 if (OutputBufferSize) {
534 *OutputBufferSize = (ULONG) IoStatus.Information;
535 }
536
537 return Status;
538 }
539
540 NTSTATUS NTAPI
541 RfsdMediaEjectControlCompletion (
542 IN PDEVICE_OBJECT DeviceObject,
543 IN PIRP Irp,
544 IN PVOID Contxt
545 )
546 {
547 PKEVENT Event = (PKEVENT)Contxt;
548
549 KeSetEvent( Event, 0, FALSE );
550
551 UNREFERENCED_PARAMETER( DeviceObject );
552
553 return STATUS_SUCCESS;
554 }
555
556 __drv_mustHoldCriticalRegion
557 VOID
558 RfsdMediaEjectControl (
559 IN PRFSD_IRP_CONTEXT IrpContext,
560 IN PRFSD_VCB Vcb,
561 IN BOOLEAN bPrevent
562 )
563 {
564 PIRP Irp;
565 KEVENT Event;
566 NTSTATUS Status;
567 PREVENT_MEDIA_REMOVAL Prevent;
568 IO_STATUS_BLOCK IoStatus;
569
570 PAGED_CODE();
571
572 ExAcquireResourceExclusiveLite(
573 &Vcb->MainResource,
574 TRUE );
575
576 if (bPrevent != IsFlagOn(Vcb->Flags, VCB_REMOVAL_PREVENTED)) {
577 if (bPrevent) {
578 SetFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
579 } else {
580 ClearFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
581 }
582 }
583
584 ExReleaseResourceForThreadLite(
585 &Vcb->MainResource,
586 ExGetCurrentResourceThread());
587
588 Prevent.PreventMediaRemoval = bPrevent;
589
590 KeInitializeEvent( &Event, NotificationEvent, FALSE );
591
592 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
593 Vcb->TargetDeviceObject,
594 &Prevent,
595 sizeof(PREVENT_MEDIA_REMOVAL),
596 NULL,
597 0,
598 FALSE,
599 NULL,
600 &IoStatus );
601
602 if (Irp != NULL) {
603 IoSetCompletionRoutine( Irp,
604 RfsdMediaEjectControlCompletion,
605 &Event,
606 TRUE,
607 TRUE,
608 TRUE );
609
610 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
611
612 if (Status == STATUS_PENDING) {
613 Status = KeWaitForSingleObject( &Event,
614 Executive,
615 KernelMode,
616 FALSE,
617 NULL );
618 }
619 }
620 }
621
622 NTSTATUS
623 RfsdDiskShutDown(PRFSD_VCB Vcb)
624 {
625 PIRP Irp;
626 KEVENT Event;
627 NTSTATUS Status;
628 IO_STATUS_BLOCK IoStatus;
629
630 PAGED_CODE();
631
632 KeInitializeEvent(&Event, NotificationEvent, FALSE);
633
634 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
635 Vcb->TargetDeviceObject,
636 NULL,
637 0,
638 NULL,
639 &Event,
640 &IoStatus);
641
642 if (Irp) {
643 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
644
645 if (Status == STATUS_PENDING) {
646 KeWaitForSingleObject(&Event,
647 Executive,
648 KernelMode,
649 FALSE,
650 NULL);
651
652 Status = IoStatus.Status;
653 }
654 } else {
655 Status = IoStatus.Status;
656 }
657
658 return Status;
659 }