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