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