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