Windows: Skip Extent operations if Direct IO
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSClose.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011, 2012, 2013 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, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16  *   nor the names of their contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission from Kernel Drivers, LLC and Your File System, Inc.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 //
34 // File: AFSClose.cpp
35 //
36
37 #include "AFSCommon.h"
38
39 //
40 // Function: AFSClose
41 //
42 // Description:
43 //
44 //      This function is the IRP_MJ_CLOSE dispatch handler
45 //
46 // Return:
47 //
48 //       A status is returned for the handling of this request
49 //
50
51 NTSTATUS
52 AFSClose( IN PDEVICE_OBJECT LibDeviceObject,
53           IN PIRP Irp)
54 {
55     UNREFERENCED_PARAMETER(LibDeviceObject);
56     NTSTATUS ntStatus = STATUS_SUCCESS;
57     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
58     AFSFcb *pFcb = NULL;
59     AFSDeviceExt *pDeviceExt = NULL;
60     AFSCcb *pCcb = NULL;
61     AFSObjectInfoCB *pObjectInfo = NULL;
62     AFSObjectInfoCB *pParentObjectInfo = NULL;
63     AFSDirectoryCB *pDirCB = NULL;
64     LONG lCount;
65
66     __try
67     {
68
69         if( AFSRDRDeviceObject == NULL)
70         {
71
72             //
73             // Let this through, it's an close on the library control device
74             //
75
76             try_return( ntStatus);
77         }
78
79         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
80
81         pIrpSp = IoGetCurrentIrpStackLocation( Irp);
82
83         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
84
85         if( pFcb == NULL)
86         {
87             try_return( ntStatus);
88         }
89
90         pObjectInfo = pFcb->ObjectInformation;
91
92         //
93         // Perform the close functionality depending on the type of node it is
94         //
95
96         switch( pFcb->Header.NodeTypeCode)
97         {
98
99             case AFS_IOCTL_FCB:
100             {
101
102                 AFSPIOCtlOpenCloseRequestCB stPIOCtlClose;
103                 AFSFileID stParentFileId;
104
105                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
106                               AFS_TRACE_LEVEL_VERBOSE,
107                               "AFSClose Acquiring GlobalRoot lock %p EXCL %08lX\n",
108                               &pFcb->NPFcb->Resource,
109                               PsGetCurrentThread()));
110
111                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
112                                   TRUE);
113
114                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
115
116                 pIrpSp->FileObject->FsContext2 = NULL;
117
118                 //
119                 // Send the close to the CM
120                 //
121
122                 RtlZeroMemory( &stPIOCtlClose,
123                                sizeof( AFSPIOCtlOpenCloseRequestCB));
124
125                 stPIOCtlClose.RequestId = pCcb->RequestID;
126
127                 stPIOCtlClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
128
129                 RtlZeroMemory( &stParentFileId,
130                                sizeof( AFSFileID));
131
132                 stParentFileId = pObjectInfo->ParentFileId;
133
134                 //
135                 // Issue the close request to the service
136                 //
137
138                 AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_CLOSE,
139                                    AFS_REQUEST_FLAG_SYNCHRONOUS,
140                                    &pCcb->AuthGroup,
141                                    NULL,
142                                    &stParentFileId,
143                                    NULL,
144                                    0,
145                                    (void *)&stPIOCtlClose,
146                                    sizeof( AFSPIOCtlOpenCloseRequestCB),
147                                    NULL,
148                                    NULL);
149
150                 //
151                 // Remove the Ccb and de-allocate it
152                 //
153
154                 AFSRemoveCcb( pFcb,
155                               pCcb);
156
157                 //
158                 // If this is not the root then decrement the open child reference count
159                 //
160
161                 if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
162                 {
163
164                     pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
165                                                            &pObjectInfo->ParentFileId,
166                                                            FALSE);
167                 }
168
169                 if( pParentObjectInfo != NULL &&
170                     pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount > 0)
171                 {
172
173                     InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount);
174
175                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
176                                   AFS_TRACE_LEVEL_VERBOSE,
177                                   "AFSClose (IOCtl) Decrement child open ref count on Parent object %p Cnt %d\n",
178                                   pParentObjectInfo,
179                                   pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount));
180                 }
181
182                 AFSReleaseResource( &pFcb->NPFcb->Resource);
183
184                 pIrpSp->FileObject->FsContext = NULL;
185
186                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
187
188                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
189                               AFS_TRACE_LEVEL_VERBOSE,
190                               "AFSClose (IOCtl) Decrement count on Fcb %p Cnt %d\n",
191                               pFcb,
192                               lCount));
193
194                 ASSERT( lCount >= 0);
195
196                 break;
197             }
198
199             case AFS_ROOT_ALL:
200             {
201
202                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
203                               AFS_TRACE_LEVEL_VERBOSE,
204                               "AFSClose Acquiring Special Root ALL lock %p EXCL %08lX\n",
205                               &pFcb->NPFcb->Resource,
206                               PsGetCurrentThread()));
207
208                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
209                                 TRUE);
210
211                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
212
213                 pIrpSp->FileObject->FsContext2;
214
215                 //
216                 // Remove the Ccb and de-allocate it
217                 //
218
219                 AFSRemoveCcb( pFcb,
220                               pCcb);
221
222                 AFSReleaseResource( &pFcb->NPFcb->Resource);
223
224                 pIrpSp->FileObject->FsContext = NULL;
225
226                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
227
228                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
229                               AFS_TRACE_LEVEL_VERBOSE,
230                               "AFSClose (RootAll) Decrement count on Fcb %p Cnt %d\n",
231                               pFcb,
232                               lCount));
233
234                 ASSERT( lCount >= 0);
235
236                 break;
237             }
238
239             //
240             // Root, file or directory node
241             //
242
243             case AFS_FILE_FCB:
244             case AFS_ROOT_FCB:
245             case AFS_DIRECTORY_FCB:
246             case AFS_SYMBOLIC_LINK_FCB:
247             case AFS_MOUNT_POINT_FCB:
248             case AFS_DFS_LINK_FCB:
249             case AFS_INVALID_FCB:
250             {
251
252                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
253
254                 pIrpSp->FileObject->FsContext2 = NULL;
255
256                 //
257                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
258                 //
259
260                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
261                               AFS_TRACE_LEVEL_VERBOSE,
262                               "AFSClose Acquiring Dcb lock %p EXCL %08lX\n",
263                               &pFcb->NPFcb->Resource,
264                               PsGetCurrentThread()));
265
266                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
267                                 TRUE);
268
269                 KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount);
270
271                 if( pFcb->OpenReferenceCount == 1 &&
272                     pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
273                 {
274
275                     SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED);
276
277                     if( !BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_DIRECT_SERVICE_IO))
278                     {
279
280                         //
281                         // Attempt to tear down our extent list for the file
282                         // If there are remaining dirty extents then attempt to
283                         // flush them as well
284                         //
285
286                         if( pFcb->Specific.File.ExtentsDirtyCount)
287                         {
288
289                             AFSFlushExtents( pFcb,
290                                              &pCcb->AuthGroup);
291                         }
292
293                         //
294                         // Wait for any outstanding queued flushes to complete
295                         //
296
297                         AFSWaitOnQueuedFlushes( pFcb);
298
299                         ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 &&
300                                 pFcb->Specific.File.QueuedFlushCount == 0);
301
302                         AFSReleaseResource( &pFcb->NPFcb->Resource);
303
304                         //
305                         // Tear 'em down, we'll not be needing them again
306                         //
307
308                         AFSTearDownFcbExtents( pFcb,
309                                                &pCcb->AuthGroup);
310                     }
311                     else
312                     {
313
314                         if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
315                             pFcb->Specific.File.ExtentsDirtyCount &&
316                             (pCcb->GrantedAccess & FILE_WRITE_DATA))
317                         {
318
319                             AFSFlushExtents( pFcb,
320                                              &pCcb->AuthGroup);
321                         }
322
323                         AFSReleaseResource( &pFcb->NPFcb->Resource);
324                     }
325                 }
326                 else
327                 {
328
329                     AFSReleaseResource( &pFcb->NPFcb->Resource);
330                 }
331
332                 pDirCB = pCcb->DirectoryCB;
333
334                 //
335                 // Steal the DirOpenReferenceCount from the Ccb
336                 //
337
338                 pCcb->DirectoryCB = NULL;
339
340                 //
341                 // Object the Parent ObjectInformationCB
342                 //
343
344                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
345                 {
346
347                     pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
348                                                            &pObjectInfo->ParentFileId,
349                                                            FALSE);
350                 }
351
352                 //
353                 // Remove the Ccb and de-allocate it
354                 //
355
356                 AFSRemoveCcb( pFcb,
357                               pCcb);
358
359                 //
360                 // If this entry is deleted then remove the object from the volume tree
361                 //
362
363                 if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED))
364                 {
365
366                     if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
367                         pObjectInfo->Links == 0)
368                     {
369
370                         //
371                         // Stop anything possibly in process
372                         //
373
374                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
375                                       AFS_TRACE_LEVEL_VERBOSE,
376                                       "AFSClose Acquiring Fcb extents lock %p EXCL %08lX\n",
377                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
378                                       PsGetCurrentThread()));
379
380                         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
381                                         TRUE);
382
383                         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
384
385                         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
386                                     0,
387                                     FALSE);
388
389                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
390                                       AFS_TRACE_LEVEL_VERBOSE,
391                                       "AFSClose Releasing Fcb extents lock %p EXCL %08lX\n",
392                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
393                                       PsGetCurrentThread()));
394
395                         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
396                     }
397
398                     ASSERT( pParentObjectInfo != NULL);
399
400                     if ( pParentObjectInfo != NULL)
401                     {
402                         AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
403                                         TRUE);
404
405                         AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
406                                         TRUE);
407
408                         lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
409
410                         AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
411                                       AFS_TRACE_LEVEL_VERBOSE,
412                                       "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
413                                       &pDirCB->NameInformation.FileName,
414                                       pDirCB,
415                                       pCcb,
416                                       lCount));
417
418                         ASSERT( lCount >= 0);
419
420                         if( lCount == 0 &&
421                             pDirCB->NameArrayReferenceCount <= 0)
422                         {
423
424                             AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
425                                           AFS_TRACE_LEVEL_VERBOSE,
426                                           "AFSClose Deleting dir entry %p (%p) for %wZ  FID %08lX-%08lX-%08lX-%08lX\n",
427                                           pDirCB,
428                                           pObjectInfo,
429                                           &pDirCB->NameInformation.FileName,
430                                           pObjectInfo->FileId.Cell,
431                                           pObjectInfo->FileId.Volume,
432                                           pObjectInfo->FileId.Vnode,
433                                           pObjectInfo->FileId.Unique));
434
435                             //
436                             // Remove and delete the directory entry from the parent list
437                             //
438
439                             AFSDeleteDirEntry( pParentObjectInfo,
440                                                &pDirCB);
441
442                             AFSAcquireShared( &pObjectInfo->NonPagedInfo->ObjectInfoLock,
443                                               TRUE);
444
445                             if( pObjectInfo->ObjectReferenceCount <= 0)
446                             {
447
448                                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
449                                 {
450
451                                     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
452                                                   AFS_TRACE_LEVEL_VERBOSE,
453                                                   "AFSClose Removing object %p from volume tree\n",
454                                                   pObjectInfo));
455
456                                     AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
457                                                         &pObjectInfo->TreeEntry);
458
459                                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE);
460                                 }
461                             }
462
463                             AFSReleaseResource( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
464                         }
465
466                         AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
467
468                         AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
469                     }
470                 }
471                 else
472                 {
473
474                     lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
475
476                     AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
477                                   AFS_TRACE_LEVEL_VERBOSE,
478                                   "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
479                                   &pDirCB->NameInformation.FileName,
480                                   pDirCB,
481                                   pCcb,
482                                   lCount));
483
484                     ASSERT( lCount >= 0);
485                 }
486
487                 //
488                 // If this is not the root then decrement the open child reference count
489                 //
490
491                 if( pObjectInfo != NULL &&
492                     pParentObjectInfo != NULL &&
493                     pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount > 0)
494                 {
495
496                     InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount);
497
498                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
499                                   AFS_TRACE_LEVEL_VERBOSE,
500                                   "AFSClose Decrement child open ref count on Parent object %p Cnt %d\n",
501                                   pParentObjectInfo,
502                                   pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount));
503                 }
504
505                 pIrpSp->FileObject->FsContext = NULL;
506
507                 //
508                 // Decrement the reference count on the Fcb. this is protecting it from teardown.
509                 //
510
511                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
512
513                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
514                               AFS_TRACE_LEVEL_VERBOSE,
515                               "AFSClose Decrement count on Fcb %p Cnt %d\n",
516                               pFcb,
517                               lCount));
518
519                 ASSERT( lCount >= 0);
520
521                 break;
522             }
523
524             case AFS_SPECIAL_SHARE_FCB:
525             {
526
527                 AFSPipeOpenCloseRequestCB stPipeClose;
528
529                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
530
531                 pIrpSp->FileObject->FsContext2 = NULL;
532
533                 //
534                 // Object the Parent ObjectInformationCB
535                 //
536
537                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
538                 {
539
540                     pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
541                                                            &pObjectInfo->ParentFileId,
542                                                            FALSE);
543                 }
544
545                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
546                               AFS_TRACE_LEVEL_VERBOSE,
547                               "AFSClose Acquiring Special Share lock %p EXCL %08lX\n",
548                               &pFcb->NPFcb->Resource,
549                               PsGetCurrentThread()));
550
551                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
552                                 TRUE);
553
554                 RtlZeroMemory( &stPipeClose,
555                                sizeof( AFSPipeOpenCloseRequestCB));
556
557                 stPipeClose.RequestId = pCcb->RequestID;
558
559                 stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
560
561                 //
562                 // Remove the Ccb and de-allocate it
563                 //
564
565                 AFSRemoveCcb( pFcb,
566                               pCcb);
567
568                 //
569                 // If this is not the root then decrement the open child reference count
570                 //
571
572                 if( pParentObjectInfo != NULL &&
573                     pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount > 0)
574                 {
575
576                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount);
577
578                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
579                                   AFS_TRACE_LEVEL_VERBOSE,
580                                   "AFSClose (Share) Decrement child open ref count on Parent object %p Cnt %d\n",
581                                   pParentObjectInfo,
582                                   lCount));
583                 }
584
585                 AFSReleaseResource( &pFcb->NPFcb->Resource);
586
587                 pIrpSp->FileObject->FsContext = NULL;
588
589                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
590
591                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
592                               AFS_TRACE_LEVEL_VERBOSE,
593                               "AFSClose (Share) Decrement count on Fcb %p Cnt %d\n",
594                               pFcb,
595                               lCount));
596
597                 ASSERT( lCount >= 0);
598
599                 break;
600             }
601
602             default:
603             {
604
605                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
606                               AFS_TRACE_LEVEL_ERROR,
607                               "AFSClose Processing unknown node type %d\n",
608                               pFcb->Header.NodeTypeCode));
609
610                 break;
611             }
612         }
613
614 try_exit:
615
616         //
617         // Complete the request
618         //
619
620         AFSCompleteRequest( Irp,
621                             ntStatus);
622     }
623     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
624     {
625
626         AFSDbgTrace(( 0,
627                       0,
628                       "EXCEPTION - AFSClose\n"));
629
630         AFSDumpTraceFilesFnc();
631     }
632
633     if ( pParentObjectInfo != NULL)
634     {
635
636         AFSReleaseObjectInfo( &pParentObjectInfo);
637     }
638
639     return ntStatus;
640 }