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