[REISERFS] Don't leak on failure
[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 #ifdef __REACTOS__
250 ExFreePool(pContext);
251 pContext = NULL;
252 #endif
253 _SEH2_LEAVE;
254 }
255
256 Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
257 RfsdBDL[i].Offset,
258 RfsdBDL[i].Length,
259 FALSE,
260 FALSE,
261 Irp );
262
263 if (!Mdl) {
264 Status = STATUS_INSUFFICIENT_RESOURCES;
265 #ifdef __REACTOS__
266 ExFreePool(pContext);
267 pContext = NULL;
268 #endif
269 _SEH2_LEAVE;
270 }
271
272 IoBuildPartialMdl( MasterIrp->MdlAddress,
273 Mdl,
274 (PCHAR)MasterIrp->UserBuffer + RfsdBDL[i].Offset,
275 RfsdBDL[i].Length );
276
277 IoSetNextIrpStackLocation( Irp );
278 IrpSp = IoGetCurrentIrpStackLocation( Irp );
279
280
281 IrpSp->MajorFunction = IrpContext->MajorFunction;
282 IrpSp->Parameters.Read.Length = RfsdBDL[i].Length;
283 IrpSp->Parameters.Read.ByteOffset.QuadPart = RfsdBDL[i].Lba;
284
285 IoSetCompletionRoutine(
286 Irp,
287 ((IrpContext->IsSynchronous) ?
288 (&RfsdReadWriteBlockSyncCompletionRoutine) :
289 (&RfsdReadWriteBlockAsyncCompletionRoutine)),
290 (PVOID) pContext,
291 TRUE,
292 TRUE,
293 TRUE );
294
295 IrpSp = IoGetNextIrpStackLocation( Irp );
296
297 IrpSp->MajorFunction = IrpContext->MajorFunction;
298 IrpSp->Parameters.Read.Length = RfsdBDL[i].Length;
299 IrpSp->Parameters.Read.ByteOffset.QuadPart = RfsdBDL[i].Lba;
300
301 if (bVerify) {
302 SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
303 }
304
305 RfsdBDL[i].Irp = Irp;
306 }
307
308 MasterIrp->AssociatedIrp.IrpCount = Count;
309
310 if (IrpContext->IsSynchronous) {
311 MasterIrp->AssociatedIrp.IrpCount += 1;
312 }
313
314 pContext->Length = Length;
315
316 bBugCheck = TRUE;
317
318 for (i = 0; i < Count; i++) {
319 Status = IoCallDriver ( Vcb->TargetDeviceObject,
320 RfsdBDL[i].Irp);
321 }
322
323 if (IrpContext->IsSynchronous) {
324 KeWaitForSingleObject( &(pContext->Event),
325 Executive, KernelMode, FALSE, NULL );
326
327 KeClearEvent( &(pContext->Event) );
328 }
329
330 } _SEH2_FINALLY {
331
332 if (IrpContext->IsSynchronous) {
333 if (MasterIrp)
334 Status = MasterIrp->IoStatus.Status;
335
336 if (pContext)
337 ExFreePool(pContext);
338
339 } else {
340 IrpContext->Irp = NULL;
341 Status = STATUS_PENDING;
342 }
343
344 if (_SEH2_AbnormalTermination()) {
345 if (bBugCheck) {
346 RfsdBugCheck(RFSD_BUGCHK_BLOCK, 0, 0, 0);
347 }
348
349 for (i = 0; i < Count; i++) {
350 if (RfsdBDL[i].Irp != NULL ) {
351 if ( RfsdBDL[i].Irp->MdlAddress != NULL ) {
352 IoFreeMdl( RfsdBDL[i].Irp->MdlAddress );
353 }
354
355 IoFreeIrp( RfsdBDL[i].Irp );
356 }
357 }
358 }
359 } _SEH2_END;
360
361 return Status;
362 }
363
364 NTSTATUS
365 RfsdReadSync(
366 IN PRFSD_VCB Vcb,
367 IN ULONGLONG Offset,
368 IN ULONG Length,
369 OUT PVOID Buffer,
370 BOOLEAN bVerify
371 )
372 {
373 PKEVENT Event = NULL;
374 PIRP Irp;
375 IO_STATUS_BLOCK IoStatus;
376 NTSTATUS Status;
377
378 PAGED_CODE();
379
380 ASSERT(Vcb != NULL);
381 ASSERT(Vcb->TargetDeviceObject != NULL);
382 ASSERT(Buffer != NULL);
383
384 _SEH2_TRY {
385
386 Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), RFSD_POOL_TAG);
387
388 if (NULL == Event) {
389 _SEH2_LEAVE;
390 }
391
392 KeInitializeEvent(Event, NotificationEvent, FALSE);
393
394 Irp = IoBuildSynchronousFsdRequest(
395 IRP_MJ_READ,
396 Vcb->TargetDeviceObject,
397 Buffer,
398 Length,
399 (PLARGE_INTEGER)(&Offset),
400 Event,
401 &IoStatus
402 );
403
404 if (!Irp) {
405 Status = STATUS_INSUFFICIENT_RESOURCES;
406 _SEH2_LEAVE;
407 }
408
409 if (bVerify) {
410 SetFlag( IoGetNextIrpStackLocation(Irp)->Flags,
411 SL_OVERRIDE_VERIFY_VOLUME );
412 }
413
414 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
415
416 if (Status == STATUS_PENDING) {
417 KeWaitForSingleObject(
418 Event,
419 Suspended,
420 KernelMode,
421 FALSE,
422 NULL
423 );
424
425 Status = IoStatus.Status;
426 }
427
428 } _SEH2_FINALLY {
429
430 if (Event) {
431 ExFreePool(Event);
432 }
433 } _SEH2_END;
434
435 return Status;
436 }
437
438 NTSTATUS
439 RfsdReadDisk(
440 IN PRFSD_VCB Vcb,
441 IN ULONGLONG Offset, // Byte offset (relative to disk) to read from (need not be sector-aligned!)
442 IN ULONG Size,
443 IN OUT PVOID Buffer,
444 IN BOOLEAN bVerify ) // True if the volume should be verified before reading
445 {
446 NTSTATUS Status;
447 PUCHAR Buf;
448 ULONG Length;
449 ULONGLONG Lba;
450
451 PAGED_CODE();
452
453 // Align the offset and length to the sector boundaries
454 Lba = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
455 Length = (ULONG)(Size + Offset + SECTOR_SIZE - 1 - Lba) &
456 (~((ULONG)SECTOR_SIZE - 1));
457
458 // Allocate a temporary buffer to read the sector-aligned data into
459 Buf = ExAllocatePoolWithTag(PagedPool, Length, RFSD_POOL_TAG);
460 if (!Buf) {
461 RfsdPrint((DBG_ERROR, "RfsdReadDisk: no enough memory.\n"));
462 Status = STATUS_INSUFFICIENT_RESOURCES;
463
464 goto errorout;
465 }
466
467 // Read the data
468 Status = RfsdReadSync( Vcb,
469 Lba,
470 Length,
471 Buf,
472 FALSE );
473
474 if (!NT_SUCCESS(Status)) {
475 RfsdPrint((DBG_ERROR, "RfsdReadDisk: Read Block Device error.\n"));
476
477 goto errorout;
478 }
479
480 // Copy the requested data into the user's buffer
481 RtlCopyMemory(Buffer, &Buf[Offset - Lba], Size);
482
483 errorout:
484
485 if (Buf)
486 ExFreePool(Buf);
487
488 return Status;
489 }
490
491 NTSTATUS
492 RfsdDiskIoControl (
493 IN PDEVICE_OBJECT DeviceObject,
494 IN ULONG IoctlCode,
495 IN PVOID InputBuffer,
496 IN ULONG InputBufferSize,
497 IN OUT PVOID OutputBuffer,
498 IN OUT PULONG OutputBufferSize)
499 {
500 ULONG OutBufferSize = 0;
501 KEVENT Event;
502 PIRP Irp;
503 IO_STATUS_BLOCK IoStatus;
504 NTSTATUS Status;
505
506 PAGED_CODE();
507
508 ASSERT(DeviceObject != NULL);
509
510 if (OutputBufferSize)
511 {
512 OutBufferSize = *OutputBufferSize;
513 }
514
515 KeInitializeEvent(&Event, NotificationEvent, FALSE);
516
517 Irp = IoBuildDeviceIoControlRequest(
518 IoctlCode,
519 DeviceObject,
520 InputBuffer,
521 InputBufferSize,
522 OutputBuffer,
523 OutBufferSize,
524 FALSE,
525 &Event,
526 &IoStatus
527 );
528
529 if (Irp == NULL) {
530 RfsdPrint((DBG_ERROR, "RfsdDiskIoControl: Building IRQ error!\n"));
531 return STATUS_INSUFFICIENT_RESOURCES;
532 }
533
534 Status = IoCallDriver(DeviceObject, Irp);
535
536 if (Status == STATUS_PENDING) {
537 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
538 Status = IoStatus.Status;
539 }
540
541 if (OutputBufferSize) {
542 *OutputBufferSize = (ULONG) IoStatus.Information;
543 }
544
545 return Status;
546 }
547
548 NTSTATUS NTAPI
549 RfsdMediaEjectControlCompletion (
550 IN PDEVICE_OBJECT DeviceObject,
551 IN PIRP Irp,
552 IN PVOID Contxt
553 )
554 {
555 PKEVENT Event = (PKEVENT)Contxt;
556
557 KeSetEvent( Event, 0, FALSE );
558
559 UNREFERENCED_PARAMETER( DeviceObject );
560
561 return STATUS_SUCCESS;
562 }
563
564 __drv_mustHoldCriticalRegion
565 VOID
566 RfsdMediaEjectControl (
567 IN PRFSD_IRP_CONTEXT IrpContext,
568 IN PRFSD_VCB Vcb,
569 IN BOOLEAN bPrevent
570 )
571 {
572 PIRP Irp;
573 KEVENT Event;
574 NTSTATUS Status;
575 PREVENT_MEDIA_REMOVAL Prevent;
576 IO_STATUS_BLOCK IoStatus;
577
578 PAGED_CODE();
579
580 ExAcquireResourceExclusiveLite(
581 &Vcb->MainResource,
582 TRUE );
583
584 if (bPrevent != IsFlagOn(Vcb->Flags, VCB_REMOVAL_PREVENTED)) {
585 if (bPrevent) {
586 SetFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
587 } else {
588 ClearFlag(Vcb->Flags, VCB_REMOVAL_PREVENTED);
589 }
590 }
591
592 ExReleaseResourceForThreadLite(
593 &Vcb->MainResource,
594 ExGetCurrentResourceThread());
595
596 Prevent.PreventMediaRemoval = bPrevent;
597
598 KeInitializeEvent( &Event, NotificationEvent, FALSE );
599
600 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
601 Vcb->TargetDeviceObject,
602 &Prevent,
603 sizeof(PREVENT_MEDIA_REMOVAL),
604 NULL,
605 0,
606 FALSE,
607 NULL,
608 &IoStatus );
609
610 if (Irp != NULL) {
611 IoSetCompletionRoutine( Irp,
612 RfsdMediaEjectControlCompletion,
613 &Event,
614 TRUE,
615 TRUE,
616 TRUE );
617
618 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
619
620 if (Status == STATUS_PENDING) {
621 Status = KeWaitForSingleObject( &Event,
622 Executive,
623 KernelMode,
624 FALSE,
625 NULL );
626 }
627 }
628 }
629
630 NTSTATUS
631 RfsdDiskShutDown(PRFSD_VCB Vcb)
632 {
633 PIRP Irp;
634 KEVENT Event;
635 NTSTATUS Status;
636 IO_STATUS_BLOCK IoStatus;
637
638 PAGED_CODE();
639
640 KeInitializeEvent(&Event, NotificationEvent, FALSE);
641
642 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
643 Vcb->TargetDeviceObject,
644 NULL,
645 0,
646 NULL,
647 &Event,
648 &IoStatus);
649
650 if (Irp) {
651 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
652
653 if (Status == STATUS_PENDING) {
654 KeWaitForSingleObject(&Event,
655 Executive,
656 KernelMode,
657 FALSE,
658 NULL);
659
660 Status = IoStatus.Status;
661 }
662 } else {
663 Status = IoStatus.Status;
664 }
665
666 return Status;
667 }