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 UNREFERENCED_PARAMETER(Fcb);
56 NTSTATUS ntStatus = STATUS_SUCCESS;
57 ULONG extentsCount = 0, runCount = 0;
58 AFSExtent *pEndExtent = NULL;
59 LARGE_INTEGER liLastCacheOffset;
65 ASSERT(AFSExtentContains(From, Offset));
70 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
72 while ((Offset->QuadPart + Length) >
73 pEndExtent->FileOffset.QuadPart + pEndExtent->Size) {
75 pEndExtent = NextExtent(pEndExtent, AFS_EXTENTS_LIST);
77 if (liLastCacheOffset.QuadPart != pEndExtent->CacheOffset.QuadPart) {
79 // Discontiguous (in the cache)
87 liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
90 *ExtentCount = extentsCount;
92 ntStatus = STATUS_SUCCESS;
99 AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice,
101 IN PVOID SystemBuffer,
102 IN OUT AFSIoRun *IoRuns,
103 IN PLARGE_INTEGER Start,
106 IN OUT ULONG *RunCount)
108 UNREFERENCED_PARAMETER(MasterIrp);
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 = NULL;
120 BOOLEAN done = FALSE;
121 NTSTATUS ntStatus = STATUS_SUCCESS;
128 ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
130 liCacheOffset = pExtent->CacheOffset;
131 liCacheOffset.QuadPart += (liFileOffset.QuadPart -
132 pExtent->FileOffset.QuadPart);
137 // While there is still data to process, loop
139 while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
140 (Start->QuadPart + Length) )
143 // Collapse the read if we can
145 pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST);
147 if (pNextExtent->CacheOffset.QuadPart !=
148 (pExtent->CacheOffset.QuadPart + pExtent->Size))
151 // This extent and the next extent are not contiguous
155 pExtent = pNextExtent;
159 // So, this run goes from liCacheOffset to the end of pExtent
162 if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
165 // The last extent overruns the area we care
166 // about, so trim it back.
168 ulCurrLength = (ULONG) (Start->QuadPart + Length -
169 liFileOffset.QuadPart);
178 // Length is from the LiFileOffset to the end of this
181 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
182 liFileOffset.QuadPart);
187 // Calculate the offset into the buffer
189 ulReadOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
191 IoRuns[ulCurrRun].CacheOffset = liCacheOffset;
192 IoRuns[ulCurrRun].ByteCount = ulCurrLength;
194 IoRuns[ulCurrRun].ChildIrp = IoAllocateIrp( CacheDevice->StackSize + 1,
197 if (NULL == IoRuns[ulCurrRun].ChildIrp)
199 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
202 IoRuns[ulCurrRun].ChildIrp->UserBuffer = ((PCHAR) SystemBuffer) + ulReadOffset;
203 IoRuns[ulCurrRun].ChildIrp->Tail.Overlay.Thread = PsGetCurrentThread();
204 IoRuns[ulCurrRun].ChildIrp->RequestorMode = KernelMode;
205 IoRuns[ulCurrRun].ChildIrp->MdlAddress = NULL;
210 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
212 // Move cursors forward
214 pExtent = pNextExtent;
215 liFileOffset = pExtent->FileOffset;
218 ASSERT(ulCurrRun <= *RunCount);
220 if (!NT_SUCCESS(ntStatus))
222 for (ulCurrRun = 0 ; ulCurrRun < *RunCount; ulCurrRun++)
224 if (IoRuns[ulCurrRun].ChildIrp) {
225 IoFreeIrp( IoRuns[ulCurrRun].ChildIrp );
226 IoRuns[ulCurrRun].ChildIrp = NULL;
232 *RunCount = ulCurrRun;
239 // We manage our own scatter / gather. This completion
240 // function calls into our generic function.
245 CompletionFunction(IN PDEVICE_OBJECT DeviceObject,
249 UNREFERENCED_PARAMETER(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 PIO_STACK_LOCATION pIoStackLocation = NULL;
280 NTSTATUS ntStatus = STATUS_SUCCESS;
281 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 lCount = 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,
343 if (!NT_SUCCESS(Status)) {
345 Gather->Status = Status;
348 lCount = InterlockedDecrement( &Gather->Count );
352 // Last outstanding IO. Complete the parent and
353 // do whatever it takes to clean up
355 if (!NT_SUCCESS(Gather->Status))
357 Gather->MasterIrp->IoStatus.Status = Gather->Status;
358 Gather->MasterIrp->IoStatus.Information = 0;
361 if( Gather->CompleteMasterIrp)
364 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
365 AFS_TRACE_LEVEL_VERBOSE,
366 "AFSCompleteIo Completing Irp %p Status %08lX\n",
370 AFSCompleteRequest(Gather->MasterIrp, Gather->Status);
373 if (Gather->Synchronous)
376 // Someone was waiting for us tell them. They also own
377 // the data structure so we don't free it
379 KeSetEvent( &Gather->Event,
386 AFSExFreePoolWithTag( Gather, AFS_GATHER_TAG);
392 AFSProcessExtentRun( IN PVOID SystemBuffer,
393 IN PLARGE_INTEGER Start,
396 IN BOOLEAN WriteRequest)
399 LARGE_INTEGER liCacheOffset;
400 LARGE_INTEGER liFileOffset = *Start;
404 AFSExtent *pExtent = From;
405 AFSExtent *pNextExtent = NULL;
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;