c56faf4db68c79d3634f9e2a7f2b185103489117
[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                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
421                                           AFS_TRACE_LEVEL_VERBOSE,
422                                           "AFSCleanup DE %p for %wZ removing entry\n",
423                                           pCcb->DirectoryCB,
424                                           &pCcb->DirectoryCB->NameInformation.FileName);
425
426                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
427                                                 pCcb->DirectoryCB);
428
429                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
430                         }
431                         else
432                         {
433
434                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
435                                           AFS_TRACE_LEVEL_VERBOSE,
436                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
437                                           pCcb->DirectoryCB,
438                                           &pCcb->DirectoryCB->NameInformation.FileName);
439                         }
440                     }
441                 }
442                 else
443                 {
444
445                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
446                     {
447
448                         ULONG ulNotifyFilter = 0;
449
450                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
451
452                         ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
453
454                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
455                                                         pCcb,
456                                                         (ULONG)ulNotifyFilter,
457                                                         (ULONG)FILE_ACTION_MODIFIED);
458                     }
459
460                     //
461                     // Flush out any dirty pages on every handle close to reduce strain on the afs cache
462                     //
463
464                     if( CcIsFileCached( pIrpSp->FileObject))
465                     {
466
467                         __try
468                         {
469
470                             CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
471                                           NULL,
472                                           0,
473                                           &stIoSB);
474
475                             if( !NT_SUCCESS( stIoSB.Status))
476                             {
477
478                                 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
479                                               AFS_TRACE_LEVEL_ERROR,
480                                               "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
481                                               &pCcb->FullFileName,
482                                               pObjectInfo->FileId.Cell,
483                                               pObjectInfo->FileId.Volume,
484                                               pObjectInfo->FileId.Vnode,
485                                               pObjectInfo->FileId.Unique,
486                                               stIoSB.Status,
487                                               stIoSB.Information);
488
489                                 ntStatus = stIoSB.Status;
490                             }
491                         }
492                         __except( EXCEPTION_EXECUTE_HANDLER)
493                         {
494
495                             ntStatus = GetExceptionCode();
496                         }
497                     }
498
499                     //
500                     // Attempt to flush any dirty extents to the server. This may be a little
501                     // aggressive, to flush whenever the handle is closed, but it ensures
502                     // coherency.
503                     //
504
505                     if( pFcb->Specific.File.ExtentsDirtyCount)
506                     {
507
508                         AFSFlushExtents( pFcb);
509                     }
510
511                     if( pFcb->OpenHandleCount == 0)
512                     {
513
514                         //
515                         // Wait for any outstanding queued flushes to complete
516                         //
517
518                         AFSWaitOnQueuedFlushes( pFcb);
519
520                         ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
521                     }
522
523                     //
524                     // Push the request to the service
525                     //
526
527                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
528                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
529                                        &pFcb->AuthGroup,
530                                        &pCcb->DirectoryCB->NameInformation.FileName,
531                                        &pObjectInfo->FileId,
532                                        &stFileCleanup,
533                                        sizeof( AFSFileCleanupCB),
534                                        NULL,
535                                        NULL);
536                 }
537
538                 //
539                 // Remove the share access at this time since we may not get the close for sometime on this FO.
540                 //
541
542                 IoRemoveShareAccess( pFileObject,
543                                      &pFcb->ShareAccess);
544
545                 //
546                 // We don't need the name array after the user closes the handle on the file
547                 //
548
549                 if( pCcb->NameArray != NULL)
550                 {
551
552                     AFSFreeNameArray( pCcb->NameArray);
553
554                     pCcb->NameArray = NULL;
555                 }
556
557                 //
558                 // Decrement the open child handle count
559                 //
560
561                 if( pObjectInfo->ParentObjectInformation != NULL)
562                 {
563
564                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
565
566                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
567
568                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
569                                   AFS_TRACE_LEVEL_VERBOSE,
570                                   "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
571                                   pObjectInfo->ParentObjectInformation,
572                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
573                 }
574
575                 //
576                 // And finally, release the Fcb if we acquired it.
577                 //
578
579                 AFSReleaseResource( &pFcb->NPFcb->Resource);
580
581                 break;
582             }
583
584             //
585             // Root or directory node
586             //
587
588             case AFS_ROOT_FCB:
589             {
590
591                 //
592                 // Set the root Fcb to this node
593                 //
594
595                 pRootFcb = pFcb;
596
597                 //
598                 // Fall through to below
599                 //
600             }
601
602             case AFS_DIRECTORY_FCB:
603             {
604
605                 //
606                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
607                 //
608
609                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
610                               AFS_TRACE_LEVEL_VERBOSE,
611                               "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
612                               &pFcb->NPFcb->Resource,
613                               PsGetCurrentThread());
614
615                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
616                                   TRUE);
617
618                 //
619                 // Perform some final common processing
620                 //
621
622                 ASSERT( pFcb->OpenHandleCount != 0);
623
624                 InterlockedDecrement( &pFcb->OpenHandleCount);
625
626                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
627                               AFS_TRACE_LEVEL_VERBOSE,
628                               "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
629                               pFcb,
630                               pFcb->OpenHandleCount);
631
632                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
633                 {
634
635                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
636                 }
637
638                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
639
640                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
641                 {
642
643                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
644
645                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
646                     {
647
648                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
649
650                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
651                     }
652
653                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
654                     {
655
656                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
657
658                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
659                     }
660
661                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
662                     {
663
664                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
665
666                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
667                     }
668                 }
669
670                 //
671                 // If the count has dropped to zero and there is a pending delete
672                 // then delete the node
673                 //
674
675                 if( pFcb->OpenHandleCount == 0 &&
676                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
677                 {
678
679                     //
680                     // Try to notify the service about the delete
681                     //
682
683                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
684
685                     //
686                     // Push the request to the service
687                     //
688
689                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
690                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
691                                                   &pFcb->AuthGroup,
692                                                   &pCcb->DirectoryCB->NameInformation.FileName,
693                                                   &pObjectInfo->FileId,
694                                                   &stFileCleanup,
695                                                   sizeof( AFSFileCleanupCB),
696                                                   NULL,
697                                                   NULL);
698
699                     if( !NT_SUCCESS( ntStatus) &&
700                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
701                     {
702
703                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
704                                       AFS_TRACE_LEVEL_ERROR,
705                                       "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
706                                       &pCcb->FullFileName,
707                                       ntStatus);
708
709                         ntStatus = STATUS_SUCCESS;
710
711                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
712                     }
713                     else
714                     {
715
716                         ntStatus = STATUS_SUCCESS;
717
718                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
719                                       AFS_TRACE_LEVEL_VERBOSE,
720                                       "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
721                                       &pCcb->FullFileName,
722                                       pCcb->DirectoryCB);
723
724                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
725
726                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
727
728                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
729                                                         pCcb,
730                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
731                                                         (ULONG)FILE_ACTION_REMOVED);
732
733                         //
734                         // Now that the service has the entry has deleted we need to remove it from the parent
735                         // tree so another lookup on the node will fail
736                         //
737
738                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
739                         {
740
741                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
742                                             TRUE);
743
744                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
745                                                 pCcb->DirectoryCB);
746
747                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
748                         }
749                         else
750                         {
751
752                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
753                                           AFS_TRACE_LEVEL_VERBOSE,
754                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
755                                           pCcb->DirectoryCB,
756                                           &pCcb->DirectoryCB->NameInformation.FileName);
757                         }
758                     }
759                 }
760
761                 //
762                 // If there have been any updates to the node then push it to
763                 // the service
764                 //
765
766                 else
767                 {
768
769                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
770                     {
771
772                         ULONG ulNotifyFilter = 0;
773
774                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
775
776                         if(  pObjectInfo->ParentObjectInformation != NULL)
777                         {
778
779                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
780
781                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
782                                                             pCcb,
783                                                             (ULONG)ulNotifyFilter,
784                                                             (ULONG)FILE_ACTION_MODIFIED);
785                         }
786                     }
787
788                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
789                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
790                                        &pFcb->AuthGroup,
791                                        &pCcb->DirectoryCB->NameInformation.FileName,
792                                        &pObjectInfo->FileId,
793                                        &stFileCleanup,
794                                        sizeof( AFSFileCleanupCB),
795                                        NULL,
796                                        NULL);
797                 }
798
799                 //
800                 // Release the notification for this directory if there is one
801                 //
802
803                 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
804                                     &pControlDeviceExt->Specific.Control.DirNotifyList,
805                                     pCcb);
806
807                 //
808                 // Remove the share access at this time since we may not get the close for sometime on this FO.
809                 //
810
811                 IoRemoveShareAccess( pFileObject,
812                                      &pFcb->ShareAccess);
813
814                 //
815                 // We don't need the name array after the user closes the handle on the file
816                 //
817
818                 if( pCcb->NameArray != NULL)
819                 {
820
821                     AFSFreeNameArray( pCcb->NameArray);
822
823                     pCcb->NameArray = NULL;
824                 }
825
826                 //
827                 // Decrement the open child handle count
828                 //
829
830                 if( pObjectInfo->ParentObjectInformation != NULL)
831                 {
832
833                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
834
835                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
836
837                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
838                                   AFS_TRACE_LEVEL_VERBOSE,
839                                   "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
840                                   pObjectInfo->ParentObjectInformation,
841                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
842                 }
843
844                 //
845                 // And finally, release the Fcb if we acquired it.
846                 //
847
848                 AFSReleaseResource( &pFcb->NPFcb->Resource);
849
850                 break;
851             }
852
853             case AFS_SYMBOLIC_LINK_FCB:
854             case AFS_MOUNT_POINT_FCB:
855             case AFS_DFS_LINK_FCB:
856             {
857
858                 //
859                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
860                 //
861
862                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
863                               AFS_TRACE_LEVEL_VERBOSE,
864                               "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
865                               &pFcb->NPFcb->Resource,
866                               PsGetCurrentThread());
867
868                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
869                                   TRUE);
870
871                 //
872                 // Perform some final common processing
873                 //
874
875                 ASSERT( pFcb->OpenHandleCount != 0);
876
877                 InterlockedDecrement( &pFcb->OpenHandleCount);
878
879                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
880                               AFS_TRACE_LEVEL_VERBOSE,
881                               "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
882                               pFcb,
883                               pFcb->OpenHandleCount);
884
885                 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
886                 {
887
888                     stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
889                 }
890
891                 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
892
893                 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
894                 {
895
896                     stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
897
898                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
899                     {
900
901                         stFileCleanup.CreateTime = pObjectInfo->CreationTime;
902
903                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
904                     }
905
906                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
907                     {
908
909                         stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
910
911                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
912                     }
913
914                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
915                     {
916
917                         stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
918
919                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
920                     }
921                 }
922
923                 //
924                 // If the count has dropped to zero and there is a pending delete
925                 // then delete the node
926                 //
927
928                 if( pFcb->OpenHandleCount == 0 &&
929                     BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
930                 {
931
932                     //
933                     // Try to notify the service about the delete
934                     //
935
936                     ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
937
938                     //
939                     // Push the request to the service
940                     //
941
942                     ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
943                                                   ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
944                                                   &pFcb->AuthGroup,
945                                                   &pCcb->DirectoryCB->NameInformation.FileName,
946                                                   &pObjectInfo->FileId,
947                                                   &stFileCleanup,
948                                                   sizeof( AFSFileCleanupCB),
949                                                   NULL,
950                                                   NULL);
951
952                     if( !NT_SUCCESS( ntStatus) &&
953                         ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
954                     {
955
956                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
957                                       AFS_TRACE_LEVEL_ERROR,
958                                       "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
959                                       &pCcb->FullFileName,
960                                       ntStatus);
961
962                         ntStatus = STATUS_SUCCESS;
963
964                         ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
965                     }
966                     else
967                     {
968
969                         ntStatus = STATUS_SUCCESS;
970
971                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
972                                       AFS_TRACE_LEVEL_VERBOSE,
973                                       "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
974                                       &pCcb->FullFileName,
975                                       pCcb->DirectoryCB);
976
977                         SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
978
979                         ASSERT( pObjectInfo->ParentObjectInformation != NULL);
980
981                         AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
982                                                         pCcb,
983                                                         (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
984                                                         (ULONG)FILE_ACTION_REMOVED);
985
986                         //
987                         // Now that the service has the entry has deleted we need to remove it from the parent
988                         // tree so another lookup on the node will fail
989                         //
990
991                         if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
992                         {
993
994                             AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
995                                             TRUE);
996
997                             AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
998                                                 pCcb->DirectoryCB);
999
1000                             AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1001                         }
1002                         else
1003                         {
1004
1005                             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1006                                           AFS_TRACE_LEVEL_VERBOSE,
1007                                           "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1008                                           pCcb->DirectoryCB,
1009                                           &pCcb->DirectoryCB->NameInformation.FileName);
1010                         }
1011                     }
1012                 }
1013
1014                 //
1015                 // If there have been any updates to the node then push it to
1016                 // the service
1017                 //
1018
1019                 else
1020                 {
1021
1022                     if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1023                     {
1024
1025                         ULONG ulNotifyFilter = 0;
1026
1027                         ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1028
1029                         if(  pObjectInfo->ParentObjectInformation != NULL)
1030                         {
1031
1032                             ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1033
1034                             AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1035                                                             pCcb,
1036                                                             (ULONG)ulNotifyFilter,
1037                                                             (ULONG)FILE_ACTION_MODIFIED);
1038                         }
1039                     }
1040
1041                     AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1042                                        ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1043                                        &pFcb->AuthGroup,
1044                                        &pCcb->DirectoryCB->NameInformation.FileName,
1045                                        &pObjectInfo->FileId,
1046                                        &stFileCleanup,
1047                                        sizeof( AFSFileCleanupCB),
1048                                        NULL,
1049                                        NULL);
1050                 }
1051
1052                 //
1053                 // Remove the share access at this time since we may not get the close for sometime on this FO.
1054                 //
1055
1056                 IoRemoveShareAccess( pFileObject,
1057                                      &pFcb->ShareAccess);
1058
1059                 //
1060                 // We don't need the name array after the user closes the handle on the file
1061                 //
1062
1063                 if( pCcb->NameArray != NULL)
1064                 {
1065
1066                     AFSFreeNameArray( pCcb->NameArray);
1067
1068                     pCcb->NameArray = NULL;
1069                 }
1070
1071                 //
1072                 // Decrement the open child handle count
1073                 //
1074
1075                 if( pObjectInfo->ParentObjectInformation != NULL)
1076                 {
1077
1078                     ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
1079
1080                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1081
1082                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1083                                   AFS_TRACE_LEVEL_VERBOSE,
1084                                   "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1085                                   pObjectInfo->ParentObjectInformation,
1086                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1087                 }
1088
1089                 //
1090                 // And finally, release the Fcb if we acquired it.
1091                 //
1092
1093                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1094
1095                 break;
1096             }
1097
1098             case AFS_SPECIAL_SHARE_FCB:
1099             {
1100
1101                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1102                               AFS_TRACE_LEVEL_VERBOSE,
1103                               "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1104                               &pFcb->NPFcb->Resource,
1105                               PsGetCurrentThread());
1106
1107                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1108                                 TRUE);
1109
1110                 ASSERT( pFcb->OpenHandleCount != 0);
1111
1112                 InterlockedDecrement( &pFcb->OpenHandleCount);
1113
1114                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1115                               AFS_TRACE_LEVEL_VERBOSE,
1116                               "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1117                               pFcb,
1118                               pFcb->OpenHandleCount);
1119
1120                 //
1121                 // Decrement the open child handle count
1122                 //
1123
1124                 if( pObjectInfo->ParentObjectInformation != NULL &&
1125                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
1126                 {
1127
1128                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1129
1130                     AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1131                                   AFS_TRACE_LEVEL_VERBOSE,
1132                                   "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1133                                   pObjectInfo->ParentObjectInformation,
1134                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1135                 }
1136
1137                 //
1138                 // And finally, release the Fcb if we acquired it.
1139                 //
1140
1141                 AFSReleaseResource( &pFcb->NPFcb->Resource);
1142
1143                 break;
1144             }
1145
1146             default:
1147
1148                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1149                               AFS_TRACE_LEVEL_WARNING,
1150                               "AFSCleanup Processing unknown node type %d\n",
1151                               pFcb->Header.NodeTypeCode);
1152
1153                 break;
1154         }
1155
1156
1157 try_exit:
1158
1159         if( pFileObject != NULL)
1160         {
1161
1162             //
1163             // Setup the fileobject flags to indicate cleanup is complete.
1164             //
1165
1166             SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1167         }
1168
1169         //
1170         // Complete the request
1171         //
1172
1173         AFSCompleteRequest( Irp, ntStatus);
1174     }
1175     __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
1176     {
1177
1178         AFSDbgLogMsg( 0,
1179                       0,
1180                       "EXCEPTION - AFSCleanup\n");
1181     }
1182
1183     return ntStatus;
1184 }