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