70e7f2427c0bc26820ec26ddd292326266b9b02e
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSCleanup.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: AFSCleanup.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSCleanup
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_CLEANUP dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
55             IN PIRP Irp)
56 {
57
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     AFSDeviceExt *pDeviceExt = NULL;
60     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
61     AFSFcb *pFcb = NULL;
62     AFSCcb *pCcb = NULL;
63     PFILE_OBJECT pFileObject = NULL;
64     AFSFcb *pRootFcb = NULL;
65     AFSDeviceExt *pControlDeviceExt = NULL;
66     IO_STATUS_BLOCK stIoSB;
67     AFSObjectInfoCB *pObjectInfo = NULL;
68     AFSFileCleanupCB stFileCleanup;
69     ULONG   ulNotificationFlags = 0;
70
71     __try
72     {
73
74         if( AFSRDRDeviceObject == NULL)
75         {
76
77             //
78             // Let this through, it's a cleanup on the library control device
79             //
80
81             try_return( ntStatus);
82         }
83
84         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
85         pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
86
87         //
88         // Set some initial variables to make processing easier
89         //
90
91         pFileObject = pIrpSp->FileObject;
92
93         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
94
95         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
96
97         if( pFcb == NULL)
98         {
99             try_return( ntStatus);
100         }
101
102         pObjectInfo = pFcb->ObjectInformation;
103
104         pRootFcb = pObjectInfo->VolumeCB->RootFcb;
105
106         RtlZeroMemory( &stFileCleanup,
107                        sizeof( AFSFileCleanupCB));
108
109         stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
110
111         stFileCleanup.Identifier = (ULONGLONG)pFileObject;
112
113         //
114         // Perform the cleanup functionality depending on the type of node it is
115         //
116
117         switch( pFcb->Header.NodeTypeCode)
118         {
119
120             case AFS_ROOT_ALL:
121             {
122
123                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
124                               AFS_TRACE_LEVEL_VERBOSE,
125                               "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
126                               &pFcb->NPFcb->Resource,
127                               PsGetCurrentThread());
128
129                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
130                                   TRUE);
131
132                 ASSERT( pFcb->OpenHandleCount != 0);
133
134                 InterlockedDecrement( &pFcb->OpenHandleCount);
135
136                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
137                               AFS_TRACE_LEVEL_VERBOSE,
138                               "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n",
139                               pFcb,
140                               pFcb->OpenHandleCount);
141
142                 AFSReleaseResource( &pFcb->NPFcb->Resource);
143
144                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
145                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
146                                     pCcb);
147
148                 break;
149             }
150
151             case AFS_IOCTL_FCB:
152             {
153
154                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
155                               AFS_TRACE_LEVEL_VERBOSE,
156                               "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n",
157                               &pFcb->NPFcb->Resource,
158                               PsGetCurrentThread());
159
160                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
161                                   TRUE);
162
163                 ASSERT( pFcb->OpenHandleCount != 0);
164
165                 InterlockedDecrement( &pFcb->OpenHandleCount);
166
167                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
168                               AFS_TRACE_LEVEL_VERBOSE,
169                               "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n",
170                               pFcb,
171                               pFcb->OpenHandleCount);
172
173                 //
174                 // Decrement the open child handle count
175                 //
176
177                 if( pObjectInfo->ParentObjectInformation != NULL &&
178                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
179                 {
180
181                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
182
183                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
184                                   AFS_TRACE_LEVEL_VERBOSE,
185                                   "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n",
186                                   pObjectInfo->ParentObjectInformation,
187                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
188                 }
189
190                 //
191                 // And finally, release the Fcb if we acquired it.
192                 //
193
194                 AFSReleaseResource( &pFcb->NPFcb->Resource);
195
196                 break;
197             }
198
199             //
200             // This Fcb represents a file
201             //
202
203             case AFS_FILE_FCB:
204             {
205
206                 //
207                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
208                 //
209
210                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
211                               AFS_TRACE_LEVEL_VERBOSE,
212                               "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n",
213                               &pFcb->NPFcb->Resource,
214                               PsGetCurrentThread());
215
216                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
217                                 TRUE);
218
219                 //
220                 // Uninitialize the cache map. This call is unconditional.
221                 //
222
223                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
224                               AFS_TRACE_LEVEL_VERBOSE,
225                               "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n",
226                               pFcb,
227                               pFileObject);
228
229                 CcUninitializeCacheMap( pFileObject,
230                                         NULL,
231                                         NULL);
232
233                 //
234                 // Unlock all outstanding locks on the file, again, unconditionally
235                 //
236
237                 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
238                                            pFileObject,
239                                            IoGetRequestorProcess( Irp),
240                                            NULL);
241
242                 //
243                 // Tell the service to unlock all on the file
244                 //
245
246                 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
247
248                 //
249                 // Perform some final common processing
250                 //
251
252                 ASSERT( pFcb->OpenHandleCount != 0);
253
254                 InterlockedDecrement( &pFcb->OpenHandleCount);
255
256                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
257                               AFS_TRACE_LEVEL_VERBOSE,
258                               "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n",
259                               pFcb,
260                               pFcb->OpenHandleCount);
261
262                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
263                 {
264
265                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
266                 }
267
268                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
269
270                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
271                 {
272
273                     stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
274
275                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
276
277                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
278                     {
279
280                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
281
282                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
283                     }
284
285                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
286                     {
287
288                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
289
290                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
291                     }
292
293                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
294                     {
295
296                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
297
298                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
299                     }
300
301                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
302                     {
303
304                         stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
305
306                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
307                     }
308                 }
309
310                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
311                 {
312
313                     stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
314                 }
315
316                 //
317                 // If the count has dropped to zero and there is a pending delete
318                 // then delete the node
319                 //
320
321                 if( pFcb->OpenHandleCount == 0 &&
322                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
323                 {
324
325                     //
326                     // Stop anything possibly in process
327                     //
328
329                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
330                                   AFS_TRACE_LEVEL_VERBOSE,
331                                   "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n",
332                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
333                                   PsGetCurrentThread());
334
335                     AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
336                                     TRUE);
337
338                     pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
339
340                     KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
341                                 0,
342                                 FALSE);
343
344                     AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
345                                   AFS_TRACE_LEVEL_VERBOSE,
346                                   "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n",
347                                   &pFcb->NPFcb->Specific.File.ExtentsResource,
348                                   PsGetCurrentThread());
349
350                     AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
351
352                     //
353                     // Before telling the server about the deleted file, tear down all extents for
354                     // the file
355                     //
356
357                     AFSTearDownFcbExtents( pFcb,
358                                            &pCcb->AuthGroup);
359
360                     ntStatus = STATUS_SUCCESS;
361
362                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
363
364                     //
365                     // Indicate the file access mode that is being released
366                     //
367
368                     stFileCleanup.FileAccess = pCcb->FileAccess;
369
370                     //
371                     // Push the request to the service
372                     //
373
374                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
375                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
376                                                   &pCcb->AuthGroup,
377                                                   &pCcb->DirectoryCB->NameInformation.FileName,
378                                                   &pObjectInfo->FileId,
379                                                   &stFileCleanup,
380                                                   sizeof( AFSFileCleanupCB),
381                                                   NULL,
382                                                   NULL);
383
384                     if( !NT_SUCCESS( ntStatus) &&
385                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
386                     {
387
388                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
389                                       AFS_TRACE_LEVEL_ERROR,
390                                       "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
391                                       &pCcb->FullFileName,
392                                       ntStatus);
393
394                         ntStatus = STATUS_SUCCESS;
395
396                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
397                     }
398                     else
399                     {
400
401                         ntStatus = STATUS_SUCCESS;
402
403                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
404                                       AFS_TRACE_LEVEL_VERBOSE,
405                                       "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
406                                       &pCcb->FullFileName,
407                                       pCcb->DirectoryCB);
408
409                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
410
411                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
412
413                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
414                                                         pCcb,
415                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
416                                                         (ULONG)FILE_ACTION_REMOVED);
417
418                         //
419                         // Now that the service has the entry has deleted we need to remove it from the parent
420                         // tree so another lookup on the node will fail
421                         //
422
423                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
424                         {
425
426                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
427                                             TRUE);
428
429                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
430                                           AFS_TRACE_LEVEL_VERBOSE,
431                                           "AFSCleanup DE %p for %wZ removing entry\n",
432                                           pCcb->DirectoryCB,
433                                           &pCcb->DirectoryCB->NameInformation.FileName);
434
435                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
436                                                 pCcb->DirectoryCB);
437
438                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
439                         }
440                         else
441                         {
442
443                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
444                                           AFS_TRACE_LEVEL_VERBOSE,
445                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
446                                           pCcb->DirectoryCB,
447                                           &pCcb->DirectoryCB->NameInformation.FileName);
448                         }
449                     }
450                 }
451                 else
452                 {
453
454                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
455                     {
456
457                         ULONG ulNotifyFilter = 0;
458
459                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
460
461                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
462
463                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
464                                                         pCcb,
465                                                         (ULONG)ulNotifyFilter,
466                                                         (ULONG)FILE_ACTION_MODIFIED);
467                     }
468
469                     //
470                     // Flush out any dirty pages on every handle close to reduce strain on the afs cache
471                     //
472
473                     if( CcIsFileCached( pIrpSp->FileObject))
474                     {
475
476                         __try
477                         {
478
479                             CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
480                                           NULL,
481                                           0,
482                                           &stIoSB);
483
484                             if( !NT_SUCCESS( stIoSB.Status))
485                             {
486
487                                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
488                                               AFS_TRACE_LEVEL_ERROR,
489                                               "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
490                                               &pCcb->FullFileName,
491                                               pObjectInfo->FileId.Cell,
492                                               pObjectInfo->FileId.Volume,
493                                               pObjectInfo->FileId.Vnode,
494                                               pObjectInfo->FileId.Unique,
495                                               stIoSB.Status,
496                                               stIoSB.Information);
497
498                                 ntStatus = stIoSB.Status;
499                             }
500                         }
501                         __except( EXCEPTION_EXECUTE_HANDLER)
502                         {
503
504                             ntStatus = GetExceptionCode();
505                         }
506                     }
507
508                     //
509                     // Attempt to flush any dirty extents to the server. This may be a little
510                     // aggressive, to flush whenever the handle is closed, but it ensures
511                     // coherency.
512                     //
513
514                     if( pFcb->Specific.File.ExtentsDirtyCount)
515                     {
516
517                         AFSFlushExtents( pFcb,
518                                          &pCcb->AuthGroup);
519                     }
520
521                     if( pFcb->OpenHandleCount == 0)
522                     {
523
524                         //
525                         // Wait for any outstanding queued flushes to complete
526                         //
527
528                         AFSWaitOnQueuedFlushes( pFcb);
529
530                         ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
531                     }
532
533                     //
534                     // Indicate the file access mode that is being released
535                     //
536
537                     stFileCleanup.FileAccess = pCcb->FileAccess;
538
539                     //
540                     // Push the request to the service
541                     //
542
543                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
544                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
545                                        &pCcb->AuthGroup,
546                                        &pCcb->DirectoryCB->NameInformation.FileName,
547                                        &pObjectInfo->FileId,
548                                        &stFileCleanup,
549                                        sizeof( AFSFileCleanupCB),
550                                        NULL,
551                                        NULL);
552                 }
553
554                 //
555                 // Remove the share access at this time since we may not get the close for sometime on this FO.
556                 //
557
558                 IoRemoveShareAccess( pFileObject,
559                                      &pFcb->ShareAccess);
560
561                 //
562                 // We don't need the name array after the user closes the handle on the file
563                 //
564
565                 if( pCcb->NameArray != NULL)
566                 {
567
568                     AFSFreeNameArray( pCcb->NameArray);
569
570                     pCcb->NameArray = NULL;
571                 }
572
573                 //
574                 // Decrement the open child handle count
575                 //
576
577                 if( pObjectInfo->ParentObjectInformation != NULL)
578                 {
579
580                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
581
582                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
583
584                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
585                                   AFS_TRACE_LEVEL_VERBOSE,
586                                   "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
587                                   pObjectInfo->ParentObjectInformation,
588                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
589                 }
590
591                 //
592                 // And finally, release the Fcb if we acquired it.
593                 //
594
595                 AFSReleaseResource( &pFcb->NPFcb->Resource);
596
597                 break;
598             }
599
600             //
601             // Root or directory node
602             //
603
604             case AFS_ROOT_FCB:
605             {
606
607                 //
608                 // Set the root Fcb to this node
609                 //
610
611                 pRootFcb = pFcb;
612
613                 //
614                 // Fall through to below
615                 //
616             }
617
618             case AFS_DIRECTORY_FCB:
619             {
620
621                 //
622                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
623                 //
624
625                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
626                               AFS_TRACE_LEVEL_VERBOSE,
627                               "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
628                               &pFcb->NPFcb->Resource,
629                               PsGetCurrentThread());
630
631                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
632                                   TRUE);
633
634                 //
635                 // Perform some final common processing
636                 //
637
638                 ASSERT( pFcb->OpenHandleCount != 0);
639
640                 InterlockedDecrement( &pFcb->OpenHandleCount);
641
642                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
643                               AFS_TRACE_LEVEL_VERBOSE,
644                               "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
645                               pFcb,
646                               pFcb->OpenHandleCount);
647
648                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
649                 {
650
651                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
652                 }
653
654                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
655
656                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
657                 {
658
659                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
660
661                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
662                     {
663
664                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
665
666                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
667                     }
668
669                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
670                     {
671
672                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
673
674                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
675                     }
676
677                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
678                     {
679
680                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
681
682                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
683                     }
684                 }
685
686                 //
687                 // If the count has dropped to zero and there is a pending delete
688                 // then delete the node
689                 //
690
691                 if( pFcb->OpenHandleCount == 0 &&
692                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
693                 {
694
695                     //
696                     // Try to notify the service about the delete
697                     //
698
699                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
700
701                     //
702                     // Indicate the file access mode that is being released
703                     //
704
705                     stFileCleanup.FileAccess = pCcb->FileAccess;
706
707                     //
708                     // Push the request to the service
709                     //
710
711                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
712                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
713                                                   &pCcb->AuthGroup,
714                                                   &pCcb->DirectoryCB->NameInformation.FileName,
715                                                   &pObjectInfo->FileId,
716                                                   &stFileCleanup,
717                                                   sizeof( AFSFileCleanupCB),
718                                                   NULL,
719                                                   NULL);
720
721                     if( !NT_SUCCESS( ntStatus) &&
722                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
723                     {
724
725                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
726                                       AFS_TRACE_LEVEL_ERROR,
727                                       "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
728                                       &pCcb->FullFileName,
729                                       ntStatus);
730
731                         ntStatus = STATUS_SUCCESS;
732
733                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
734                     }
735                     else
736                     {
737
738                         ntStatus = STATUS_SUCCESS;
739
740                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
741                                       AFS_TRACE_LEVEL_VERBOSE,
742                                       "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
743                                       &pCcb->FullFileName,
744                                       pCcb->DirectoryCB);
745
746                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
747
748                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
749
750                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
751                                                         pCcb,
752                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
753                                                         (ULONG)FILE_ACTION_REMOVED);
754
755                         //
756                         // Now that the service has the entry has deleted we need to remove it from the parent
757                         // tree so another lookup on the node will fail
758                         //
759
760                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
761                         {
762
763                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
764                                             TRUE);
765
766                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
767                                                 pCcb->DirectoryCB);
768
769                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
770                         }
771                         else
772                         {
773
774                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
775                                           AFS_TRACE_LEVEL_VERBOSE,
776                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
777                                           pCcb->DirectoryCB,
778                                           &pCcb->DirectoryCB->NameInformation.FileName);
779                         }
780                     }
781                 }
782
783                 //
784                 // If there have been any updates to the node then push it to
785                 // the service
786                 //
787
788                 else
789                 {
790
791                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
792                     {
793
794                         ULONG ulNotifyFilter = 0;
795
796                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
797
798                         if(  pObjectInfo->ParentObjectInformation != NULL)
799                         {
800
801                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
802
803                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
804                                                             pCcb,
805                                                             (ULONG)ulNotifyFilter,
806                                                             (ULONG)FILE_ACTION_MODIFIED);
807                         }
808                     }
809
810                     //
811                     // Indicate the file access mode that is being released
812                     //
813
814                     stFileCleanup.FileAccess = pCcb->FileAccess;
815
816                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
817                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
818                                        &pCcb->AuthGroup,
819                                        &pCcb->DirectoryCB->NameInformation.FileName,
820                                        &pObjectInfo->FileId,
821                                        &stFileCleanup,
822                                        sizeof( AFSFileCleanupCB),
823                                        NULL,
824                                        NULL);
825                 }
826
827                 //
828                 // Release the notification for this directory if there is one
829                 //
830
831                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
832                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
833                                     pCcb);
834
835                 //
836                 // Remove the share access at this time since we may not get the close for sometime on this FO.
837                 //
838
839                 IoRemoveShareAccess( pFileObject,
840                                      &pFcb->ShareAccess);
841
842                 //
843                 // We don't need the name array after the user closes the handle on the file
844                 //
845
846                 if( pCcb->NameArray != NULL)
847                 {
848
849                     AFSFreeNameArray( pCcb->NameArray);
850
851                     pCcb->NameArray = NULL;
852                 }
853
854                 //
855                 // Decrement the open child handle count
856                 //
857
858                 if( pObjectInfo->ParentObjectInformation != NULL)
859                 {
860
861                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
862
863                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
864
865                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
866                                   AFS_TRACE_LEVEL_VERBOSE,
867                                   "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
868                                   pObjectInfo->ParentObjectInformation,
869                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
870                 }
871
872                 //
873                 // And finally, release the Fcb if we acquired it.
874                 //
875
876                 AFSReleaseResource( &pFcb->NPFcb->Resource);
877
878                 break;
879             }
880
881             case AFS_SYMBOLIC_LINK_FCB:
882             case AFS_MOUNT_POINT_FCB:
883             case AFS_DFS_LINK_FCB:
884             {
885
886                 //
887                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
888                 //
889
890                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
891                               AFS_TRACE_LEVEL_VERBOSE,
892                               "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
893                               &pFcb->NPFcb->Resource,
894                               PsGetCurrentThread());
895
896                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
897                                   TRUE);
898
899                 //
900                 // Perform some final common processing
901                 //
902
903                 ASSERT( pFcb->OpenHandleCount != 0);
904
905                 InterlockedDecrement( &pFcb->OpenHandleCount);
906
907                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
908                               AFS_TRACE_LEVEL_VERBOSE,
909                               "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
910                               pFcb,
911                               pFcb->OpenHandleCount);
912
913                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
914                 {
915
916                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
917                 }
918
919                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
920
921                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
922                 {
923
924                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
925
926                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
927                     {
928
929                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
930
931                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
932                     }
933
934                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
935                     {
936
937                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
938
939                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
940                     }
941
942                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
943                     {
944
945                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
946
947                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
948                     }
949                 }
950
951                 //
952                 // If the count has dropped to zero and there is a pending delete
953                 // then delete the node
954                 //
955
956                 if( pFcb->OpenHandleCount == 0 &&
957                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
958                 {
959
960                     //
961                     // Try to notify the service about the delete
962                     //
963
964                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
965
966                     //
967                     // Indicate the file access mode that is being released
968                     //
969
970                     stFileCleanup.FileAccess = pCcb->FileAccess;
971
972                     //
973                     // Push the request to the service
974                     //
975
976                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
977                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
978                                                   &pCcb->AuthGroup,
979                                                   &pCcb->DirectoryCB->NameInformation.FileName,
980                                                   &pObjectInfo->FileId,
981                                                   &stFileCleanup,
982                                                   sizeof( AFSFileCleanupCB),
983                                                   NULL,
984                                                   NULL);
985
986                     if( !NT_SUCCESS( ntStatus) &&
987                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
988                     {
989
990                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
991                                       AFS_TRACE_LEVEL_ERROR,
992                                       "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
993                                       &pCcb->FullFileName,
994                                       ntStatus);
995
996                         ntStatus = STATUS_SUCCESS;
997
998                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
999                     }
1000                     else
1001                     {
1002
1003                         ntStatus = STATUS_SUCCESS;
1004
1005                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1006                                       AFS_TRACE_LEVEL_VERBOSE,
1007                                       "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1008                                       &pCcb->FullFileName,
1009                                       pCcb->DirectoryCB);
1010
1011                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1012
1013                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
1014
1015                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1016                                                         pCcb,
1017                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1018                                                         (ULONG)FILE_ACTION_REMOVED);
1019
1020                         //
1021                         // Now that the service has the entry has deleted we need to remove it from the parent
1022                         // tree so another lookup on the node will fail
1023                         //
1024
1025                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1026                         {
1027
1028                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
1029                                             TRUE);
1030
1031                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
1032                                                 pCcb->DirectoryCB);
1033
1034                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1035                         }
1036                         else
1037                         {
1038
1039                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1040                                           AFS_TRACE_LEVEL_VERBOSE,
1041                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1042                                           pCcb->DirectoryCB,
1043                                           &pCcb->DirectoryCB->NameInformation.FileName);
1044                         }
1045                     }
1046                 }
1047
1048                 //
1049                 // If there have been any updates to the node then push it to
1050                 // the service
1051                 //
1052
1053                 else
1054                 {
1055
1056                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1057                     {
1058
1059                         ULONG ulNotifyFilter = 0;
1060
1061                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1062
1063                         if(  pObjectInfo->ParentObjectInformation != NULL)
1064                         {
1065
1066                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1067
1068                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1069                                                             pCcb,
1070                                                             (ULONG)ulNotifyFilter,
1071                                                             (ULONG)FILE_ACTION_MODIFIED);
1072                         }
1073                     }
1074
1075                     //
1076                     // Indicate the file access mode that is being released
1077                     //
1078
1079                     stFileCleanup.FileAccess = pCcb->FileAccess;
1080
1081                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1082                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1083                                        &pCcb->AuthGroup,
1084                                        &pCcb->DirectoryCB->NameInformation.FileName,
1085                                        &pObjectInfo->FileId,
1086                                        &stFileCleanup,
1087                                        sizeof( AFSFileCleanupCB),
1088                                        NULL,
1089                                        NULL);
1090                 }
1091
1092                 //
1093                 // Remove the share access at this time since we may not get the close for sometime on this FO.
1094                 //
1095
1096                 IoRemoveShareAccess( pFileObject,
1097                                      &pFcb->ShareAccess);
1098
1099                 //
1100                 // We don't need the name array after the user closes the handle on the file
1101                 //
1102
1103                 if( pCcb->NameArray != NULL)
1104                 {
1105
1106                     AFSFreeNameArray( pCcb->NameArray);
1107
1108                     pCcb->NameArray = NULL;
1109                 }
1110
1111                 //
1112                 // Decrement the open child handle count
1113                 //
1114
1115                 if( pObjectInfo->ParentObjectInformation != NULL)
1116                 {
1117
1118                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
1119
1120                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1121
1122                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1123                                   AFS_TRACE_LEVEL_VERBOSE,
1124                                   "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1125                                   pObjectInfo->ParentObjectInformation,
1126                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1127                 }
1128
1129                 //
1130                 // And finally, release the Fcb if we acquired it.
1131                 //
1132
1133                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1134
1135                 break;
1136             }
1137
1138             case AFS_SPECIAL_SHARE_FCB:
1139             {
1140
1141                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1142                               AFS_TRACE_LEVEL_VERBOSE,
1143                               "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1144                               &pFcb->NPFcb->Resource,
1145                               PsGetCurrentThread());
1146
1147                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1148                                 TRUE);
1149
1150                 ASSERT( pFcb->OpenHandleCount != 0);
1151
1152                 InterlockedDecrement( &pFcb->OpenHandleCount);
1153
1154                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1155                               AFS_TRACE_LEVEL_VERBOSE,
1156                               "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1157                               pFcb,
1158                               pFcb->OpenHandleCount);
1159
1160                 //
1161                 // Decrement the open child handle count
1162                 //
1163
1164                 if( pObjectInfo->ParentObjectInformation != NULL &&
1165                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
1166                 {
1167
1168                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1169
1170                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1171                                   AFS_TRACE_LEVEL_VERBOSE,
1172                                   "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1173                                   pObjectInfo->ParentObjectInformation,
1174                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1175                 }
1176
1177                 //
1178                 // And finally, release the Fcb if we acquired it.
1179                 //
1180
1181                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1182
1183                 break;
1184             }
1185
1186             default:
1187
1188                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1189                               AFS_TRACE_LEVEL_WARNING,
1190                               "AFSCleanup Processing unknown node type %d\n",
1191                               pFcb->Header.NodeTypeCode);
1192
1193                 break;
1194         }
1195
1196
1197 try_exit:
1198
1199         if( pFileObject != NULL)
1200         {
1201
1202             //
1203             // Setup the fileobject flags to indicate cleanup is complete.
1204             //
1205
1206             SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1207         }
1208
1209         //
1210         // Complete the request
1211         //
1212
1213         AFSCompleteRequest( Irp, ntStatus);
1214     }
1215     __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
1216     {
1217
1218         AFSDbgLogMsg( 0,
1219                       0,
1220                       "EXCEPTION - AFSCleanup\n");
1221     }
1222
1223     return ntStatus;
1224 }