48ab9c354fabf88fa3113100b3bc121bc5723597
[reactos.git] / drivers / filesystems / fastfat_new / cachesup.c
1 /*++
2
3 Copyright (c) 1990-2000 Microsoft Corporation
4
5 Module Name:
6
7 cache.c
8
9 Abstract:
10
11 This module implements the cache management routines for the Fat
12 FSD and FSP, by calling the Common Cache Manager.
13
14
15 --*/
16
17 #include "fatprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (FAT_BUG_CHECK_CACHESUP)
24
25 //
26 // Local debug trace level
27 //
28
29 #define Dbg (DEBUG_TRACE_CACHESUP)
30
31 #if DBG
32
33 BOOLEAN
34 FatIsCurrentOperationSynchedForDcbTeardown (
35 IN PIRP_CONTEXT IrpContext,
36 IN PDCB Dcb
37 );
38
39 #endif
40
41 #ifdef ALLOC_PRAGMA
42 #pragma alloc_text(PAGE, FatCloseEaFile)
43 #pragma alloc_text(PAGE, FatCompleteMdl)
44 #pragma alloc_text(PAGE, FatOpenDirectoryFile)
45 #pragma alloc_text(PAGE, FatOpenEaFile)
46 #pragma alloc_text(PAGE, FatPinMappedData)
47 #pragma alloc_text(PAGE, FatPrepareWriteDirectoryFile)
48 #pragma alloc_text(PAGE, FatPrepareWriteVolumeFile)
49 #pragma alloc_text(PAGE, FatReadDirectoryFile)
50 #pragma alloc_text(PAGE, FatReadVolumeFile)
51 #pragma alloc_text(PAGE, FatRepinBcb)
52 #pragma alloc_text(PAGE, FatSyncUninitializeCacheMap)
53 #pragma alloc_text(PAGE, FatUnpinRepinnedBcbs)
54 #pragma alloc_text(PAGE, FatZeroData)
55 #if DBG
56 #pragma alloc_text(PAGE, FatIsCurrentOperationSynchedForDcbTeardown)
57 #endif
58 #endif
59
60 \f
61 VOID
62 FatReadVolumeFile (
63 IN PIRP_CONTEXT IrpContext,
64 IN PVCB Vcb,
65 IN VBO StartingVbo,
66 IN ULONG ByteCount,
67 OUT PBCB *Bcb,
68 OUT PVOID *Buffer
69 )
70
71 /*++
72
73 Routine Description:
74
75 This routine is called when the specified range of sectors is to be
76 read into the cache. In fat, the volume file only contains the boot
77 sector, reserved sectors, and the "fat(s)." Thus the volume file is
78 of fixed size and only extends up to (but not not including) the root
79 directory entry, and will never move or change size.
80
81 The fat volume file is also peculiar in that, since it starts at the
82 logical beginning of the disk, Vbo == Lbo.
83
84 Arguments:
85
86 Vcb - Pointer to the VCB for the volume
87
88 StartingVbo - The virtual offset of the first desired byte
89
90 ByteCount - Number of bytes desired
91
92 Bcb - Returns a pointer to the BCB which is valid until unpinned
93
94 Buffer - Returns a pointer to the sectors, which is valid until unpinned
95
96 --*/
97
98 {
99 LARGE_INTEGER Vbo;
100
101 PAGED_CODE();
102
103 //
104 // Check to see that all references are within the Bios Parameter Block
105 // or the fat(s). A special case is made when StartingVbo == 0 at
106 // mounting time since we do not know how big the fat is.
107 //
108
109 ASSERT( ((StartingVbo == 0) || ((StartingVbo + ByteCount) <= (ULONG)
110 (FatRootDirectoryLbo( &Vcb->Bpb ) + PAGE_SIZE))));
111
112 DebugTrace(+1, Dbg, "FatReadVolumeFile\n", 0);
113 DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
114 DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
115 DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
116
117 //
118 // Call the Cache manager to attempt the transfer.
119 //
120
121 Vbo.QuadPart = StartingVbo;
122
123 if (!CcMapData( Vcb->VirtualVolumeFile,
124 &Vbo,
125 ByteCount,
126 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
127 Bcb,
128 Buffer )) {
129
130 ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
131
132 //
133 // Could not read the data without waiting (cache miss).
134 //
135
136 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
137 }
138
139 DbgDoit( IrpContext->PinCount += 1 )
140
141 DebugTrace(-1, Dbg, "FatReadVolumeFile -> VOID, *BCB = %08lx\n", *Bcb);
142
143 return;
144 }
145
146 \f
147 VOID
148 FatPrepareWriteVolumeFile (
149 IN PIRP_CONTEXT IrpContext,
150 IN PVCB Vcb,
151 IN VBO StartingVbo,
152 IN ULONG ByteCount,
153 OUT PBCB *Bcb,
154 OUT PVOID *Buffer,
155 IN BOOLEAN Reversible,
156 IN BOOLEAN Zero
157 )
158
159 /*++
160
161 Routine Description:
162
163 This routine first looks to see if the specified range of sectors,
164 is already in the cache. If so, it increments the BCB PinCount,
165 sets the BCB dirty, and returns with the location of the sectors.
166
167 If the sectors are not in the cache and Wait is TRUE, it finds a
168 free BCB (potentially causing a flush), and clears out the entire
169 buffer. Once this is done, it increments the BCB PinCount, sets the
170 BCB dirty, and returns with the location of the sectors.
171
172 If the sectors are not in the cache and Wait is FALSE, this routine
173 raises STATUS_CANT_WAIT.
174
175 Arguments:
176
177 Vcb - Pointer to the VCB for the volume
178
179 StartingVbo - The virtual offset of the first byte to be written
180
181 ByteCount - Number of bytes to be written
182
183 Bcb - Returns a pointer to the BCB which is valid until unpinned
184
185 Buffer - Returns a pointer to the sectors, which is valid until unpinned
186
187 Reversible - Supplies TRUE if the specified range of modification should
188 be repinned so that the operation can be reversed in a controlled
189 fashion if errors are encountered.
190
191 Zero - Supplies TRUE if the specified range of bytes should be zeroed
192
193 --*/
194
195 {
196 LARGE_INTEGER Vbo;
197
198 PAGED_CODE();
199
200 //
201 // Check to see that all references are within the Bios Parameter Block
202 // or the fat(s).
203 //
204
205 ASSERT( ((StartingVbo + ByteCount) <= (ULONG)
206 (FatRootDirectoryLbo( &Vcb->Bpb ))));
207
208 DebugTrace(+1, Dbg, "FatPrepareWriteVolumeFile\n", 0);
209 DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
210 DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo);
211 DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
212 DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero);
213
214 //
215 // Call the Cache manager to attempt the transfer.
216 //
217
218 Vbo.QuadPart = StartingVbo;
219
220 if (!CcPinRead( Vcb->VirtualVolumeFile,
221 &Vbo,
222 ByteCount,
223 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
224 Bcb,
225 Buffer )) {
226
227 ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
228
229 //
230 // Could not read the data without waiting (cache miss).
231 //
232
233 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
234 }
235
236 //
237 // This keeps the data pinned until we complete the request
238 // and writes the dirty bit through to the disk.
239 //
240
241 DbgDoit( IrpContext->PinCount += 1 )
242
243 _SEH2_TRY {
244
245 if (Zero) {
246
247 RtlZeroMemory( *Buffer, ByteCount );
248 }
249
250 FatSetDirtyBcb( IrpContext, *Bcb, Vcb, Reversible );
251
252 } _SEH2_FINALLY {
253
254 if (_SEH2_AbnormalTermination()) {
255
256 FatUnpinBcb(IrpContext, *Bcb);
257 }
258 } _SEH2_END;
259
260 DebugTrace(-1, Dbg, "FatPrepareWriteVolumeFile -> VOID, *Bcb = %08lx\n", *Bcb);
261
262 return;
263 }
264
265 \f
266 VOID
267 FatReadDirectoryFile (
268 IN PIRP_CONTEXT IrpContext,
269 IN PDCB Dcb,
270 IN VBO StartingVbo,
271 IN ULONG ByteCount,
272 IN BOOLEAN Pin,
273 OUT PBCB *Bcb,
274 OUT PVOID *Buffer,
275 OUT PNTSTATUS Status
276 )
277
278 /*++
279
280 Routine Description:
281
282 This routine is called when the specified range of sectors is to be
283 read into the cache. If the desired range falls beyond the current
284 cache mapping, the fat will be searched, and if the desired range can
285 be satisfied, the cache mapping will be extended and the MCB updated
286 accordingly.
287
288 Arguments:
289
290 Dcb - Pointer to the DCB for the directory
291
292 StartingVbo - The virtual offset of the first desired byte
293
294 ByteCount - Number of bytes desired
295
296 Pin - Tells us if we should pin instead of just mapping.
297
298 Bcb - Returns a pointer to the BCB which is valid until unpinned
299
300 Buffer - Returns a pointer to the sectors, which is valid until unpinned
301
302 Status - Returns the status of the operation.
303
304 --*/
305
306 {
307 LARGE_INTEGER Vbo;
308
309 PAGED_CODE();
310
311 DebugTrace(+1, Dbg, "FatReadDirectoryFile\n", 0);
312 DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
313 DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
314 DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
315
316 //
317 // Check for the zero case
318 //
319
320 if (ByteCount == 0) {
321
322 DebugTrace(0, Dbg, "Nothing to read\n", 0);
323
324 *Bcb = NULL;
325 *Buffer = NULL;
326 *Status = STATUS_SUCCESS;
327
328 DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID\n", 0);
329 return;
330 }
331
332 //
333 // If we need to create a directory file and initialize the
334 // cachemap, do so.
335 //
336
337 FatOpenDirectoryFile( IrpContext, Dcb );
338
339 //
340 // Now if the transfer is beyond the allocation size return EOF.
341 //
342
343 if (StartingVbo >= Dcb->Header.AllocationSize.LowPart) {
344
345 DebugTrace(0, Dbg, "End of file read for directory\n", 0);
346
347 *Bcb = NULL;
348 *Buffer = NULL;
349 *Status = STATUS_END_OF_FILE;
350
351 DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID\n", 0);
352 return;
353 }
354
355 //
356 // If the caller is trying to read past the EOF, truncate the
357 // read.
358 //
359
360 ByteCount = (Dcb->Header.AllocationSize.LowPart - StartingVbo < ByteCount) ?
361 Dcb->Header.AllocationSize.LowPart - StartingVbo : ByteCount;
362
363 ASSERT( ByteCount != 0 );
364
365 //
366 // Call the Cache manager to attempt the transfer.
367 //
368
369 Vbo.QuadPart = StartingVbo;
370
371 if (Pin ?
372
373 !CcPinRead( Dcb->Specific.Dcb.DirectoryFile,
374 &Vbo,
375 ByteCount,
376 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
377 Bcb,
378 Buffer )
379 :
380
381 !CcMapData( Dcb->Specific.Dcb.DirectoryFile,
382 &Vbo,
383 ByteCount,
384 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
385 Bcb,
386 Buffer ) ) {
387
388 //
389 // Could not read the data without waiting (cache miss).
390 //
391
392 *Bcb = NULL;
393 *Buffer = NULL;
394 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
395 }
396
397 DbgDoit( IrpContext->PinCount += 1 )
398
399 *Status = STATUS_SUCCESS;
400
401 DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID, *BCB = %08lx\n", *Bcb);
402
403 return;
404 }
405
406 \f
407 VOID
408 FatPrepareWriteDirectoryFile (
409 IN PIRP_CONTEXT IrpContext,
410 IN PDCB Dcb,
411 IN VBO StartingVbo,
412 IN ULONG ByteCount,
413 OUT PBCB *Bcb,
414 OUT PVOID *Buffer,
415 IN BOOLEAN Zero,
416 IN BOOLEAN Reversible,
417 OUT PNTSTATUS Status
418 )
419
420 /*++
421
422 Routine Description:
423
424 This routine first looks to see if the specified range of sectors
425 is already in the cache. If so, it increments the BCB PinCount,
426 sets the BCB dirty, and returns TRUE with the location of the sectors.
427
428 The IrpContext->Flags .. Wait == TRUE/FALSE actions of this routine are identical to
429 FatPrepareWriteVolumeFile() above.
430
431 Arguments:
432
433 Dcb - Pointer to the DCB for the directory
434
435 StartingVbo - The virtual offset of the first byte to be written
436
437 ByteCount - Number of bytes to be written
438
439 Bcb - Returns a pointer to the BCB which is valid until unpinned
440
441 Buffer - Returns a pointer to the sectors, which is valid until unpinned
442
443 Zero - Supplies TRUE if the specified range of bytes should be zeroed
444
445 Reversible - Supplies TRUE if the specified range of modification should
446 be repinned so that the operation can be reversed in a controlled
447 fashion if errors are encountered.
448
449 Status - Returns the status of the operation.
450
451 --*/
452
453 {
454 LARGE_INTEGER Vbo;
455 ULONG InitialAllocation;
456 BOOLEAN UnwindWeAllocatedDiskSpace = FALSE;
457 ULONG ClusterSize;
458
459 PVOID LocalBuffer;
460
461 PAGED_CODE();
462
463 DebugTrace(+1, Dbg, "FatPrepareWriteDirectoryFile\n", 0);
464 DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
465 DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo);
466 DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
467 DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero);
468
469 *Bcb = NULL;
470 *Buffer = NULL;
471
472 //
473 // If we need to create a directory file and initialize the
474 // cachemap, do so.
475 //
476
477 FatOpenDirectoryFile( IrpContext, Dcb );
478
479 //
480 // If the transfer is beyond the allocation size we need to
481 // extend the directory's allocation. The call to
482 // AddFileAllocation will raise a condition if
483 // it runs out of disk space. Note that the root directory
484 // cannot be extended.
485 //
486
487 Vbo.QuadPart = StartingVbo;
488
489 _SEH2_TRY {
490
491 if (StartingVbo + ByteCount > Dcb->Header.AllocationSize.LowPart) {
492
493 if (NodeType(Dcb) == FAT_NTC_ROOT_DCB &&
494 !FatIsFat32(Dcb->Vcb)) {
495
496 FatRaiseStatus( IrpContext, STATUS_DISK_FULL );
497 }
498
499 DebugTrace(0, Dbg, "Try extending normal directory\n", 0);
500
501 InitialAllocation = Dcb->Header.AllocationSize.LowPart;
502
503 FatAddFileAllocation( IrpContext,
504 Dcb,
505 Dcb->Specific.Dcb.DirectoryFile,
506 StartingVbo + ByteCount );
507
508 UnwindWeAllocatedDiskSpace = TRUE;
509
510 //
511 // Inform the cache manager of the new allocation
512 //
513
514 Dcb->Header.FileSize.LowPart =
515 Dcb->Header.AllocationSize.LowPart;
516
517 CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
518 (PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
519
520 //
521 // Set up the Bitmap buffer if it is not big enough already
522 //
523
524 FatCheckFreeDirentBitmap( IrpContext, Dcb );
525
526 //
527 // The newly allocated clusters should be zeroed starting at
528 // the previous allocation size
529 //
530
531 Zero = TRUE;
532 Vbo.QuadPart = InitialAllocation;
533 ByteCount = Dcb->Header.AllocationSize.LowPart - InitialAllocation;
534 }
535
536 //
537 // Call the Cache Manager to attempt the transfer, going one cluster
538 // at a time to avoid pinning across a page boundary.
539 //
540
541 ClusterSize =
542 1 << Dcb->Vcb->AllocationSupport.LogOfBytesPerCluster;
543
544 while (ByteCount > 0) {
545
546 ULONG BytesToPin;
547
548 *Bcb = NULL;
549
550 if (ByteCount > ClusterSize) {
551 BytesToPin = ClusterSize;
552 } else {
553 BytesToPin = ByteCount;
554 }
555
556 ASSERT( (Vbo.QuadPart / ClusterSize) ==
557 (Vbo.QuadPart + BytesToPin - 1)/ClusterSize );
558
559 if (!CcPinRead( Dcb->Specific.Dcb.DirectoryFile,
560 &Vbo,
561 BytesToPin,
562 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
563 Bcb,
564 &LocalBuffer )) {
565
566 //
567 // Could not read the data without waiting (cache miss).
568 //
569
570 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
571 }
572
573 //
574 // Update our caller with the beginning of their request.
575 //
576
577 if (*Buffer == NULL) {
578
579 *Buffer = LocalBuffer;
580 }
581
582 DbgDoit( IrpContext->PinCount += 1 )
583
584 if (Zero) {
585
586 //
587 // We set this guy dirty right now so that we can raise CANT_WAIT when
588 // it needs to be done. It'd be beautiful if we could noop the read IO
589 // since we know we don't care about it.
590 //
591
592 RtlZeroMemory( LocalBuffer, BytesToPin );
593 CcSetDirtyPinnedData( *Bcb, NULL );
594 }
595
596 ByteCount -= BytesToPin;
597 Vbo.QuadPart += BytesToPin;
598
599
600 if (ByteCount > 0) {
601
602 FatUnpinBcb( IrpContext, *Bcb );
603 }
604 }
605
606 //
607 // This lets us get the data pinned until we complete the request
608 // and writes the dirty bit through to the disk.
609 //
610
611 FatSetDirtyBcb( IrpContext, *Bcb, Dcb->Vcb, Reversible );
612
613 *Status = STATUS_SUCCESS;
614
615 } _SEH2_FINALLY {
616
617 DebugUnwind( FatPrepareWriteDirectoryFile );
618
619 if (_SEH2_AbnormalTermination()) {
620
621 //
622 // These steps are carefully arranged - FatTruncateFileAllocation can raise.
623 // Make sure we unpin the buffer. If FTFA raises, the effect should be benign.
624 //
625
626 FatUnpinBcb(IrpContext, *Bcb);
627
628 if (UnwindWeAllocatedDiskSpace == TRUE) {
629
630 //
631 // Inform the cache manager of the change.
632 //
633
634 FatTruncateFileAllocation( IrpContext, Dcb, InitialAllocation );
635
636 Dcb->Header.FileSize.LowPart =
637 Dcb->Header.AllocationSize.LowPart;
638
639 CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile,
640 (PCC_FILE_SIZES)&Dcb->Header.AllocationSize );
641 }
642 }
643
644 DebugTrace(-1, Dbg, "FatPrepareWriteDirectoryFile -> (VOID), *Bcb = %08lx\n", *Bcb);
645 } _SEH2_END;
646
647 return;
648 }
649
650 \f
651 #if DBG
652 BOOLEAN FatDisableParentCheck = 0;
653
654 BOOLEAN
655 FatIsCurrentOperationSynchedForDcbTeardown (
656 IN PIRP_CONTEXT IrpContext,
657 IN PDCB Dcb
658 )
659 {
660 PIRP Irp = IrpContext->OriginatingIrp;
661 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation( Irp ) ;
662 #ifndef __REACTOS__
663 PFILE_OBJECT FileObject = Stack->FileObject;
664 #endif
665 PVCB Vcb;
666 PFCB Fcb;
667 PCCB Ccb;
668
669 PFILE_OBJECT ToCheck[3];
670 ULONG Index = 0;
671
672 PAGED_CODE();
673
674 //
675 // While mounting, we're OK without having to own anything.
676 //
677
678 if (Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
679 Stack->MinorFunction == IRP_MN_MOUNT_VOLUME) {
680
681 return TRUE;
682 }
683
684 //
685 // With the Vcb held, the close path is blocked out.
686 //
687
688 if (ExIsResourceAcquiredSharedLite( &Dcb->Vcb->Resource ) ||
689 ExIsResourceAcquiredExclusiveLite( &Dcb->Vcb->Resource )) {
690
691 return TRUE;
692 }
693
694 //
695 // Accept this assertion at face value. It comes from GetDirentForFcbOrDcb,
696 // and is reliable.
697 //
698
699 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_PARENT_BY_CHILD )) {
700
701 return TRUE;
702 }
703
704 //
705 // Determine which fileobjects are around on this operation.
706 //
707
708 if (Stack->MajorFunction == IRP_MJ_SET_INFORMATION &&
709 Stack->Parameters.SetFile.FileObject) {
710
711 ToCheck[Index++] = Stack->Parameters.SetFile.FileObject;
712 }
713
714 if (Stack->FileObject) {
715
716 ToCheck[Index++] = Stack->FileObject;
717 }
718
719 ToCheck[Index] = NULL;
720
721 //
722 // If the fileobjects we have are for this dcb or a child of it, we are
723 // also guaranteed that this dcb isn't going anywhere (even without
724 // the Vcb).
725 //
726
727 for (Index = 0; ToCheck[Index] != NULL; Index++) {
728
729 (VOID) FatDecodeFileObject( ToCheck[Index], &Vcb, &Fcb, &Ccb );
730
731 while ( Fcb ) {
732
733 if (Fcb == Dcb) {
734
735 return TRUE;
736 }
737
738 Fcb = Fcb->ParentDcb;
739 }
740 }
741
742 return FatDisableParentCheck;
743 }
744 #endif // DBG
745
746 VOID
747 FatOpenDirectoryFile (
748 IN PIRP_CONTEXT IrpContext,
749 IN PDCB Dcb
750 )
751
752 /*++
753
754 Routine Description:
755
756 This routine opens a new directory file if one is not already open.
757
758 Arguments:
759
760 Dcb - Pointer to the DCB for the directory
761
762 Return Value:
763
764 None.
765
766 --*/
767
768 {
769 PAGED_CODE();
770
771 DebugTrace(+1, Dbg, "FatOpenDirectoryFile\n", 0);
772 DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
773
774 //
775 // If we don't have some hold on this Dcb (there are several ways), there is nothing
776 // to prevent child files from closing and tearing this branch of the tree down in the
777 // midst of our slapping this reference onto it.
778 //
779 // I really wish we had a proper Fcb synchronization model (like CDFS/UDFS/NTFS).
780 //
781
782 ASSERT( FatIsCurrentOperationSynchedForDcbTeardown( IrpContext, Dcb ));
783
784 //
785 // If we haven't yet set the correct AllocationSize, do so.
786 //
787
788 if (Dcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
789
790 FatLookupFileAllocationSize( IrpContext, Dcb );
791
792 Dcb->Header.FileSize.LowPart =
793 Dcb->Header.AllocationSize.LowPart;
794 }
795
796 //
797 // Setup the Bitmap buffer if it is not big enough already
798 //
799
800 FatCheckFreeDirentBitmap( IrpContext, Dcb );
801
802 //
803 // Check if we need to create a directory file.
804 //
805 // We first do a spot check and then synchronize and check again.
806 //
807
808 if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
809
810 PFILE_OBJECT DirectoryFileObject = NULL;
811
812 FatAcquireDirectoryFileMutex( Dcb->Vcb );
813
814 _SEH2_TRY {
815
816 if (Dcb->Specific.Dcb.DirectoryFile == NULL) {
817
818 PDEVICE_OBJECT RealDevice;
819
820 //
821 // Create the special file object for the directory file, and set
822 // up its pointers back to the Dcb and the section object pointer.
823 // Note that setting the DirectoryFile pointer in the Dcb has
824 // to be the last thing done.
825 //
826 // Preallocate a close context since we have no Ccb for this object.
827 //
828
829 RealDevice = Dcb->Vcb->CurrentDevice;
830
831 DirectoryFileObject = IoCreateStreamFileObject( NULL, RealDevice );
832 FatPreallocateCloseContext();
833
834 FatSetFileObject( DirectoryFileObject,
835 DirectoryFile,
836 Dcb,
837 NULL );
838
839 //
840 // Remember this internal open.
841 //
842
843 #ifndef __REACTOS__
844 InterlockedIncrement( &(Dcb->Vcb->InternalOpenCount) );
845 #else
846 InterlockedIncrement( (LONG*)&(Dcb->Vcb->InternalOpenCount) );
847 #endif
848
849 //
850 // If this is the root directory, it is also a residual open.
851 //
852
853 if (NodeType( Dcb ) == FAT_NTC_ROOT_DCB) {
854
855 #ifndef __REACTOS__
856 InterlockedIncrement( &(Dcb->Vcb->ResidualOpenCount) );
857 #else
858 InterlockedIncrement( (LONG*)&(Dcb->Vcb->ResidualOpenCount) );
859 #endif
860 }
861
862 DirectoryFileObject->SectionObjectPointer = &Dcb->NonPaged->SectionObjectPointers;
863
864 DirectoryFileObject->ReadAccess = TRUE;
865 DirectoryFileObject->WriteAccess = TRUE;
866 DirectoryFileObject->DeleteAccess = TRUE;
867
868 #ifndef __REACTOS__
869 InterlockedIncrement( &Dcb->Specific.Dcb.DirectoryFileOpenCount );
870 #else
871 InterlockedIncrement( (LONG*)&Dcb->Specific.Dcb.DirectoryFileOpenCount );
872 #endif
873
874 Dcb->Specific.Dcb.DirectoryFile = DirectoryFileObject;
875
876 //
877 // Indicate we're happy with the fileobject now.
878 //
879
880 DirectoryFileObject = NULL;
881 }
882
883 } _SEH2_FINALLY {
884
885 FatReleaseDirectoryFileMutex( Dcb->Vcb );
886
887 //
888 // Rip the object up if we couldn't get the close context.
889 //
890
891 if (DirectoryFileObject) {
892
893 ObDereferenceObject( DirectoryFileObject );
894 }
895 } _SEH2_END;
896 }
897
898 //
899 // Finally check if we need to initialize the Cache Map for the
900 // directory file. The size of the section we are going to map
901 // the current allocation size for the directory. Note that the
902 // cache manager will provide syncronization for us.
903 //
904
905 if ( Dcb->Specific.Dcb.DirectoryFile->PrivateCacheMap == NULL ) {
906
907 Dcb->Header.ValidDataLength = FatMaxLarge;
908 Dcb->ValidDataToDisk = MAXULONG;
909
910 CcInitializeCacheMap( Dcb->Specific.Dcb.DirectoryFile,
911 (PCC_FILE_SIZES)&Dcb->Header.AllocationSize,
912 TRUE,
913 &FatData.CacheManagerNoOpCallbacks,
914 Dcb );
915 }
916
917 DebugTrace(-1, Dbg, "FatOpenDirectoryFile -> VOID\n", 0);
918
919 return;
920 }
921
922 \f
923 PFILE_OBJECT
924 FatOpenEaFile (
925 IN PIRP_CONTEXT IrpContext,
926 IN PFCB EaFcb
927 )
928
929 /*++
930
931 Routine Description:
932
933 This routine opens the Ea file.
934
935 Arguments:
936
937 EaFcb - Pointer to the Fcb for the Ea file.
938
939 Return Value:
940
941 Pointer to the new file object.
942
943 --*/
944
945 {
946 PFILE_OBJECT EaFileObject = NULL;
947 PDEVICE_OBJECT RealDevice;
948
949 PAGED_CODE();
950
951 DebugTrace(+1, Dbg, "FatOpenEaFile\n", 0);
952 DebugTrace( 0, Dbg, "EaFcb = %08lx\n", EaFcb);
953
954 //
955 // Create the special file object for the ea file, and set
956 // up its pointers back to the Fcb and the section object pointer
957 //
958
959 RealDevice = EaFcb->Vcb->CurrentDevice;
960
961 EaFileObject = IoCreateStreamFileObject( NULL, RealDevice );
962
963 _SEH2_TRY {
964
965 FatPreallocateCloseContext();
966
967 FatSetFileObject( EaFileObject,
968 EaFile,
969 EaFcb,
970 NULL );
971
972 //
973 // Remember this internal, residual open.
974 //
975
976 #ifndef __REACTOS__
977 InterlockedIncrement( &(EaFcb->Vcb->InternalOpenCount) );
978 InterlockedIncrement( &(EaFcb->Vcb->ResidualOpenCount) );
979 #else
980 InterlockedIncrement( (LONG*)&(EaFcb->Vcb->InternalOpenCount) );
981 InterlockedIncrement( (LONG*)&(EaFcb->Vcb->ResidualOpenCount) );
982 #endif
983
984 EaFileObject->SectionObjectPointer = &EaFcb->NonPaged->SectionObjectPointers;
985
986 EaFileObject->ReadAccess = TRUE;
987 EaFileObject->WriteAccess = TRUE;
988
989 //
990 // Finally check if we need to initialize the Cache Map for the
991 // ea file. The size of the section we are going to map
992 // the current allocation size for the Fcb.
993 //
994
995 EaFcb->Header.ValidDataLength = FatMaxLarge;
996
997 CcInitializeCacheMap( EaFileObject,
998 (PCC_FILE_SIZES)&EaFcb->Header.AllocationSize,
999 TRUE,
1000 &FatData.CacheManagerCallbacks,
1001 EaFcb );
1002
1003 CcSetAdditionalCacheAttributes( EaFileObject, TRUE, TRUE );
1004
1005 } _SEH2_FINALLY {
1006
1007 //
1008 // Drop the fileobject if we're raising. Two cases: couldn't get
1009 // the close context, and it is still an UnopenedFileObject, or
1010 // we lost trying to build the cache map - in which case we're
1011 // OK for the close context if we have to.
1012 //
1013
1014 if (_SEH2_AbnormalTermination()) {
1015
1016 ObDereferenceObject( EaFileObject );
1017 }
1018 } _SEH2_END;
1019
1020 DebugTrace(-1, Dbg, "FatOpenEaFile -> %08lx\n", EaFileObject);
1021
1022 UNREFERENCED_PARAMETER( IrpContext );
1023
1024 return EaFileObject;
1025 }
1026
1027 \f
1028 VOID
1029 FatCloseEaFile (
1030 IN PIRP_CONTEXT IrpContext,
1031 IN PVCB Vcb,
1032 IN BOOLEAN FlushFirst
1033 )
1034
1035 /*++
1036
1037 Routine Description:
1038
1039 This routine shuts down the ea file. Usually this is required when the volume
1040 begins to leave the system: after verify, dismount, deletion, pnp.
1041
1042 Arguments:
1043
1044 Vcb - the volume to close the ea file on
1045
1046 FlushFirst - whether the file should be flushed
1047
1048 Return Value:
1049
1050 None. As a side effect, the EA fileobject in the Vcb is cleared.
1051
1052 Caller must have the Vcb exclusive.
1053
1054 --*/
1055
1056 {
1057 PFILE_OBJECT EaFileObject = Vcb->VirtualEaFile;
1058
1059 PAGED_CODE();
1060
1061 DebugTrace(+1, Dbg, "FatCloseEaFile\n", 0);
1062 DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb);
1063
1064 ASSERT( FatVcbAcquiredExclusive(IrpContext, Vcb) );
1065
1066 if (EaFileObject != NULL) {
1067
1068 EaFileObject = Vcb->VirtualEaFile;
1069
1070 if (FlushFirst) {
1071
1072 CcFlushCache( Vcb->VirtualEaFile->SectionObjectPointer, NULL, 0, NULL );
1073 }
1074
1075 Vcb->VirtualEaFile = NULL;
1076
1077 //
1078 // Empty the Mcb for the Ea file.
1079 //
1080
1081 FatRemoveMcbEntry( Vcb, &Vcb->EaFcb->Mcb, 0, 0xFFFFFFFF );
1082
1083 //
1084 // Uninitialize the cache for this file object and dereference it.
1085 //
1086
1087 FatSyncUninitializeCacheMap( IrpContext, EaFileObject );
1088
1089 ObDereferenceObject( EaFileObject );
1090 }
1091
1092 DebugTrace(-1, Dbg, "FatCloseEaFile -> %08lx\n", EaFileObject);
1093 }
1094
1095 \f
1096 VOID
1097 FatSetDirtyBcb (
1098 IN PIRP_CONTEXT IrpContext,
1099 IN PBCB Bcb,
1100 IN PVCB Vcb OPTIONAL,
1101 IN BOOLEAN Reversible
1102 )
1103
1104 /*++
1105
1106 Routine Description:
1107
1108 This routine saves a reference to the bcb in the irp context and
1109 sets the bcb dirty. This will have the affect of keeping the page in
1110 memory until we complete the request
1111
1112 In addition, a DPC is set to fire in 5 seconds (or if one is pending,
1113 pushed back 5 seconds) to mark the volume clean.
1114
1115 Arguments:
1116
1117 Bcb - Supplies the Bcb being set dirty
1118
1119 Vcb - Supplies the volume being marked dirty
1120
1121 Reversible - Supplies TRUE if the specified range of bcb should be repinned
1122 so that the changes can be reversed in a controlled fashion if errors
1123 are encountered.
1124
1125 Return Value:
1126
1127 None.
1128
1129 --*/
1130
1131 {
1132 DebugTrace(+1, Dbg, "FatSetDirtyBcb\n", 0 );
1133 DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
1134 DebugTrace( 0, Dbg, "Bcb = %08lx\n", Bcb );
1135 DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
1136
1137 //
1138 // Repin the bcb as required
1139 //
1140
1141 if (Reversible) {
1142
1143 FatRepinBcb( IrpContext, Bcb );
1144 }
1145
1146 //
1147 // Set the bcb dirty
1148 //
1149
1150 CcSetDirtyPinnedData( Bcb, NULL );
1151
1152 //
1153 // If volume dirtying isn't disabled for this operation (for
1154 // instance, when we're changing the dirty state), set the
1155 // volume dirty if we were given a Vcb that we want to perform
1156 // clean volume processing on, and return.
1157 //
1158 // As a historical note, we used to key off of the old floppy
1159 // (now deferred flush) bit to disable dirtying behavior. Since
1160 // hotpluggable media can still be yanked while operations are
1161 // in flight, recognize that its really the case that FAT12
1162 // doesn't have the dirty bit.
1163 //
1164
1165 if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_DIRTY) &&
1166 ARGUMENT_PRESENT(Vcb) &&
1167 !FatIsFat12(Vcb)) {
1168
1169 KIRQL SavedIrql;
1170
1171 BOOLEAN SetTimer;
1172
1173 LARGE_INTEGER TimeSincePreviousCall;
1174 LARGE_INTEGER CurrentTime;
1175
1176 //
1177 // "Borrow" the irp context spinlock.
1178 //
1179
1180 KeQuerySystemTime( &CurrentTime );
1181
1182 KeAcquireSpinLock( &FatData.GeneralSpinLock, &SavedIrql );
1183
1184 TimeSincePreviousCall.QuadPart =
1185 CurrentTime.QuadPart - Vcb->LastFatMarkVolumeDirtyCall.QuadPart;
1186
1187 //
1188 // If more than one second has elapsed since the prior call
1189 // to here, bump the timer up again and see if we need to
1190 // physically mark the volume dirty.
1191 //
1192
1193 if ( (TimeSincePreviousCall.HighPart != 0) ||
1194 (TimeSincePreviousCall.LowPart > (1000 * 1000 * 10)) ) {
1195
1196 SetTimer = TRUE;
1197
1198 } else {
1199
1200 SetTimer = FALSE;
1201 }
1202
1203 KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
1204
1205 if ( SetTimer ) {
1206
1207 LARGE_INTEGER CleanVolumeTimer;
1208
1209 //
1210 // We use a shorter volume clean timer for hot plug volumes.
1211 //
1212
1213 CleanVolumeTimer.QuadPart = FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)
1214 ? (LONG)-1500*1000*10
1215 : (LONG)-8*1000*1000*10;
1216
1217 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
1218 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
1219
1220 //
1221 // We have now synchronized with anybody clearing the dirty
1222 // flag, so we can now see if we really have to actually write
1223 // out the physical bit.
1224 //
1225
1226 if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY) ) {
1227
1228 //
1229 // We want to really mark the volume dirty now.
1230 //
1231
1232 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
1233
1234 FatMarkVolume( IrpContext, Vcb, VolumeDirty );
1235 }
1236
1237 SetFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
1238
1239 //
1240 // Lock the volume if it is removable.
1241 //
1242
1243 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
1244
1245 FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
1246 }
1247 }
1248
1249 KeAcquireSpinLock( &FatData.GeneralSpinLock, &SavedIrql );
1250
1251 KeQuerySystemTime( &Vcb->LastFatMarkVolumeDirtyCall );
1252
1253 KeReleaseSpinLock( &FatData.GeneralSpinLock, SavedIrql );
1254
1255 KeSetTimer( &Vcb->CleanVolumeTimer,
1256 CleanVolumeTimer,
1257 &Vcb->CleanVolumeDpc );
1258 }
1259 }
1260
1261 DebugTrace(-1, Dbg, "FatSetDirtyBcb -> VOID\n", 0 );
1262 }
1263
1264 \f
1265 VOID
1266 FatRepinBcb (
1267 IN PIRP_CONTEXT IrpContext,
1268 IN PBCB Bcb
1269 )
1270
1271 /*++
1272
1273 Routine Description:
1274
1275 This routine saves a reference to the bcb in the irp context. This will
1276 have the affect of keeping the page in memory until we complete the
1277 request
1278
1279 Arguments:
1280
1281 Bcb - Supplies the Bcb being referenced
1282
1283 Return Value:
1284
1285 None.
1286
1287 --*/
1288
1289 {
1290 PREPINNED_BCBS Repinned;
1291 ULONG i;
1292
1293 PAGED_CODE();
1294
1295 DebugTrace(+1, Dbg, "FatRepinBcb\n", 0 );
1296 DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
1297 DebugTrace( 0, Dbg, "Bcb = %08lx\n", Bcb );
1298
1299 //
1300 // The algorithm is to search the list of repinned records until
1301 // we either find a match for the bcb or we find a null slot.
1302 //
1303
1304 Repinned = &IrpContext->Repinned;
1305
1306 while (TRUE) {
1307
1308 //
1309 // For every entry in the repinned record check if the bcb's
1310 // match or if the entry is null. If the bcb's match then
1311 // we've done because we've already repinned this bcb, if
1312 // the entry is null then we know, because it's densely packed,
1313 // that the bcb is not in the list so add it to the repinned
1314 // record and repin it.
1315 //
1316
1317 for (i = 0; i < REPINNED_BCBS_ARRAY_SIZE; i += 1) {
1318
1319 if (Repinned->Bcb[i] == Bcb) {
1320
1321 DebugTrace(-1, Dbg, "FatRepinBcb -> VOID\n", 0 );
1322 return;
1323 }
1324
1325 if (Repinned->Bcb[i] == NULL) {
1326
1327 Repinned->Bcb[i] = Bcb;
1328 CcRepinBcb( Bcb );
1329
1330 DebugTrace(-1, Dbg, "FatRepinBcb -> VOID\n", 0 );
1331 return;
1332 }
1333 }
1334
1335 //
1336 // We finished checking one repinned record so now locate the next
1337 // repinned record, If there isn't one then allocate and zero out
1338 // a new one.
1339 //
1340
1341 if (Repinned->Next == NULL) {
1342
1343 Repinned->Next = FsRtlAllocatePoolWithTag( PagedPool,
1344 sizeof(REPINNED_BCBS),
1345 TAG_REPINNED_BCB );
1346
1347 RtlZeroMemory( Repinned->Next, sizeof(REPINNED_BCBS) );
1348 }
1349
1350 Repinned = Repinned->Next;
1351 }
1352 }
1353
1354 \f
1355 VOID
1356 FatUnpinRepinnedBcbs (
1357 IN PIRP_CONTEXT IrpContext
1358 )
1359
1360 /*++
1361
1362 Routine Description:
1363
1364 This routine frees all of the repinned bcbs, stored in an IRP context.
1365
1366 Arguments:
1367
1368 Return Value:
1369
1370 None.
1371
1372 --*/
1373
1374 {
1375 IO_STATUS_BLOCK RaiseIosb;
1376 PREPINNED_BCBS Repinned;
1377 BOOLEAN WriteThroughToDisk;
1378 PFILE_OBJECT FileObject = NULL;
1379 BOOLEAN ForceVerify = FALSE;
1380 ULONG i;
1381
1382 PAGED_CODE();
1383
1384 DebugTrace(+1, Dbg, "FatUnpinRepinnedBcbs\n", 0 );
1385 DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
1386
1387 //
1388 // The algorithm for this procedure is to scan the entire list of
1389 // repinned records unpinning any repinned bcbs. We start off
1390 // with the first record in the irp context, and while there is a
1391 // record to scan we do the following loop.
1392 //
1393
1394 Repinned = &IrpContext->Repinned;
1395 RaiseIosb.Status = STATUS_SUCCESS;
1396
1397 //
1398 // If the request is write through or the media is deferred flush,
1399 // unpin the bcb's write through.
1400 //
1401
1402 WriteThroughToDisk = (BOOLEAN) (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH) &&
1403 IrpContext->Vcb != NULL &&
1404 (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH) ||
1405 FlagOn(IrpContext->Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)));
1406
1407 while (Repinned != NULL) {
1408
1409 //
1410 // For every non-null entry in the repinned record unpin the
1411 // repinned entry.
1412 //
1413 // If the this is removable media (therefore all requests write-
1414 // through) and the write fails, purge the cache so that we throw
1415 // away the modifications as we will be returning an error to the
1416 // user.
1417 //
1418
1419 for (i = 0; i < REPINNED_BCBS_ARRAY_SIZE; i += 1) {
1420
1421 if (Repinned->Bcb[i] != NULL) {
1422
1423 IO_STATUS_BLOCK Iosb;
1424
1425 if (WriteThroughToDisk &&
1426 FlagOn(IrpContext->Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH)) {
1427
1428 FileObject = CcGetFileObjectFromBcb( Repinned->Bcb[i] );
1429 }
1430
1431 CcUnpinRepinnedBcb( Repinned->Bcb[i],
1432 WriteThroughToDisk,
1433 &Iosb );
1434
1435 if ( !NT_SUCCESS(Iosb.Status) ) {
1436
1437 if (RaiseIosb.Status == STATUS_SUCCESS) {
1438
1439 RaiseIosb = Iosb;
1440 }
1441
1442 //
1443 // If this was a writethrough device, purge the cache,
1444 // except for Irp major codes that either don't handle
1445 // the error paths correctly or are simple victims like
1446 // cleanup.c.
1447 //
1448
1449 if (FileObject &&
1450 (IrpContext->MajorFunction != IRP_MJ_CLEANUP) &&
1451 (IrpContext->MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
1452 (IrpContext->MajorFunction != IRP_MJ_SET_INFORMATION)) {
1453
1454 //
1455 // The call to CcPurgeCacheSection() below will
1456 // purge the entire file from memory. It will also
1457 // block until all the file's BCB's are pinned.
1458 //
1459 // We end up in a deadlock situation of there
1460 // are any other pinned BCB's in this IRP context
1461 // so the first thing we do is search the list
1462 // for BCB's pinned in the same file and unpin
1463 // them.
1464 //
1465 // We are probably not going to lose data because
1466 // it's safe to assume that all flushes will
1467 // fail after the first one fails.
1468 //
1469
1470 ULONG j;
1471
1472 for (j = i + 1; j < REPINNED_BCBS_ARRAY_SIZE; j++) {
1473
1474 if (Repinned->Bcb[j] != NULL) {
1475
1476 if (CcGetFileObjectFromBcb( Repinned->Bcb[j] ) == FileObject) {
1477
1478 CcUnpinRepinnedBcb( Repinned->Bcb[j],
1479 FALSE,
1480 &Iosb );
1481
1482 Repinned->Bcb[j] = NULL;
1483 }
1484 }
1485 }
1486
1487 CcPurgeCacheSection( FileObject->SectionObjectPointer,
1488 NULL,
1489 0,
1490 FALSE );
1491
1492 //
1493 // Force a verify operation here since who knows
1494 // what state things are in.
1495 //
1496
1497 ForceVerify = TRUE;
1498 }
1499 }
1500
1501 Repinned->Bcb[i] = NULL;
1502
1503 }
1504 }
1505
1506 //
1507 // Now find the next repinned record in the list, and possibly
1508 // delete the one we've just processed.
1509 //
1510
1511 if (Repinned != &IrpContext->Repinned) {
1512
1513 PREPINNED_BCBS Saved;
1514
1515 Saved = Repinned->Next;
1516 ExFreePool( Repinned );
1517 Repinned = Saved;
1518
1519 } else {
1520
1521 Repinned = Repinned->Next;
1522 IrpContext->Repinned.Next = NULL;
1523 }
1524 }
1525
1526 //
1527 // Now if we weren't completely successful in the our unpin
1528 // then raise the iosb we got
1529 //
1530
1531 if (!NT_SUCCESS(RaiseIosb.Status)) {
1532
1533 if (ForceVerify && FileObject) {
1534
1535 SetFlag(FileObject->DeviceObject->Flags, DO_VERIFY_VOLUME);
1536
1537 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
1538 FileObject->DeviceObject );
1539 }
1540
1541 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE )) {
1542
1543 IrpContext->OriginatingIrp->IoStatus = RaiseIosb;
1544 FatNormalizeAndRaiseStatus( IrpContext, RaiseIosb.Status );
1545 }
1546 }
1547
1548 DebugTrace(-1, Dbg, "FatUnpinRepinnedBcbs -> VOID\n", 0 );
1549
1550 return;
1551 }
1552
1553 \f
1554 FINISHED
1555 FatZeroData (
1556 IN PIRP_CONTEXT IrpContext,
1557 IN PVCB Vcb,
1558 IN PFILE_OBJECT FileObject,
1559 IN ULONG StartingZero,
1560 IN ULONG ByteCount
1561 )
1562
1563 /*++
1564
1565 **** Temporary function - Remove when CcZeroData is capable of handling
1566 non sector aligned requests.
1567
1568 --*/
1569 {
1570 #ifndef __REACTOS__
1571 LARGE_INTEGER ZeroStart = {0,0};
1572 LARGE_INTEGER BeyondZeroEnd = {0,0};
1573 #else
1574 LARGE_INTEGER ZeroStart = {{0}};
1575 LARGE_INTEGER BeyondZeroEnd = {{0}};
1576 #endif
1577
1578 ULONG SectorSize;
1579
1580 BOOLEAN Finished;
1581
1582 PAGED_CODE();
1583
1584 SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
1585
1586 ZeroStart.LowPart = (StartingZero + (SectorSize - 1)) & ~(SectorSize - 1);
1587
1588 //
1589 // Detect overflow if we were asked to zero in the last sector of the file,
1590 // which must be "zeroed" already (or we're in trouble).
1591 //
1592
1593 if (StartingZero != 0 && ZeroStart.LowPart == 0) {
1594
1595 return TRUE;
1596 }
1597
1598 //
1599 // Note that BeyondZeroEnd can take the value 4gb.
1600 //
1601
1602 BeyondZeroEnd.QuadPart = ((ULONGLONG) StartingZero + ByteCount + (SectorSize - 1))
1603 & (~((LONGLONG) SectorSize - 1));
1604
1605 //
1606 // If we were called to just zero part of a sector we are in trouble.
1607 //
1608
1609 if ( ZeroStart.QuadPart == BeyondZeroEnd.QuadPart ) {
1610
1611 return TRUE;
1612 }
1613
1614 Finished = CcZeroData( FileObject,
1615 &ZeroStart,
1616 &BeyondZeroEnd,
1617 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
1618
1619 return Finished;
1620 }
1621
1622 \f
1623 NTSTATUS
1624 FatCompleteMdl (
1625 IN PIRP_CONTEXT IrpContext,
1626 IN PIRP Irp
1627 )
1628
1629 /*++
1630
1631 Routine Description:
1632
1633 This routine performs the function of completing Mdl read and write
1634 requests. It should be called only from FatFsdRead and FatFsdWrite.
1635
1636 Arguments:
1637
1638 Irp - Supplies the originating Irp.
1639
1640 Return Value:
1641
1642 NTSTATUS - Will always be STATUS_PENDING or STATUS_SUCCESS.
1643
1644 --*/
1645
1646 {
1647 PFILE_OBJECT FileObject;
1648 PIO_STACK_LOCATION IrpSp;
1649
1650 PAGED_CODE();
1651
1652 DebugTrace(+1, Dbg, "FatCompleteMdl\n", 0 );
1653 DebugTrace( 0, Dbg, "IrpContext = %08lx\n", IrpContext );
1654 DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
1655
1656 //
1657 // Do completion processing.
1658 //
1659
1660 FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
1661
1662 switch( IrpContext->MajorFunction ) {
1663
1664 case IRP_MJ_READ:
1665
1666 CcMdlReadComplete( FileObject, Irp->MdlAddress );
1667 break;
1668
1669 case IRP_MJ_WRITE:
1670
1671 IrpSp = IoGetCurrentIrpStackLocation( Irp );
1672
1673 ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ));
1674
1675 CcMdlWriteComplete( FileObject, &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress );
1676
1677 Irp->IoStatus.Status = STATUS_SUCCESS;
1678
1679 break;
1680
1681 default:
1682
1683 DebugTrace( DEBUG_TRACE_ERROR, 0, "Illegal Mdl Complete.\n", 0);
1684 FatBugCheck( IrpContext->MajorFunction, 0, 0 );
1685 }
1686
1687 //
1688 // Mdl is now deallocated.
1689 //
1690
1691 Irp->MdlAddress = NULL;
1692
1693 //
1694 // Complete the request and exit right away.
1695 //
1696
1697 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
1698
1699 DebugTrace(-1, Dbg, "FatCompleteMdl -> STATUS_SUCCESS\n", 0 );
1700
1701 return STATUS_SUCCESS;
1702 }
1703 \f
1704 VOID
1705 FatSyncUninitializeCacheMap (
1706 IN PIRP_CONTEXT IrpContext,
1707 IN PFILE_OBJECT FileObject
1708 )
1709
1710 /*++
1711
1712 Routine Description:
1713
1714 The routine performs a CcUnitializeCacheMap to LargeZero synchronously. That
1715 is it waits on the Cc event. This call is useful when we want to be certain
1716 when a close will actually some in.
1717
1718 Return Value:
1719
1720 None.
1721
1722 --*/
1723
1724 {
1725 CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
1726 NTSTATUS WaitStatus;
1727
1728 PAGED_CODE();
1729
1730 KeInitializeEvent( &UninitializeCompleteEvent.Event,
1731 SynchronizationEvent,
1732 FALSE);
1733
1734 CcUninitializeCacheMap( FileObject,
1735 &FatLargeZero,
1736 &UninitializeCompleteEvent );
1737
1738 //
1739 // Now wait for the cache manager to finish purging the file.
1740 // This will garentee that Mm gets the purge before we
1741 // delete the Vcb.
1742 //
1743
1744 WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
1745 Executive,
1746 KernelMode,
1747 FALSE,
1748 NULL);
1749
1750 ASSERT(WaitStatus == STATUS_SUCCESS);
1751 }
1752 \f
1753 VOID
1754 FatPinMappedData (
1755 IN PIRP_CONTEXT IrpContext,
1756 IN PDCB Dcb,
1757 IN VBO StartingVbo,
1758 IN ULONG ByteCount,
1759 OUT PBCB *Bcb
1760 )
1761
1762 /*++
1763
1764 Routine Description:
1765
1766 This routine pins data that was previously mapped before setting it dirty.
1767
1768 Arguments:
1769
1770 Dcb - Pointer to the DCB for the directory
1771
1772 StartingVbo - The virtual offset of the first desired byte
1773
1774 ByteCount - Number of bytes desired
1775
1776 Bcb - Returns a pointer to the BCB which is valid until unpinned
1777
1778 --*/
1779
1780 {
1781 LARGE_INTEGER Vbo;
1782
1783 PAGED_CODE();
1784
1785 DebugTrace(+1, Dbg, "FatPinMappedData\n", 0);
1786 DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb);
1787 DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo);
1788 DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
1789
1790 //
1791 // Call the Cache manager to perform the operation.
1792 //
1793
1794 Vbo.QuadPart = StartingVbo;
1795
1796 if (!CcPinMappedData( Dcb->Specific.Dcb.DirectoryFile,
1797 &Vbo,
1798 ByteCount,
1799 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
1800 Bcb )) {
1801
1802 //
1803 // Could not pin the data without waiting (cache miss).
1804 //
1805
1806 FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
1807 }
1808
1809 DebugTrace(-1, Dbg, "FatReadDirectoryFile -> VOID, *BCB = %08lx\n", *Bcb);
1810
1811 return;
1812 }
1813
1814