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"
41 static AFSExtent *NextExtent(AFSExtent *Extent);
44 // Called in the paging or non cached read and write paths to get the
45 // first and last extent in a span. We also the count of how many
46 // discontiguous extents the are in the cache file.
50 AFSGetExtents( IN AFSFcb *Fcb,
51 IN PLARGE_INTEGER Offset,
54 OUT ULONG *ExtentCount,
57 NTSTATUS ntStatus = STATUS_SUCCESS;
58 ULONG extentsCount = 0, runCount = 0;
59 AFSExtent *pEndExtent = NULL;
60 LARGE_INTEGER liLastCacheOffset;
66 ASSERT(AFSExtentContains(From, Offset));
71 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
73 while ((Offset->QuadPart + Length) >
74 pEndExtent->FileOffset.QuadPart + pEndExtent->Size) {
76 pEndExtent = NextExtent(pEndExtent);
78 if (liLastCacheOffset.QuadPart != pEndExtent->CacheOffset.QuadPart) {
80 // Discontiguous (in the cache)
88 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
91 *ExtentCount = extentsCount;
93 ntStatus = STATUS_SUCCESS;
100 AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice,
102 IN PVOID SystemBuffer,
103 IN OUT AFSIoRun *IoRuns,
104 IN PLARGE_INTEGER Start,
107 IN OUT ULONG *RunCount)
110 // Do all the work which we can prior to firing off the IRP
111 // (allocate them, calculate offsets and so on)
113 LARGE_INTEGER liCacheOffset;
114 LARGE_INTEGER liFileOffset = *Start;
118 AFSExtent *pExtent = From;
119 AFSExtent *pNextExtent;
121 BOOLEAN done = FALSE;
122 NTSTATUS ntStatus = STATUS_SUCCESS;
129 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
131 liCacheOffset = pExtent->CacheOffset;
132 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
133 pExtent->FileOffset.QuadPart);
138 // While there is still data to process, loop
140 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
141 (Start->QuadPart + Length) )
144 // Collapse the read if we can
146 pNextExtent = NextExtent( pExtent );
148 if (pNextExtent->CacheOffset.QuadPart !=
149 (pExtent->CacheOffset.QuadPart + pExtent->Size))
152 // This extent and the next extent are not contiguous
156 pExtent = pNextExtent;
160 // So, this run goes from liCacheOffset to the end of pExtent
163 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
166 // The last extent overruns the area we care
167 // about, so trim it back.
169 ulCurrLength = (ULONG) (Start->QuadPart + Length -
170 liFileOffset.QuadPart);
179 // Length is from the LiFileOffset to the end of this
182 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
183 liFileOffset.QuadPart);
188 // Calculate the offset into the buffer
190 ulReadOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
192 IoRuns[ulCurrRun].CacheOffset = liCacheOffset;
193 IoRuns[ulCurrRun].ByteCount = ulCurrLength;
195 IoRuns[ulCurrRun].ChildIrp = IoAllocateIrp( CacheDevice->StackSize + 1,
198 if (NULL == IoRuns[ulCurrRun].ChildIrp)
200 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
203 IoRuns[ulCurrRun].ChildIrp->UserBuffer = ((PCHAR) SystemBuffer) + ulReadOffset;
204 IoRuns[ulCurrRun].ChildIrp->Tail.Overlay.Thread = PsGetCurrentThread();
205 IoRuns[ulCurrRun].ChildIrp->RequestorMode = KernelMode;
206 IoRuns[ulCurrRun].ChildIrp->MdlAddress = NULL;
211 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
213 // Move cursors forward
215 pExtent = pNextExtent;
216 liFileOffset = pExtent->FileOffset;
219 ASSERT(ulCurrRun <= *RunCount);
221 if (!NT_SUCCESS(ntStatus))
223 for (ulCurrRun = 0 ; ulCurrRun < *RunCount; ulCurrRun++)
225 if (IoRuns[ulCurrRun].ChildIrp) {
226 IoFreeIrp( IoRuns[ulCurrRun].ChildIrp );
227 IoRuns[ulCurrRun].ChildIrp = NULL;
233 *RunCount = ulCurrRun;
240 // We manage our own scatter / gather. This completion
241 // function calls into our generic function.
246 CompletionFunction(IN PDEVICE_OBJECT DeviceObject,
250 AFSGatherIo *pGather = (AFSGatherIo *) Context;
252 AFSCompleteIo( pGather, Irp->IoStatus.Status);
254 if (Irp->MdlAddress) {
255 if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
256 MmUnlockPages(Irp->MdlAddress);
258 IoFreeMdl(Irp->MdlAddress);
259 Irp->MdlAddress = NULL;
264 // Tell io manager that we own the Irp
266 return STATUS_MORE_PROCESSING_REQUIRED;
270 AFSStartIos( IN PFILE_OBJECT CacheFileObject,
271 IN UCHAR FunctionCode,
275 IN OUT AFSGatherIo *Gather)
278 AFSDeviceExt *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
279 PIO_STACK_LOCATION pIoStackLocation = NULL;
281 NTSTATUS ntStatus = STATUS_SUCCESS;
282 PDEVICE_OBJECT pDeviceObject = NULL;
287 pDeviceObject = IoGetRelatedDeviceObject( CacheFileObject);
289 for (ULONG i = 0; i < Count; i++)
292 pIrp = IoRun[i].ChildIrp;
294 pIoStackLocation = IoGetNextIrpStackLocation( pIrp);
296 pIrp->Flags = IrpFlags;
297 pIoStackLocation->MajorFunction = FunctionCode;
298 pIoStackLocation->DeviceObject = pDeviceObject;
299 pIoStackLocation->FileObject = CacheFileObject;
300 pIoStackLocation->Parameters.Write.Length = IoRun[i].ByteCount;
301 pIoStackLocation->Parameters.Write.ByteOffset = IoRun[i].CacheOffset;
304 // Bump the count *before* we start the IO, that way if it
305 // completes real fast it will still not set the event
307 InterlockedIncrement(&Gather->Count);
310 // Set the completion routine.
313 IoSetCompletionRoutine( pIrp,
321 // Send it to the Cache
324 ntStatus = IoCallDriver( pDeviceObject,
327 if( !NT_SUCCESS( ntStatus))
338 AFSCompleteIo( IN AFSGatherIo *Gather,
341 if (!NT_SUCCESS(Status)) {
343 Gather->Status = Status;
346 if (0 == InterlockedDecrement( &Gather->Count )) {
348 // Last outstanding IO. Complete the parent and
349 // do whatever it takes to clean up
351 if (!NT_SUCCESS(Gather->Status))
353 Gather->MasterIrp->IoStatus.Status = Gather->Status;
354 Gather->MasterIrp->IoStatus.Information = 0;
357 if( Gather->CompleteMasterIrp)
360 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
361 AFS_TRACE_LEVEL_VERBOSE,
362 "AFSCompleteIo Completing Irp %08lX Status %08lX\n",
366 AFSCompleteRequest(Gather->MasterIrp, Gather->Status);
369 if (Gather->Synchronous)
372 // Someone was waiting for us tell them. They also own
373 // the data structure so we don't free it
375 KeSetEvent( &Gather->Event,
382 AFSExFreePool( Gather);
387 static AFSExtent *ExtentFor(PLIST_ENTRY le)
389 return CONTAINING_RECORD( le, AFSExtent, Lists[AFS_EXTENTS_LIST] );
392 static AFSExtent *NextExtent(AFSExtent *Extent)
394 return ExtentFor(Extent->Lists[AFS_EXTENTS_LIST].Flink);
398 AFSProcessExtentRun( IN PVOID SystemBuffer,
399 IN PLARGE_INTEGER Start,
402 IN BOOLEAN WriteRequest)
405 LARGE_INTEGER liCacheOffset;
406 LARGE_INTEGER liFileOffset = *Start;
410 AFSExtent *pExtent = From;
411 AFSExtent *pNextExtent;
413 BOOLEAN done = FALSE;
414 NTSTATUS ntStatus = STATUS_SUCCESS;
421 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
423 liCacheOffset = pExtent->CacheOffset;
424 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
425 pExtent->FileOffset.QuadPart);
430 // While there is still data to process, loop
432 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
433 (Start->QuadPart + Length) )
436 // Collapse the read if we can
438 pNextExtent = NextExtent( pExtent );
440 if (pNextExtent->CacheOffset.QuadPart !=
441 (pExtent->CacheOffset.QuadPart + pExtent->Size))
444 // This extent and the next extent are not contiguous
448 pExtent = pNextExtent;
452 // So, this run goes from liCacheOffset to the end of pExtent
455 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
458 // The last extent overruns the area we care
459 // about, so trim it back.
461 ulCurrLength = (ULONG) (Start->QuadPart + Length -
462 liFileOffset.QuadPart);
471 // Length is from the LiFileOffset to the end of this
474 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
475 liFileOffset.QuadPart);
480 // Calculate the offset into the buffer
482 ulOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
488 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
489 ((char *)SystemBuffer + ulOffset),
492 ASSERT( liCacheOffset.HighPart == 0);
493 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
494 ((char *)SystemBuffer + ulOffset),
502 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
503 ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
506 ASSERT( liCacheOffset.HighPart == 0);
507 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
508 ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
516 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
518 // Move cursors forward
520 pExtent = pNextExtent;
521 liFileOffset = pExtent->FileOffset;