2 * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
14 * this list of conditions and the following disclaimer in the
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.
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.
36 // File: AFSCleanup.cpp
39 #include "AFSCommon.h"
42 // Function: AFSCleanup
46 // This function is the IRP_MJ_CLEANUP dispatch handler
50 // A status is returned for the handling of this request
54 AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
58 NTSTATUS ntStatus = STATUS_SUCCESS;
59 AFSDeviceExt *pDeviceExt = NULL;
60 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
63 PFILE_OBJECT pFileObject = NULL;
64 AFSFcb *pRootFcb = NULL;
65 AFSDeviceExt *pControlDeviceExt = NULL;
66 IO_STATUS_BLOCK stIoSB;
67 AFSObjectInfoCB *pObjectInfo = NULL;
68 AFSObjectInfoCB *pParentObjectInfo = NULL;
69 AFSFileCleanupCB stFileCleanup;
70 AFSFileCleanupResultCB *pResultCB = NULL;
71 ULONG ulResultLen = 0;
72 ULONG ulNotificationFlags = 0;
78 if( AFSRDRDeviceObject == NULL)
82 // Let this through, it's a cleanup on the library control device
85 try_return( ntStatus);
88 pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
90 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
93 // Set some initial variables to make processing easier
96 pFileObject = pIrpSp->FileObject;
98 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
100 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
104 try_return( ntStatus);
107 pObjectInfo = pFcb->ObjectInformation;
109 pRootFcb = pObjectInfo->VolumeCB->RootFcb;
111 RtlZeroMemory( &stFileCleanup,
112 sizeof( AFSFileCleanupCB));
114 stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
116 stFileCleanup.Identifier = (ULONGLONG)pFileObject;
119 // Allocate our return buffer
122 pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
124 AFS_GENERIC_MEMORY_32_TAG);
126 if( pResultCB == NULL)
129 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
132 RtlZeroMemory( pResultCB,
135 ulResultLen = PAGE_SIZE;
139 // Perform the cleanup functionality depending on the type of node it is
142 switch( pFcb->Header.NodeTypeCode)
148 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
149 AFS_TRACE_LEVEL_VERBOSE,
150 "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
151 &pFcb->NPFcb->Resource,
152 PsGetCurrentThread());
154 AFSAcquireExcl( &pFcb->NPFcb->Resource,
157 ASSERT( pFcb->OpenHandleCount != 0);
159 AFSReleaseResource( &pFcb->NPFcb->Resource);
161 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
163 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
164 AFS_TRACE_LEVEL_VERBOSE,
165 "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n",
169 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
170 &pControlDeviceExt->Specific.Control.DirNotifyList,
179 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
180 AFS_TRACE_LEVEL_VERBOSE,
181 "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n",
182 &pFcb->NPFcb->Resource,
183 PsGetCurrentThread());
185 AFSAcquireExcl( &pFcb->NPFcb->Resource,
188 ASSERT( pFcb->OpenHandleCount != 0);
191 // Decrement the open child handle count
194 if( pObjectInfo->ParentObjectInformation != NULL &&
195 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
198 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
200 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
201 AFS_TRACE_LEVEL_VERBOSE,
202 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n",
203 pObjectInfo->ParentObjectInformation,
207 AFSReleaseResource( &pFcb->NPFcb->Resource);
209 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
211 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
212 AFS_TRACE_LEVEL_VERBOSE,
213 "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n",
221 // This Fcb represents a file
228 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
231 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
232 AFS_TRACE_LEVEL_VERBOSE,
233 "AFSCleanup Acquiring Fcb SectionObject lock %08lX EXCL %08lX\n",
234 &pFcb->NPFcb->SectionObjectResource,
235 PsGetCurrentThread());
237 AFSAcquireExcl( &pFcb->NPFcb->SectionObjectResource,
241 // If the handle has write permission ...
244 if( ((pCcb->GrantedAccess & FILE_WRITE_DATA) || pFcb->OpenHandleCount == 1) &&
245 CcIsFileCached( pIrpSp->FileObject))
251 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
256 if( !NT_SUCCESS( stIoSB.Status))
259 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
260 AFS_TRACE_LEVEL_ERROR,
261 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
263 pObjectInfo->FileId.Cell,
264 pObjectInfo->FileId.Volume,
265 pObjectInfo->FileId.Vnode,
266 pObjectInfo->FileId.Unique,
270 ntStatus = stIoSB.Status;
273 if ( ( pFcb->OpenHandleCount == 1 ||
274 BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE)) &&
275 pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL)
278 if ( !CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers,
284 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
285 AFS_TRACE_LEVEL_WARNING,
286 "AFSCleanup CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
287 pObjectInfo->FileId.Cell,
288 pObjectInfo->FileId.Volume,
289 pObjectInfo->FileId.Vnode,
290 pObjectInfo->FileId.Unique);
292 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
296 ClearFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
300 __except( EXCEPTION_EXECUTE_HANDLER)
303 ntStatus = GetExceptionCode();
307 "EXCEPTION - AFSCleanup Cc FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
308 pObjectInfo->FileId.Cell,
309 pObjectInfo->FileId.Volume,
310 pObjectInfo->FileId.Vnode,
311 pObjectInfo->FileId.Unique,
314 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
319 // Uninitialize the cache map. This call is unconditional.
322 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
323 AFS_TRACE_LEVEL_VERBOSE,
324 "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n",
328 CcUninitializeCacheMap( pFileObject,
333 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
334 AFS_TRACE_LEVEL_VERBOSE,
335 "AFSCleanup Releasing Fcb SectionObject lock %08lX EXCL %08lX\n",
336 &pFcb->NPFcb->SectionObjectResource,
337 PsGetCurrentThread());
339 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
341 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
342 AFS_TRACE_LEVEL_VERBOSE,
343 "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n",
344 &pFcb->NPFcb->Resource,
345 PsGetCurrentThread());
347 AFSAcquireExcl( &pFcb->NPFcb->Resource,
351 // Unlock all outstanding locks on the file, again, unconditionally
354 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
356 IoGetRequestorProcess( Irp),
360 // Tell the service to unlock all on the file
363 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
366 // Perform some final common processing
369 ASSERT( pFcb->OpenHandleCount != 0);
371 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
374 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
377 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
379 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
382 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
384 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
386 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
389 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
391 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
394 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
397 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
399 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
402 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
405 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
407 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
410 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
413 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
415 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
419 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
422 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
426 // If the count has dropped to one and there is a pending delete
427 // then delete the node. The final count will be decremented just
428 // before the Fcb->NPFcb->Resource is released.
431 if( pFcb->OpenHandleCount == 1 &&
432 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
435 ntStatus = STATUS_SUCCESS;
437 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
440 // Indicate the file access mode that is being released
443 stFileCleanup.FileAccess = pCcb->FileAccess;
446 // Push the request to the service
449 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
450 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
452 &pCcb->DirectoryCB->NameInformation.FileName,
453 &pObjectInfo->FileId,
455 sizeof( AFSFileCleanupCB),
459 if( !NT_SUCCESS( ntStatus) &&
460 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
463 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
464 AFS_TRACE_LEVEL_ERROR,
465 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
469 ntStatus = STATUS_SUCCESS;
471 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
476 ntStatus = STATUS_SUCCESS;
478 if ( --pObjectInfo->Links < 1)
482 // Stop anything possibly in process
485 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
486 AFS_TRACE_LEVEL_VERBOSE,
487 "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n",
488 &pFcb->NPFcb->Specific.File.ExtentsResource,
489 PsGetCurrentThread());
491 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
494 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
496 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
501 // Before telling the server about the deleted file, tear down all extents for
505 AFSTearDownFcbExtents( pFcb,
508 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
509 AFS_TRACE_LEVEL_VERBOSE,
510 "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n",
511 &pFcb->NPFcb->Specific.File.ExtentsResource,
512 PsGetCurrentThread());
514 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
517 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
518 AFS_TRACE_LEVEL_VERBOSE,
519 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
523 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
525 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
527 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
529 ASSERT( pParentObjectInfo != NULL);
531 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
534 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
537 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
539 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
544 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
548 // Now that the service has the entry has deleted we need to remove it from the parent
549 // tree so another lookup on the node will fail
552 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
555 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
556 AFS_TRACE_LEVEL_VERBOSE,
557 "AFSCleanup DE %p for %wZ removing entry\n",
559 &pCcb->DirectoryCB->NameInformation.FileName);
561 AFSRemoveNameEntry( pParentObjectInfo,
567 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
568 AFS_TRACE_LEVEL_VERBOSE,
569 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
571 &pCcb->DirectoryCB->NameInformation.FileName);
574 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
576 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
578 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
579 (ULONG)FILE_ACTION_REMOVED);
586 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
589 ULONG ulNotifyFilter = 0;
591 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
593 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
595 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
597 (ULONG)ulNotifyFilter,
598 (ULONG)FILE_ACTION_MODIFIED);
602 // Attempt to flush any dirty extents to the server. This may be a little
603 // aggressive, to flush whenever the handle is closed, but it ensures
607 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) &&
608 pFcb->Specific.File.ExtentsDirtyCount != 0)
611 AFSFlushExtents( pFcb,
614 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
617 if( pFcb->OpenHandleCount == 1)
621 // Wait for any outstanding queued flushes to complete
624 AFSWaitOnQueuedFlushes( pFcb);
626 AFSTearDownFcbExtents( pFcb,
631 // Indicate the file access mode that is being released
634 stFileCleanup.FileAccess = pCcb->FileAccess;
637 // Remove the share access at this time since we may not get the close for sometime on this FO.
640 IoRemoveShareAccess( pFileObject,
645 // We don't need the name array after the user closes the handle on the file
648 if( pCcb->NameArray != NULL)
651 AFSFreeNameArray( pCcb->NameArray);
653 pCcb->NameArray = NULL;
657 // Release the Fcb Resource across the call to the service
658 // which may block for quite a while if flushing of the
662 AFSReleaseResource( &pFcb->NPFcb->Resource);
665 // Push the request to the service
668 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
669 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
671 &pCcb->DirectoryCB->NameInformation.FileName,
672 &pObjectInfo->FileId,
674 sizeof( AFSFileCleanupCB),
679 // Regain exclusive access to the Fcb
682 AFSAcquireExcl( &pFcb->NPFcb->Resource,
685 if ( NT_SUCCESS( ntStatus))
688 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
690 if ( pParentObjectInfo != NULL)
693 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
696 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
699 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
701 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
704 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
708 ntStatus = STATUS_SUCCESS;
712 // Decrement the open child handle count
715 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
717 if( pParentObjectInfo != NULL)
720 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
722 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
724 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
725 AFS_TRACE_LEVEL_VERBOSE,
726 "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
732 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
734 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
735 AFS_TRACE_LEVEL_VERBOSE,
736 "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n",
740 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
743 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
746 AFSObjectInfoIncrement( pObjectInfo);
748 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
750 AFSReleaseResource( &pFcb->NPFcb->Resource);
752 AFSPerformObjectInvalidate( pObjectInfo,
753 AFS_INVALIDATE_DATA_VERSION);
758 AFSReleaseResource( &pFcb->NPFcb->Resource);
765 // Root or directory node
772 // Set the root Fcb to this node
778 // Fall through to below
782 case AFS_DIRECTORY_FCB:
786 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
789 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
790 AFS_TRACE_LEVEL_VERBOSE,
791 "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
792 &pFcb->NPFcb->Resource,
793 PsGetCurrentThread());
795 AFSAcquireExcl( &pFcb->NPFcb->Resource,
799 // Perform some final common processing
802 ASSERT( pFcb->OpenHandleCount != 0);
804 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
807 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
810 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
812 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
815 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
817 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
820 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
822 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
825 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
828 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
830 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
833 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
836 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
838 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
843 // If the count has dropped to one and there is a pending delete
844 // then delete the node. The final count will be decremented just
845 // before the Fcb->NPFcb->Resource is released.
848 if( pFcb->OpenHandleCount == 1 &&
849 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
853 // Try to notify the service about the delete
856 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
859 // Indicate the file access mode that is being released
862 stFileCleanup.FileAccess = pCcb->FileAccess;
865 // Push the request to the service
868 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
869 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
871 &pCcb->DirectoryCB->NameInformation.FileName,
872 &pObjectInfo->FileId,
874 sizeof( AFSFileCleanupCB),
878 if( !NT_SUCCESS( ntStatus) &&
879 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
882 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
883 AFS_TRACE_LEVEL_ERROR,
884 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
888 ntStatus = STATUS_SUCCESS;
890 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
895 ntStatus = STATUS_SUCCESS;
897 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
898 AFS_TRACE_LEVEL_VERBOSE,
899 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
903 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
905 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
907 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
909 ASSERT( pParentObjectInfo != NULL);
911 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
914 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
917 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
919 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
924 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
928 // Now that the service has the entry has deleted we need to remove it from the parent
929 // tree so another lookup on the node will fail
932 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
935 AFSRemoveNameEntry( pParentObjectInfo,
941 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
942 AFS_TRACE_LEVEL_VERBOSE,
943 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
945 &pCcb->DirectoryCB->NameInformation.FileName);
948 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
950 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
952 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
953 (ULONG)FILE_ACTION_REMOVED);
959 // If there have been any updates to the node then push it to
966 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
969 ULONG ulNotifyFilter = 0;
971 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
973 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
975 if( pParentObjectInfo != NULL)
978 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
980 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
982 (ULONG)ulNotifyFilter,
983 (ULONG)FILE_ACTION_MODIFIED);
988 // Indicate the file access mode that is being released
991 stFileCleanup.FileAccess = pCcb->FileAccess;
993 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
994 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
996 &pCcb->DirectoryCB->NameInformation.FileName,
997 &pObjectInfo->FileId,
999 sizeof( AFSFileCleanupCB),
1003 if ( NT_SUCCESS( ntStatus))
1006 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1008 if ( pParentObjectInfo != NULL)
1011 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1014 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1017 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1019 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1022 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1026 ntStatus = STATUS_SUCCESS;
1030 // Release the notification for this directory if there is one
1033 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1034 &pControlDeviceExt->Specific.Control.DirNotifyList,
1038 // Remove the share access at this time since we may not get the close for sometime on this FO.
1041 IoRemoveShareAccess( pFileObject,
1042 &pFcb->ShareAccess);
1045 // We don't need the name array after the user closes the handle on the file
1048 if( pCcb->NameArray != NULL)
1051 AFSFreeNameArray( pCcb->NameArray);
1053 pCcb->NameArray = NULL;
1057 // Decrement the open child handle count
1060 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1062 if( pParentObjectInfo != NULL)
1065 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1067 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1069 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1070 AFS_TRACE_LEVEL_VERBOSE,
1071 "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1076 AFSReleaseResource( &pFcb->NPFcb->Resource);
1078 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1080 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1081 AFS_TRACE_LEVEL_VERBOSE,
1082 "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
1089 case AFS_SYMBOLIC_LINK_FCB:
1090 case AFS_MOUNT_POINT_FCB:
1091 case AFS_DFS_LINK_FCB:
1092 case AFS_INVALID_FCB:
1096 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1099 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1100 AFS_TRACE_LEVEL_VERBOSE,
1101 "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
1102 &pFcb->NPFcb->Resource,
1103 PsGetCurrentThread());
1105 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1109 // Perform some final common processing
1112 ASSERT( pFcb->OpenHandleCount != 0);
1114 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
1117 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
1120 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1122 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1125 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1127 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1130 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1132 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1135 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1138 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1140 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1143 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1146 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1148 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1153 // If the count has dropped to one and there is a pending delete
1154 // then delete the node. The final count will be decremented just
1155 // before the Fcb->NPFcb->Resource is released.
1158 if( pFcb->OpenHandleCount == 1 &&
1159 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1163 // Try to notify the service about the delete
1166 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1169 // Indicate the file access mode that is being released
1172 stFileCleanup.FileAccess = pCcb->FileAccess;
1175 // Push the request to the service
1178 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1179 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1181 &pCcb->DirectoryCB->NameInformation.FileName,
1182 &pObjectInfo->FileId,
1184 sizeof( AFSFileCleanupCB),
1188 if( !NT_SUCCESS( ntStatus) &&
1189 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1192 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1193 AFS_TRACE_LEVEL_ERROR,
1194 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1195 &pCcb->FullFileName,
1198 ntStatus = STATUS_SUCCESS;
1200 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1205 ntStatus = STATUS_SUCCESS;
1207 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1208 AFS_TRACE_LEVEL_VERBOSE,
1209 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1210 &pCcb->FullFileName,
1213 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1215 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1217 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1219 ASSERT( pParentObjectInfo != NULL);
1221 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1224 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1227 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1229 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1233 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1237 // Now that the service has the entry has deleted we need to remove it from the parent
1238 // tree so another lookup on the node will fail
1241 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1244 AFSRemoveNameEntry( pParentObjectInfo,
1250 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1251 AFS_TRACE_LEVEL_VERBOSE,
1252 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1254 &pCcb->DirectoryCB->NameInformation.FileName);
1257 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1259 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1261 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1262 (ULONG)FILE_ACTION_REMOVED);
1268 // If there have been any updates to the node then push it to
1275 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1278 ULONG ulNotifyFilter = 0;
1280 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1282 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1284 if( pParentObjectInfo != NULL)
1287 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1289 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1291 (ULONG)ulNotifyFilter,
1292 (ULONG)FILE_ACTION_MODIFIED);
1297 // Indicate the file access mode that is being released
1300 stFileCleanup.FileAccess = pCcb->FileAccess;
1302 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1303 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1305 &pCcb->DirectoryCB->NameInformation.FileName,
1306 &pObjectInfo->FileId,
1308 sizeof( AFSFileCleanupCB),
1312 if ( NT_SUCCESS( ntStatus))
1315 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1317 if ( pParentObjectInfo != NULL)
1320 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1323 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1326 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1328 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1331 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1335 ntStatus = STATUS_SUCCESS;
1339 // Remove the share access at this time since we may not get the close for sometime on this FO.
1342 IoRemoveShareAccess( pFileObject,
1343 &pFcb->ShareAccess);
1346 // We don't need the name array after the user closes the handle on the file
1349 if( pCcb->NameArray != NULL)
1352 AFSFreeNameArray( pCcb->NameArray);
1354 pCcb->NameArray = NULL;
1358 // Decrement the open child handle count
1361 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1363 if( pParentObjectInfo != NULL)
1366 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1368 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1370 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1371 AFS_TRACE_LEVEL_VERBOSE,
1372 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1377 AFSReleaseResource( &pFcb->NPFcb->Resource);
1379 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1381 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1382 AFS_TRACE_LEVEL_VERBOSE,
1383 "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
1390 case AFS_SPECIAL_SHARE_FCB:
1393 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1394 AFS_TRACE_LEVEL_VERBOSE,
1395 "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1396 &pFcb->NPFcb->Resource,
1397 PsGetCurrentThread());
1399 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1402 ASSERT( pFcb->OpenHandleCount != 0);
1405 // Decrement the open child handle count
1408 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1410 if( pParentObjectInfo != NULL &&
1411 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1414 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1416 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1417 AFS_TRACE_LEVEL_VERBOSE,
1418 "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1423 AFSReleaseResource( &pFcb->NPFcb->Resource);
1425 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1427 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1428 AFS_TRACE_LEVEL_VERBOSE,
1429 "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1438 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1439 AFS_TRACE_LEVEL_WARNING,
1440 "AFSCleanup Processing unknown node type %d\n",
1441 pFcb->Header.NodeTypeCode);
1449 if( pResultCB != NULL)
1452 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1455 if( pFileObject != NULL)
1459 // Setup the fileobject flags to indicate cleanup is complete.
1462 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1466 // Complete the request
1469 AFSCompleteRequest( Irp, ntStatus);
1471 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1476 "EXCEPTION - AFSCleanup\n");
1478 AFSDumpTraceFilesFnc();