5fc49adc328decf4d0dc33d1673921bf92fc3c62
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSClose.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: AFSClose.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSClose
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_CLOSE dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSClose( IN PDEVICE_OBJECT LibDeviceObject,
55           IN PIRP Irp)
56 {
57     UNREFERENCED_PARAMETER(LibDeviceObject);
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
60     AFSFcb *pFcb = NULL;
61     AFSDeviceExt *pDeviceExt = NULL;
62     AFSCcb *pCcb = NULL;
63     AFSObjectInfoCB *pObjectInfo = NULL;
64     AFSObjectInfoCB *pParentObjectInfo = NULL;
65     AFSDirectoryCB *pDirCB = NULL;
66     LONG lCount;
67
68     __try
69     {
70
71         if( AFSRDRDeviceObject == NULL)
72         {
73
74             //
75             // Let this through, it's an close on the library control device
76             //
77
78             try_return( ntStatus);
79         }
80
81         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
82
83         pIrpSp = IoGetCurrentIrpStackLocation( Irp);
84
85         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
86
87         if( pFcb == NULL)
88         {
89             try_return( ntStatus);
90         }
91
92         pObjectInfo = pFcb->ObjectInformation;
93
94         //
95         // Perform the close functionality depending on the type of node it is
96         //
97
98         switch( pFcb->Header.NodeTypeCode)
99         {
100
101             case AFS_IOCTL_FCB:
102             {
103
104                 AFSPIOCtlOpenCloseRequestCB stPIOCtlClose;
105                 AFSFileID stParentFileId;
106
107                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
108                               AFS_TRACE_LEVEL_VERBOSE,
109                               "AFSClose Acquiring GlobalRoot lock %p EXCL %08lX\n",
110                               &pFcb->NPFcb->Resource,
111                               PsGetCurrentThread()));
112
113                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
114                                   TRUE);
115
116                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
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                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
185
186                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
187                               AFS_TRACE_LEVEL_VERBOSE,
188                               "AFSClose (IOCtl) Decrement count on Fcb %p Cnt %d\n",
189                               pFcb,
190                               lCount));
191
192                 ASSERT( lCount >= 0);
193
194                 break;
195             }
196
197             case AFS_ROOT_ALL:
198             {
199
200                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
201                               AFS_TRACE_LEVEL_VERBOSE,
202                               "AFSClose Acquiring Special Root ALL lock %p EXCL %08lX\n",
203                               &pFcb->NPFcb->Resource,
204                               PsGetCurrentThread()));
205
206                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
207                                 TRUE);
208
209                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
210
211                 //
212                 // Remove the Ccb and de-allocate it
213                 //
214
215                 AFSRemoveCcb( pFcb,
216                               pCcb);
217
218                 AFSReleaseResource( &pFcb->NPFcb->Resource);
219
220                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
221
222                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
223                               AFS_TRACE_LEVEL_VERBOSE,
224                               "AFSClose (RootAll) Decrement count on Fcb %p Cnt %d\n",
225                               pFcb,
226                               lCount));
227
228                 ASSERT( lCount >= 0);
229
230                 break;
231             }
232
233             //
234             // Root, file or directory node
235             //
236
237             case AFS_FILE_FCB:
238             case AFS_ROOT_FCB:
239             case AFS_DIRECTORY_FCB:
240             case AFS_SYMBOLIC_LINK_FCB:
241             case AFS_MOUNT_POINT_FCB:
242             case AFS_DFS_LINK_FCB:
243             case AFS_INVALID_FCB:
244             {
245
246                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
247
248                 //
249                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
250                 //
251
252                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
253                               AFS_TRACE_LEVEL_VERBOSE,
254                               "AFSClose Acquiring Dcb lock %p EXCL %08lX\n",
255                               &pFcb->NPFcb->Resource,
256                               PsGetCurrentThread()));
257
258                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
259                                 TRUE);
260
261                 KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount);
262
263                 if( pFcb->OpenReferenceCount == 1 &&
264                     pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
265                 {
266
267                     SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED);
268
269                     //
270                     // Attempt to tear down our extent list for the file
271                     // If there are remaining dirty extents then attempt to
272                     // flush them as well
273                     //
274
275                     if( pFcb->Specific.File.ExtentsDirtyCount)
276                     {
277
278                         AFSFlushExtents( pFcb,
279                                          &pCcb->AuthGroup);
280                     }
281
282                     //
283                     // Wait for any outstanding queued flushes to complete
284                     //
285
286                     AFSWaitOnQueuedFlushes( pFcb);
287
288                     ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 &&
289                             pFcb->Specific.File.QueuedFlushCount == 0);
290
291                     AFSReleaseResource( &pFcb->NPFcb->Resource);
292
293                     //
294                     // Tear 'em down, we'll not be needing them again
295                     //
296
297                     AFSTearDownFcbExtents( pFcb,
298                                            &pCcb->AuthGroup);
299                 }
300                 else
301                 {
302
303                     if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
304                         pFcb->Specific.File.ExtentsDirtyCount &&
305                         (pCcb->GrantedAccess & FILE_WRITE_DATA))
306                     {
307
308                         AFSFlushExtents( pFcb,
309                                          &pCcb->AuthGroup);
310                     }
311
312                     AFSReleaseResource( &pFcb->NPFcb->Resource);
313                 }
314
315                 pDirCB = pCcb->DirectoryCB;
316
317                 //
318                 // Steal the DirOpenReferenceCount from the Ccb
319                 //
320
321                 pCcb->DirectoryCB = NULL;
322
323                 //
324                 // Object the Parent ObjectInformationCB
325                 //
326
327                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
328                 {
329
330                     pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
331                                                            &pObjectInfo->ParentFileId,
332                                                            FALSE);
333                 }
334
335                 //
336                 // Remove the Ccb and de-allocate it
337                 //
338
339                 AFSRemoveCcb( pFcb,
340                               pCcb);
341
342                 //
343                 // If this entry is deleted then remove the object from the volume tree
344                 //
345
346                 if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED))
347                 {
348
349                     if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
350                         pObjectInfo->Links == 0)
351                     {
352
353                         //
354                         // Stop anything possibly in process
355                         //
356
357                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
358                                       AFS_TRACE_LEVEL_VERBOSE,
359                                       "AFSClose Acquiring Fcb extents lock %p EXCL %08lX\n",
360                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
361                                       PsGetCurrentThread()));
362
363                         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
364                                         TRUE);
365
366                         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
367
368                         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
369                                     0,
370                                     FALSE);
371
372                         AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
373                                       AFS_TRACE_LEVEL_VERBOSE,
374                                       "AFSClose Releasing Fcb extents lock %p EXCL %08lX\n",
375                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
376                                       PsGetCurrentThread()));
377
378                         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
379                     }
380
381                     ASSERT( pParentObjectInfo != NULL);
382
383                     if ( pParentObjectInfo != NULL)
384                     {
385                         AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
386                                         TRUE);
387
388                         AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
389                                         TRUE);
390
391                         lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
392
393                         AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
394                                       AFS_TRACE_LEVEL_VERBOSE,
395                                       "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
396                                       &pDirCB->NameInformation.FileName,
397                                       pDirCB,
398                                       pCcb,
399                                       lCount));
400
401                         ASSERT( lCount >= 0);
402
403                         if( lCount == 0 &&
404                             pDirCB->NameArrayReferenceCount <= 0)
405                         {
406
407                             AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
408                                           AFS_TRACE_LEVEL_VERBOSE,
409                                           "AFSClose Deleting dir entry %p (%p) for %wZ  FID %08lX-%08lX-%08lX-%08lX\n",
410                                           pDirCB,
411                                           pObjectInfo,
412                                           &pDirCB->NameInformation.FileName,
413                                           pObjectInfo->FileId.Cell,
414                                           pObjectInfo->FileId.Volume,
415                                           pObjectInfo->FileId.Vnode,
416                                           pObjectInfo->FileId.Unique));
417
418                             //
419                             // Remove and delete the directory entry from the parent list
420                             //
421
422                             AFSDeleteDirEntry( pParentObjectInfo,
423                                                &pDirCB);
424
425                             AFSAcquireShared( &pObjectInfo->NonPagedInfo->ObjectInfoLock,
426                                               TRUE);
427
428                             if( pObjectInfo->ObjectReferenceCount <= 0)
429                             {
430
431                                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
432                                 {
433
434                                     AFSDbgTrace(( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
435                                                   AFS_TRACE_LEVEL_VERBOSE,
436                                                   "AFSClose Removing object %p from volume tree\n",
437                                                   pObjectInfo));
438
439                                     AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
440                                                         &pObjectInfo->TreeEntry);
441
442                                     ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE);
443                                 }
444                             }
445
446                             AFSReleaseResource( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
447                         }
448
449                         AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
450
451                         AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
452                     }
453                 }
454                 else
455                 {
456
457                     lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
458
459                     AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
460                                   AFS_TRACE_LEVEL_VERBOSE,
461                                   "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
462                                   &pDirCB->NameInformation.FileName,
463                                   pDirCB,
464                                   pCcb,
465                                   lCount));
466
467                     ASSERT( lCount >= 0);
468                 }
469
470                 //
471                 // If this is not the root then decrement the open child reference count
472                 //
473
474                 if( pObjectInfo != NULL &&
475                     pParentObjectInfo != NULL &&
476                     pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount > 0)
477                 {
478
479                     InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount);
480
481                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
482                                   AFS_TRACE_LEVEL_VERBOSE,
483                                   "AFSClose Decrement child open ref count on Parent object %p Cnt %d\n",
484                                   pParentObjectInfo,
485                                   pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount));
486                 }
487
488                 //
489                 // Decrement the reference count on the Fcb. this is protecting it from teardown.
490                 //
491
492                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
493
494                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
495                               AFS_TRACE_LEVEL_VERBOSE,
496                               "AFSClose Decrement count on Fcb %p Cnt %d\n",
497                               pFcb,
498                               lCount));
499
500                 ASSERT( lCount >= 0);
501
502                 break;
503             }
504
505             case AFS_SPECIAL_SHARE_FCB:
506             {
507
508                 AFSPipeOpenCloseRequestCB stPipeClose;
509
510                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
511
512                 //
513                 // Object the Parent ObjectInformationCB
514                 //
515
516                 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
517                 {
518
519                     pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
520                                                            &pObjectInfo->ParentFileId,
521                                                            FALSE);
522                 }
523
524                 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
525                               AFS_TRACE_LEVEL_VERBOSE,
526                               "AFSClose Acquiring Special Share lock %p EXCL %08lX\n",
527                               &pFcb->NPFcb->Resource,
528                               PsGetCurrentThread()));
529
530                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
531                                 TRUE);
532
533                 RtlZeroMemory( &stPipeClose,
534                                sizeof( AFSPipeOpenCloseRequestCB));
535
536                 stPipeClose.RequestId = pCcb->RequestID;
537
538                 stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
539
540                 //
541                 // Issue the open request to the service
542                 //
543
544                 /*
545                 AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_CLOSE,
546                                    AFS_REQUEST_FLAG_SYNCHRONOUS,
547                                    &pFcb->AuthGroup,
548                                    &pDirCB->NameInformation.FileName,
549                                    NULL,
550                                    NULL,
551                                    0,
552                                    (void *)&stPipeClose,
553                                    sizeof( AFSPipeOpenCloseRequestCB),
554                                    NULL,
555                                    NULL);
556                 */
557
558                 //
559                 // Remove the Ccb and de-allocate it
560                 //
561
562                 AFSRemoveCcb( pFcb,
563                               pCcb);
564
565                 //
566                 // If this is not the root then decrement the open child reference count
567                 //
568
569                 if( pParentObjectInfo != NULL &&
570                     pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount > 0)
571                 {
572
573                     lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount);
574
575                     AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
576                                   AFS_TRACE_LEVEL_VERBOSE,
577                                   "AFSClose (Share) Decrement child open ref count on Parent object %p Cnt %d\n",
578                                   pParentObjectInfo,
579                                   lCount));
580                 }
581
582                 AFSReleaseResource( &pFcb->NPFcb->Resource);
583
584                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
585
586                 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
587                               AFS_TRACE_LEVEL_VERBOSE,
588                               "AFSClose (Share) Decrement count on Fcb %p Cnt %d\n",
589                               pFcb,
590                               lCount));
591
592                 ASSERT( lCount >= 0);
593
594                 break;
595             }
596
597             default:
598
599                 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
600                               AFS_TRACE_LEVEL_ERROR,
601                               "AFSClose Processing unknown node type %d\n",
602                               pFcb->Header.NodeTypeCode));
603
604                 break;
605         }
606
607 try_exit:
608
609         //
610         // Complete the request
611         //
612
613         AFSCompleteRequest( Irp,
614                             ntStatus);
615     }
616     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
617     {
618
619         AFSDbgTrace(( 0,
620                       0,
621                       "EXCEPTION - AFSClose\n"));
622
623         AFSDumpTraceFilesFnc();
624     }
625
626     if ( pParentObjectInfo != NULL)
627     {
628
629         AFSReleaseObjectInfo( &pParentObjectInfo);
630     }
631
632     return ntStatus;
633 }