2 * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
14 * this list of conditions and the following disclaimer in the
16 * and/or other materials provided with the distribution.
17 * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18 * nor the names of their contributors may be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission from Kernel Drivers, LLC and Your File System, Inc.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 // File: AFSIoSupport.cpp
39 #include "AFSCommon.h"
42 // Called in the paging or non cached read and write paths to get the
43 // first and last extent in a span. We also the count of how many
44 // discontiguous extents the are in the cache file.
48 AFSGetExtents( IN AFSFcb *Fcb,
49 IN PLARGE_INTEGER Offset,
52 OUT ULONG *ExtentCount,
55 NTSTATUS ntStatus = STATUS_SUCCESS;
56 ULONG extentsCount = 0, runCount = 0;
57 AFSExtent *pEndExtent = NULL;
58 LARGE_INTEGER liLastCacheOffset;
64 ASSERT(AFSExtentContains(From, Offset));
69 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
71 while ((Offset->QuadPart + Length) >
72 pEndExtent->FileOffset.QuadPart + pEndExtent->Size) {
74 pEndExtent = NextExtent(pEndExtent, AFS_EXTENTS_LIST);
76 if (liLastCacheOffset.QuadPart != pEndExtent->CacheOffset.QuadPart) {
78 // Discontiguous (in the cache)
86 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
89 *ExtentCount = extentsCount;
91 ntStatus = STATUS_SUCCESS;
98 AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice,
100 IN PVOID SystemBuffer,
101 IN OUT AFSIoRun *IoRuns,
102 IN PLARGE_INTEGER Start,
105 IN OUT ULONG *RunCount)
108 // Do all the work which we can prior to firing off the IRP
109 // (allocate them, calculate offsets and so on)
111 LARGE_INTEGER liCacheOffset;
112 LARGE_INTEGER liFileOffset = *Start;
116 AFSExtent *pExtent = From;
117 AFSExtent *pNextExtent;
119 BOOLEAN done = FALSE;
120 NTSTATUS ntStatus = STATUS_SUCCESS;
127 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
129 liCacheOffset = pExtent->CacheOffset;
130 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
131 pExtent->FileOffset.QuadPart);
136 // While there is still data to process, loop
138 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
139 (Start->QuadPart + Length) )
142 // Collapse the read if we can
144 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
146 if (pNextExtent->CacheOffset.QuadPart !=
147 (pExtent->CacheOffset.QuadPart + pExtent->Size))
150 // This extent and the next extent are not contiguous
154 pExtent = pNextExtent;
158 // So, this run goes from liCacheOffset to the end of pExtent
161 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
164 // The last extent overruns the area we care
165 // about, so trim it back.
167 ulCurrLength = (ULONG) (Start->QuadPart + Length -
168 liFileOffset.QuadPart);
177 // Length is from the LiFileOffset to the end of this
180 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
181 liFileOffset.QuadPart);
186 // Calculate the offset into the buffer
188 ulReadOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
190 IoRuns[ulCurrRun].CacheOffset = liCacheOffset;
191 IoRuns[ulCurrRun].ByteCount = ulCurrLength;
193 IoRuns[ulCurrRun].ChildIrp = IoAllocateIrp( CacheDevice->StackSize + 1,
196 if (NULL == IoRuns[ulCurrRun].ChildIrp)
198 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
201 IoRuns[ulCurrRun].ChildIrp->UserBuffer = ((PCHAR) SystemBuffer) + ulReadOffset;
202 IoRuns[ulCurrRun].ChildIrp->Tail.Overlay.Thread = PsGetCurrentThread();
203 IoRuns[ulCurrRun].ChildIrp->RequestorMode = KernelMode;
204 IoRuns[ulCurrRun].ChildIrp->MdlAddress = NULL;
209 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
211 // Move cursors forward
213 pExtent = pNextExtent;
214 liFileOffset = pExtent->FileOffset;
217 ASSERT(ulCurrRun <= *RunCount);
219 if (!NT_SUCCESS(ntStatus))
221 for (ulCurrRun = 0 ; ulCurrRun < *RunCount; ulCurrRun++)
223 if (IoRuns[ulCurrRun].ChildIrp) {
224 IoFreeIrp( IoRuns[ulCurrRun].ChildIrp );
225 IoRuns[ulCurrRun].ChildIrp = NULL;
231 *RunCount = ulCurrRun;
238 // We manage our own scatter / gather. This completion
239 // function calls into our generic function.
244 CompletionFunction(IN PDEVICE_OBJECT DeviceObject,
248 AFSGatherIo *pGather = (AFSGatherIo *) Context;
250 AFSCompleteIo( pGather, Irp->IoStatus.Status);
252 if (Irp->MdlAddress) {
253 if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
254 MmUnlockPages(Irp->MdlAddress);
256 IoFreeMdl(Irp->MdlAddress);
257 Irp->MdlAddress = NULL;
262 // Tell io manager that we own the Irp
264 return STATUS_MORE_PROCESSING_REQUIRED;
268 AFSStartIos( IN PFILE_OBJECT CacheFileObject,
269 IN UCHAR FunctionCode,
273 IN OUT AFSGatherIo *Gather)
276 AFSDeviceExt *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
277 PIO_STACK_LOCATION pIoStackLocation = NULL;
279 NTSTATUS ntStatus = STATUS_SUCCESS;
280 PDEVICE_OBJECT pDeviceObject = NULL;
286 pDeviceObject = IoGetRelatedDeviceObject( CacheFileObject);
288 for (ULONG i = 0; i < Count; i++)
291 pIrp = IoRun[i].ChildIrp;
293 pIoStackLocation = IoGetNextIrpStackLocation( pIrp);
295 pIrp->Flags = IrpFlags;
296 pIoStackLocation->MajorFunction = FunctionCode;
297 pIoStackLocation->DeviceObject = pDeviceObject;
298 pIoStackLocation->FileObject = CacheFileObject;
299 pIoStackLocation->Parameters.Write.Length = IoRun[i].ByteCount;
300 pIoStackLocation->Parameters.Write.ByteOffset = IoRun[i].CacheOffset;
303 // Bump the count *before* we start the IO, that way if it
304 // completes real fast it will still not set the event
306 lCount = InterlockedIncrement(&Gather->Count);
309 // Set the completion routine.
312 IoSetCompletionRoutine( pIrp,
320 // Send it to the Cache
323 ntStatus = IoCallDriver( pDeviceObject,
326 if( !NT_SUCCESS( ntStatus))
337 AFSCompleteIo( IN AFSGatherIo *Gather,
342 if (!NT_SUCCESS(Status)) {
344 Gather->Status = Status;
347 lCount = InterlockedDecrement( &Gather->Count );
351 // Last outstanding IO. Complete the parent and
352 // do whatever it takes to clean up
354 if (!NT_SUCCESS(Gather->Status))
356 Gather->MasterIrp->IoStatus.Status = Gather->Status;
357 Gather->MasterIrp->IoStatus.Information = 0;
360 if( Gather->CompleteMasterIrp)
363 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
364 AFS_TRACE_LEVEL_VERBOSE,
365 "AFSCompleteIo Completing Irp %08lX Status %08lX\n",
369 AFSCompleteRequest(Gather->MasterIrp, Gather->Status);
372 if (Gather->Synchronous)
375 // Someone was waiting for us tell them. They also own
376 // the data structure so we don't free it
378 KeSetEvent( &Gather->Event,
385 AFSExFreePool( Gather);
391 AFSProcessExtentRun( IN PVOID SystemBuffer,
392 IN PLARGE_INTEGER Start,
395 IN BOOLEAN WriteRequest)
398 LARGE_INTEGER liCacheOffset;
399 LARGE_INTEGER liFileOffset = *Start;
403 AFSExtent *pExtent = From;
404 AFSExtent *pNextExtent;
406 BOOLEAN done = FALSE;
407 NTSTATUS ntStatus = STATUS_SUCCESS;
414 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
416 liCacheOffset = pExtent->CacheOffset;
417 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
418 pExtent->FileOffset.QuadPart);
423 // While there is still data to process, loop
425 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
426 (Start->QuadPart + Length) )
429 // Collapse the read if we can
431 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
433 if (pNextExtent->CacheOffset.QuadPart !=
434 (pExtent->CacheOffset.QuadPart + pExtent->Size))
437 // This extent and the next extent are not contiguous
441 pExtent = pNextExtent;
445 // So, this run goes from liCacheOffset to the end of pExtent
448 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
451 // The last extent overruns the area we care
452 // about, so trim it back.
454 ulCurrLength = (ULONG) (Start->QuadPart + Length -
455 liFileOffset.QuadPart);
464 // Length is from the LiFileOffset to the end of this
467 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
468 liFileOffset.QuadPart);
473 // Calculate the offset into the buffer
475 ulOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
481 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
482 ((char *)SystemBuffer + ulOffset),
485 ASSERT( liCacheOffset.HighPart == 0);
486 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
487 ((char *)SystemBuffer + ulOffset),
495 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
496 ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
499 ASSERT( liCacheOffset.HighPart == 0);
500 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
501 ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
509 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
511 // Move cursors forward
513 pExtent = pNextExtent;
514 liFileOffset = pExtent->FileOffset;