windows: Set ReparsePoint Attribute in FileAttributes
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSIoSupport.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
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.
21  *
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.
33  */
34
35 //
36 // File: AFSIoSupport.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 static AFSExtent *NextExtent(AFSExtent *Extent);
42
43 //
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.
47 //
48
49 NTSTATUS
50 AFSGetExtents( IN AFSFcb *Fcb,
51                IN PLARGE_INTEGER Offset,
52                IN ULONG Length,
53                OUT AFSExtent *From,
54                OUT ULONG *ExtentCount,
55                OUT ULONG *RunCount)
56 {
57     NTSTATUS           ntStatus = STATUS_SUCCESS;
58     ULONG              extentsCount = 0, runCount = 0;
59     AFSExtent         *pEndExtent = NULL;
60     LARGE_INTEGER      liLastCacheOffset;
61
62     *ExtentCount = 0;
63
64     __Enter
65     {
66         ASSERT(AFSExtentContains(From, Offset));
67
68         pEndExtent = From;
69         extentsCount = 1;
70         runCount = 1;
71         liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
72
73         while ((Offset->QuadPart + Length) >
74                pEndExtent->FileOffset.QuadPart + pEndExtent->Size) {
75
76             pEndExtent = NextExtent(pEndExtent);
77
78             if (liLastCacheOffset.QuadPart != pEndExtent->CacheOffset.QuadPart) {
79                 //
80                 // Discontiguous (in the cache)
81                 //
82                 runCount += 1;
83
84             }
85
86             extentsCount+= 1;
87
88             liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size;
89         }
90
91         *ExtentCount = extentsCount;
92         *RunCount = runCount;
93         ntStatus = STATUS_SUCCESS;
94     }
95     return ntStatus;
96 }
97
98
99 NTSTATUS
100 AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice,
101                IN PIRP           MasterIrp,
102                IN PVOID          SystemBuffer,
103                IN OUT AFSIoRun  *IoRuns,
104                IN PLARGE_INTEGER Start,
105                IN ULONG          Length,
106                IN AFSExtent     *From,
107                IN OUT ULONG     *RunCount)
108 {
109     //
110     // Do all the work which we can prior to firing off the IRP
111     // (allocate them, calculate offsets and so on)
112     //
113     LARGE_INTEGER  liCacheOffset;
114     LARGE_INTEGER  liFileOffset = *Start;
115     ULONG          ulCurrLength;
116     ULONG          ulReadOffset;
117     ULONG          ulCurrRun = 0;
118     AFSExtent     *pExtent = From;
119     AFSExtent     *pNextExtent;
120     PMDL          *pMDL;
121     BOOLEAN        done = FALSE;
122     NTSTATUS       ntStatus = STATUS_SUCCESS;
123
124     __Enter
125     {
126
127         while( !done)
128         {
129             ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
130
131             liCacheOffset = pExtent->CacheOffset;
132             liCacheOffset.QuadPart += (liFileOffset.QuadPart -
133                                        pExtent->FileOffset.QuadPart);
134
135             ulCurrLength = 0;
136
137             //
138             // While there is still data to process, loop
139             //
140             while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
141                     (Start->QuadPart + Length) )
142             {
143                 //
144                 // Collapse the read if we can
145                 //
146                 pNextExtent = NextExtent( pExtent );
147
148                 if (pNextExtent->CacheOffset.QuadPart !=
149                     (pExtent->CacheOffset.QuadPart + pExtent->Size))
150                 {
151                     //
152                     // This extent and the next extent are not contiguous
153                     //
154                     break;
155                 }
156                 pExtent = pNextExtent;
157             }
158
159             //
160             // So, this run goes from liCacheOffset to the end of pExtent
161             //
162
163             if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
164             {
165                 //
166                 // The last extent overruns the area we care
167                 // about, so trim it back.
168                 //
169                 ulCurrLength = (ULONG) (Start->QuadPart + Length -
170                                         liFileOffset.QuadPart);
171                 //
172                 // But we are done
173                 //
174                 done = TRUE;
175             }
176             else
177             {
178                 //
179                 // Length is from the LiFileOffset to the end of this
180                 // extent.
181                 //
182                 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
183                                         liFileOffset.QuadPart);
184                 done = FALSE;
185             }
186
187             //
188             // Calculate the offset into the buffer
189             //
190             ulReadOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
191
192             IoRuns[ulCurrRun].CacheOffset = liCacheOffset;
193             IoRuns[ulCurrRun].ByteCount = ulCurrLength;
194
195             IoRuns[ulCurrRun].ChildIrp = IoAllocateIrp( CacheDevice->StackSize + 1,
196                                                         FALSE);
197
198             if (NULL == IoRuns[ulCurrRun].ChildIrp)
199             {
200                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
201             }
202
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;
207
208             ulCurrRun ++;
209             if (!done)
210             {
211                 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
212                 //
213                 // Move cursors forward
214                 //
215                 pExtent = pNextExtent;
216                 liFileOffset = pExtent->FileOffset;
217             }
218         }
219         ASSERT(ulCurrRun <= *RunCount);
220 try_exit:
221         if (!NT_SUCCESS(ntStatus))
222         {
223             for (ulCurrRun = 0 ; ulCurrRun < *RunCount; ulCurrRun++)
224             {
225                 if (IoRuns[ulCurrRun].ChildIrp) {
226                     IoFreeIrp( IoRuns[ulCurrRun].ChildIrp );
227                     IoRuns[ulCurrRun].ChildIrp = NULL;
228                 }
229             }
230         }
231         else
232         {
233             *RunCount = ulCurrRun;
234         }
235     }
236     return ntStatus;
237 }
238
239 //
240 // We manage our own scatter / gather.  This completion
241 // function calls into our generic function.
242 //
243
244 static
245 NTSTATUS
246 CompletionFunction(IN PDEVICE_OBJECT DeviceObject,
247                    PIRP Irp,
248                    PVOID Context)
249 {
250     AFSGatherIo *pGather = (AFSGatherIo *) Context;
251
252     AFSCompleteIo( pGather, Irp->IoStatus.Status);
253
254     if (Irp->MdlAddress) {
255         if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) {
256             MmUnlockPages(Irp->MdlAddress);
257         }
258         IoFreeMdl(Irp->MdlAddress);
259         Irp->MdlAddress = NULL;
260     }
261     IoFreeIrp(Irp);
262
263     //
264     // Tell io manager that we own the Irp
265     //
266     return STATUS_MORE_PROCESSING_REQUIRED;
267 }
268
269 NTSTATUS
270 AFSStartIos( IN PFILE_OBJECT     CacheFileObject,
271              IN UCHAR            FunctionCode,
272              IN ULONG            IrpFlags,
273              IN AFSIoRun        *IoRun,
274              IN ULONG            Count,
275              IN OUT AFSGatherIo *Gather)
276 {
277
278     AFSDeviceExt       *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
279     PIO_STACK_LOCATION  pIoStackLocation = NULL;
280     PIRP                pIrp;
281     NTSTATUS            ntStatus = STATUS_SUCCESS;
282     PDEVICE_OBJECT      pDeviceObject = NULL;
283
284     __Enter
285     {
286
287         pDeviceObject = IoGetRelatedDeviceObject( CacheFileObject);
288
289         for (ULONG i = 0; i < Count; i++)
290         {
291
292             pIrp = IoRun[i].ChildIrp;
293
294             pIoStackLocation = IoGetNextIrpStackLocation( pIrp);
295
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;
302
303             //
304             // Bump the count *before* we start the IO, that way if it
305             // completes real fast it will still not set the event
306             //
307             InterlockedIncrement(&Gather->Count);
308
309             //
310             // Set the completion routine.
311             //
312
313             IoSetCompletionRoutine( pIrp,
314                                     CompletionFunction,
315                                     Gather,
316                                     TRUE,
317                                     TRUE,
318                                     TRUE);
319
320             //
321             // Send it to the Cache
322             //
323
324             ntStatus = IoCallDriver( pDeviceObject,
325                                      pIrp);
326
327             if( !NT_SUCCESS( ntStatus))
328             {
329                 break;
330             }
331         }
332     }
333
334     return ntStatus;
335 }
336
337 VOID
338 AFSCompleteIo( IN AFSGatherIo *Gather,
339                IN NTSTATUS Status)
340 {
341     if (!NT_SUCCESS(Status)) {
342
343         Gather->Status = Status;
344     }
345
346     if (0 == InterlockedDecrement( &Gather->Count )) {
347         //
348         // Last outstanding IO.  Complete the parent and
349         // do whatever it takes to clean up
350         //
351         if (!NT_SUCCESS(Gather->Status))
352         {
353             Gather->MasterIrp->IoStatus.Status = Gather->Status;
354             Gather->MasterIrp->IoStatus.Information = 0;
355         }
356
357         if( Gather->CompleteMasterIrp)
358         {
359
360             AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
361                           AFS_TRACE_LEVEL_VERBOSE,
362                           "AFSCompleteIo Completing Irp %08lX Status %08lX\n",
363                           Gather->MasterIrp,
364                           Gather->Status);
365
366             AFSCompleteRequest(Gather->MasterIrp, Gather->Status);
367         }
368
369         if (Gather->Synchronous)
370         {
371             //
372             // Someone was waiting for us tell them.  They also own
373             // the data structure so we don't free it
374             //
375             KeSetEvent( &Gather->Event,
376                         0,
377                         FALSE);
378         }
379         else
380         {
381
382             AFSExFreePool( Gather);
383         }
384     }
385 }
386
387 static AFSExtent *ExtentFor(PLIST_ENTRY le)
388 {
389     return CONTAINING_RECORD( le, AFSExtent, Lists[AFS_EXTENTS_LIST] );
390 }
391
392 static AFSExtent *NextExtent(AFSExtent *Extent)
393 {
394     return ExtentFor(Extent->Lists[AFS_EXTENTS_LIST].Flink);
395 }
396
397 NTSTATUS
398 AFSProcessExtentRun( IN PVOID          SystemBuffer,
399                      IN PLARGE_INTEGER Start,
400                      IN ULONG          Length,
401                      IN AFSExtent     *From,
402                      IN BOOLEAN        WriteRequest)
403 {
404
405     LARGE_INTEGER  liCacheOffset;
406     LARGE_INTEGER  liFileOffset = *Start;
407     ULONG          ulCurrLength;
408     ULONG          ulOffset = 0;
409     ULONG          ulCurrRun = 0;
410     AFSExtent     *pExtent = From;
411     AFSExtent     *pNextExtent;
412     PMDL          *pMDL;
413     BOOLEAN        done = FALSE;
414     NTSTATUS       ntStatus = STATUS_SUCCESS;
415
416     __Enter
417     {
418
419         while( !done)
420         {
421             ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart );
422
423             liCacheOffset = pExtent->CacheOffset;
424             liCacheOffset.QuadPart += (liFileOffset.QuadPart -
425                                        pExtent->FileOffset.QuadPart);
426
427             ulCurrLength = 0;
428
429             //
430             // While there is still data to process, loop
431             //
432             while ( (pExtent->FileOffset.QuadPart + pExtent->Size) <
433                     (Start->QuadPart + Length) )
434             {
435                 //
436                 // Collapse the read if we can
437                 //
438                 pNextExtent = NextExtent( pExtent );
439
440                 if (pNextExtent->CacheOffset.QuadPart !=
441                     (pExtent->CacheOffset.QuadPart + pExtent->Size))
442                 {
443                     //
444                     // This extent and the next extent are not contiguous
445                     //
446                     break;
447                 }
448                 pExtent = pNextExtent;
449             }
450
451             //
452             // So, this run goes from liCacheOffset to the end of pExtent
453             //
454
455             if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length))
456             {
457                 //
458                 // The last extent overruns the area we care
459                 // about, so trim it back.
460                 //
461                 ulCurrLength = (ULONG) (Start->QuadPart + Length -
462                                         liFileOffset.QuadPart);
463                 //
464                 // But we are done
465                 //
466                 done = TRUE;
467             }
468             else
469             {
470                 //
471                 // Length is from the LiFileOffset to the end of this
472                 // extent.
473                 //
474                 ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size -
475                                         liFileOffset.QuadPart);
476                 done = FALSE;
477             }
478
479             //
480             // Calculate the offset into the buffer
481             //
482             ulOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart);
483
484             if( WriteRequest)
485             {
486
487 #ifdef AMD64
488                 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
489                                ((char *)SystemBuffer + ulOffset),
490                                ulCurrLength);
491 #else
492                 ASSERT( liCacheOffset.HighPart == 0);
493                 RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
494                                ((char *)SystemBuffer + ulOffset),
495                                ulCurrLength);
496 #endif
497             }
498             else
499             {
500
501 #ifdef AMD64
502                 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
503                                ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart),
504                                ulCurrLength);
505 #else
506                 ASSERT( liCacheOffset.HighPart == 0);
507                 RtlCopyMemory( ((char *)SystemBuffer + ulOffset),
508                                ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart),
509                                ulCurrLength);
510 #endif
511             }
512
513             ulCurrRun ++;
514             if (!done)
515             {
516                 ASSERT(pNextExtent != NULL && pNextExtent != pExtent);
517                 //
518                 // Move cursors forward
519                 //
520                 pExtent = pNextExtent;
521                 liFileOffset = pExtent->FileOffset;
522             }
523         }
524     }
525
526     return ntStatus;
527 }