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;
288 pDeviceObject = IoGetRelatedDeviceObject( CacheFileObject);
290 for (ULONG i = 0; i < Count; i++)
293 pIrp = IoRun[i].ChildIrp;
295 pIoStackLocation = IoGetNextIrpStackLocation( pIrp);
297 pIrp->Flags = IrpFlags;
298 pIoStackLocation->MajorFunction = FunctionCode;
299 pIoStackLocation->DeviceObject = pDeviceObject;
300 pIoStackLocation->FileObject = CacheFileObject;
301 pIoStackLocation->Parameters.Write.Length = IoRun[i].ByteCount;
302 pIoStackLocation->Parameters.Write.ByteOffset = IoRun[i].CacheOffset;
305 // Bump the count *before* we start the IO, that way if it
306 // completes real fast it will still not set the event
308 lCount = InterlockedIncrement(&Gather->Count);
311 // Set the completion routine.
314 IoSetCompletionRoutine( pIrp,
322 // Send it to the Cache
325 ntStatus = IoCallDriver( pDeviceObject,
328 if( !NT_SUCCESS( ntStatus))
339 AFSCompleteIo( IN AFSGatherIo *Gather,
344 if (!NT_SUCCESS(Status)) {
346 Gather->Status = Status;
349 lCount = InterlockedDecrement( &Gather->Count );
353 // Last outstanding IO. Complete the parent and
354 // do whatever it takes to clean up
356 if (!NT_SUCCESS(Gather->Status))
358 Gather->MasterIrp->IoStatus.Status = Gather->Status;
359 Gather->MasterIrp->IoStatus.Information = 0;
362 if( Gather->CompleteMasterIrp)
365 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
366 AFS_TRACE_LEVEL_VERBOSE,
367 "AFSCompleteIo Completing Irp %08lX Status %08lX\n",
371 AFSCompleteRequest(Gather->MasterIrp, Gather->Status);
374 if (Gather->Synchronous)
377 // Someone was waiting for us tell them. They also own
378 // the data structure so we don't free it
380 KeSetEvent( &Gather->Event,
387 AFSExFreePool( Gather);
392 static AFSExtent *ExtentFor(PLIST_ENTRY le)
394 return CONTAINING_RECORD( le, AFSExtent, Lists[AFS_EXTENTS_LIST] );
397 static AFSExtent *NextExtent(AFSExtent *Extent)
399 return ExtentFor(Extent->Lists[AFS_EXTENTS_LIST].Flink);
403 AFSProcessExtentRun( IN PVOID SystemBuffer,
404 IN PLARGE_INTEGER Start,
407 IN BOOLEAN WriteRequest)
410 LARGE_INTEGER liCacheOffset;
411 LARGE_INTEGER liFileOffset = *Start;
415 AFSExtent *pExtent = From;
416 AFSExtent *pNextExtent;
418 BOOLEAN done = FALSE;
419 NTSTATUS ntStatus = STATUS_SUCCESS;
426 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
428 liCacheOffset = pExtent->CacheOffset;
429 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
430 pExtent->FileOffset.QuadPart);
435 // While there is still data to process, loop
437 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
438 (Start->QuadPart + Length) )
441 // Collapse the read if we can
443 pNextExtent = NextExtent( pExtent );
445 if (pNextExtent->CacheOffset.QuadPart !=
446 (pExtent->CacheOffset.QuadPart + pExtent->Size))
449 // This extent and the next extent are not contiguous
453 pExtent = pNextExtent;
457 // So, this run goes from liCacheOffset to the end of pExtent
460 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
463 // The last extent overruns the area we care
464 // about, so trim it back.
466 ulCurrLength = (ULONG) (Start->QuadPart + Length -
467 liFileOffset.QuadPart);
476 // Length is from the LiFileOffset to the end of this
479 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
480 liFileOffset.QuadPart);
485 // Calculate the offset into the buffer
487 ulOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
493 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
494 ((char *)SystemBuffer + ulOffset),
497 ASSERT( liCacheOffset.HighPart == 0);
498 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
499 ((char *)SystemBuffer + ulOffset),
507 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
508 ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
511 ASSERT( liCacheOffset.HighPart == 0);
512 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
513 ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
521 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
523 // Move cursors forward
525 pExtent = pNextExtent;
526 liFileOffset = pExtent->FileOffset;