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,
57 UNREFERENCED_PARAMETER(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 %p EXCL %08lX\n",
151 &pFcb->NPFcb->Resource,
152 PsGetCurrentThread());
154 AFSAcquireExcl( &pFcb->NPFcb->Resource,
157 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
158 &pControlDeviceExt->Specific.Control.DirNotifyList,
161 ASSERT( pFcb->OpenHandleCount != 0);
163 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
165 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
166 AFS_TRACE_LEVEL_VERBOSE,
167 "AFSCleanup (RootAll) Decrement handle count on Fcb %p Cnt %d\n",
171 AFSReleaseResource( &pFcb->NPFcb->Resource);
179 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
180 AFS_TRACE_LEVEL_VERBOSE,
181 "AFSCleanup Acquiring PIOCtl lock %p 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_OBJECT_REF_COUNTING,
201 AFS_TRACE_LEVEL_VERBOSE,
202 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %p 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 %p 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 %p 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 %p FileObject %p\n",
328 CcUninitializeCacheMap( pFileObject,
333 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
334 AFS_TRACE_LEVEL_VERBOSE,
335 "AFSCleanup Releasing Fcb SectionObject lock %p 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 %p 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 %p 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 // The file has been deleted since the Link count is zero
504 AFSDeleteFcbExtents( pFcb);
506 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
507 AFS_TRACE_LEVEL_VERBOSE,
508 "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
509 &pFcb->NPFcb->Specific.File.ExtentsResource,
510 PsGetCurrentThread());
512 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
515 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
516 AFS_TRACE_LEVEL_VERBOSE,
517 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
521 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
523 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
525 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
527 ASSERT( pParentObjectInfo != NULL);
529 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
532 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
535 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
537 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
542 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
546 // Now that the service has the entry has deleted we need to remove it from the parent
547 // tree so another lookup on the node will fail
550 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
553 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
554 AFS_TRACE_LEVEL_VERBOSE,
555 "AFSCleanup DE %p for %wZ removing entry\n",
557 &pCcb->DirectoryCB->NameInformation.FileName);
559 AFSRemoveNameEntry( pParentObjectInfo,
565 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
566 AFS_TRACE_LEVEL_VERBOSE,
567 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
569 &pCcb->DirectoryCB->NameInformation.FileName);
572 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
574 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
576 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
577 (ULONG)FILE_ACTION_REMOVED);
584 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
587 ULONG ulNotifyFilter = 0;
589 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
591 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
593 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
595 (ULONG)ulNotifyFilter,
596 (ULONG)FILE_ACTION_MODIFIED);
601 // Whenever a handle with write access or the last handle is closed
602 // notify the service to FSync the file. If the redirector is holding
603 // dirty extents, flush them to the service. This is a bit aggressive
604 // but it ensures cache coherency.
607 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
610 if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
613 AFSFlushExtents( pFcb,
617 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
620 if( pFcb->OpenHandleCount == 1)
624 // Wait for any outstanding queued flushes to complete
627 AFSWaitOnQueuedFlushes( pFcb);
629 AFSTearDownFcbExtents( pFcb,
634 // Indicate the file access mode that is being released
637 stFileCleanup.FileAccess = pCcb->FileAccess;
640 // Remove the share access at this time since we may not get the close for sometime on this FO.
643 IoRemoveShareAccess( pFileObject,
648 // We don't need the name array after the user closes the handle on the file
651 if( pCcb->NameArray != NULL)
654 AFSFreeNameArray( pCcb->NameArray);
656 pCcb->NameArray = NULL;
660 // Release the Fcb Resource across the call to the service
661 // which may block for quite a while if flushing of the
665 AFSReleaseResource( &pFcb->NPFcb->Resource);
668 // Push the request to the service
671 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
672 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
674 &pCcb->DirectoryCB->NameInformation.FileName,
675 &pObjectInfo->FileId,
677 sizeof( AFSFileCleanupCB),
682 // Regain exclusive access to the Fcb
685 AFSAcquireExcl( &pFcb->NPFcb->Resource,
688 if ( NT_SUCCESS( ntStatus))
691 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
693 if ( pParentObjectInfo != NULL)
696 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
699 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
702 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
704 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
707 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
711 ntStatus = STATUS_SUCCESS;
715 // Decrement the open child handle count
718 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
720 if( pParentObjectInfo != NULL)
723 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
725 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
727 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
728 AFS_TRACE_LEVEL_VERBOSE,
729 "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
735 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
737 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
738 AFS_TRACE_LEVEL_VERBOSE,
739 "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
743 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
746 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
749 lCount = AFSObjectInfoIncrement( pObjectInfo,
750 AFS_OBJECT_REFERENCE_INVALIDATION);
752 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
753 AFS_TRACE_LEVEL_VERBOSE,
754 "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
758 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
760 AFSReleaseResource( &pFcb->NPFcb->Resource);
762 AFSPerformObjectInvalidate( pObjectInfo,
763 AFS_INVALIDATE_DATA_VERSION);
768 AFSReleaseResource( &pFcb->NPFcb->Resource);
775 // Root or directory node
782 // Set the root Fcb to this node
788 // Fall through to below
792 case AFS_DIRECTORY_FCB:
796 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
799 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
800 AFS_TRACE_LEVEL_VERBOSE,
801 "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
802 &pFcb->NPFcb->Resource,
803 PsGetCurrentThread());
805 AFSAcquireExcl( &pFcb->NPFcb->Resource,
809 // Perform some final common processing
812 ASSERT( pFcb->OpenHandleCount != 0);
814 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
817 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
820 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
822 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
825 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
827 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
830 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
832 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
835 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
838 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
840 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
843 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
846 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
848 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
853 // If the count has dropped to one and there is a pending delete
854 // then delete the node. The final count will be decremented just
855 // before the Fcb->NPFcb->Resource is released.
858 if( pFcb->OpenHandleCount == 1 &&
859 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
863 // Try to notify the service about the delete
866 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
869 // Indicate the file access mode that is being released
872 stFileCleanup.FileAccess = pCcb->FileAccess;
875 // Push the request to the service
878 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
879 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
881 &pCcb->DirectoryCB->NameInformation.FileName,
882 &pObjectInfo->FileId,
884 sizeof( AFSFileCleanupCB),
888 if( !NT_SUCCESS( ntStatus) &&
889 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
892 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
893 AFS_TRACE_LEVEL_ERROR,
894 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
898 ntStatus = STATUS_SUCCESS;
900 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
905 ntStatus = STATUS_SUCCESS;
907 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
908 AFS_TRACE_LEVEL_VERBOSE,
909 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
913 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
915 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
917 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
919 ASSERT( pParentObjectInfo != NULL);
921 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
924 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
927 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
929 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
934 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
938 // Now that the service has the entry has deleted we need to remove it from the parent
939 // tree so another lookup on the node will fail
942 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
945 AFSRemoveNameEntry( pParentObjectInfo,
951 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
952 AFS_TRACE_LEVEL_VERBOSE,
953 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
955 &pCcb->DirectoryCB->NameInformation.FileName);
958 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
960 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
962 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
963 (ULONG)FILE_ACTION_REMOVED);
969 // If there have been any updates to the node then push it to
976 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
979 ULONG ulNotifyFilter = 0;
981 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
983 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
985 if( pParentObjectInfo != NULL)
988 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
990 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
992 (ULONG)ulNotifyFilter,
993 (ULONG)FILE_ACTION_MODIFIED);
998 // Indicate the file access mode that is being released
1001 stFileCleanup.FileAccess = pCcb->FileAccess;
1003 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1004 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1006 &pCcb->DirectoryCB->NameInformation.FileName,
1007 &pObjectInfo->FileId,
1009 sizeof( AFSFileCleanupCB),
1013 if ( NT_SUCCESS( ntStatus))
1016 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1018 if ( pParentObjectInfo != NULL)
1021 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1024 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1027 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1029 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1032 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1036 ntStatus = STATUS_SUCCESS;
1040 // Release the notification for this directory if there is one
1043 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1044 &pControlDeviceExt->Specific.Control.DirNotifyList,
1048 // Remove the share access at this time since we may not get the close for sometime on this FO.
1051 IoRemoveShareAccess( pFileObject,
1052 &pFcb->ShareAccess);
1055 // We don't need the name array after the user closes the handle on the file
1058 if( pCcb->NameArray != NULL)
1061 AFSFreeNameArray( pCcb->NameArray);
1063 pCcb->NameArray = NULL;
1067 // Decrement the open child handle count
1070 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1072 if( pParentObjectInfo != NULL)
1075 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1077 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1079 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1080 AFS_TRACE_LEVEL_VERBOSE,
1081 "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1086 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1088 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1089 AFS_TRACE_LEVEL_VERBOSE,
1090 "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1094 AFSReleaseResource( &pFcb->NPFcb->Resource);
1099 case AFS_SYMBOLIC_LINK_FCB:
1100 case AFS_MOUNT_POINT_FCB:
1101 case AFS_DFS_LINK_FCB:
1102 case AFS_INVALID_FCB:
1106 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1109 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1110 AFS_TRACE_LEVEL_VERBOSE,
1111 "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1112 &pFcb->NPFcb->Resource,
1113 PsGetCurrentThread());
1115 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1119 // Perform some final common processing
1122 ASSERT( pFcb->OpenHandleCount != 0);
1124 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
1127 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
1130 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1132 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1135 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1137 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1140 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1142 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1145 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1148 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1150 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1153 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1156 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1158 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1163 // If the count has dropped to one and there is a pending delete
1164 // then delete the node. The final count will be decremented just
1165 // before the Fcb->NPFcb->Resource is released.
1168 if( pFcb->OpenHandleCount == 1 &&
1169 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1173 // Try to notify the service about the delete
1176 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1179 // Indicate the file access mode that is being released
1182 stFileCleanup.FileAccess = pCcb->FileAccess;
1185 // Push the request to the service
1188 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1189 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1191 &pCcb->DirectoryCB->NameInformation.FileName,
1192 &pObjectInfo->FileId,
1194 sizeof( AFSFileCleanupCB),
1198 if( !NT_SUCCESS( ntStatus) &&
1199 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1202 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1203 AFS_TRACE_LEVEL_ERROR,
1204 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1205 &pCcb->FullFileName,
1208 ntStatus = STATUS_SUCCESS;
1210 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1215 ntStatus = STATUS_SUCCESS;
1217 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1218 AFS_TRACE_LEVEL_VERBOSE,
1219 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1220 &pCcb->FullFileName,
1223 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1225 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1227 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1229 ASSERT( pParentObjectInfo != NULL);
1231 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1234 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1237 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1239 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1243 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1247 // Now that the service has the entry has deleted we need to remove it from the parent
1248 // tree so another lookup on the node will fail
1251 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1254 AFSRemoveNameEntry( pParentObjectInfo,
1260 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1261 AFS_TRACE_LEVEL_VERBOSE,
1262 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1264 &pCcb->DirectoryCB->NameInformation.FileName);
1267 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1269 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1271 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1272 (ULONG)FILE_ACTION_REMOVED);
1278 // If there have been any updates to the node then push it to
1285 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1288 ULONG ulNotifyFilter = 0;
1290 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1292 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1294 if( pParentObjectInfo != NULL)
1297 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1299 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1301 (ULONG)ulNotifyFilter,
1302 (ULONG)FILE_ACTION_MODIFIED);
1307 // Indicate the file access mode that is being released
1310 stFileCleanup.FileAccess = pCcb->FileAccess;
1312 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1313 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1315 &pCcb->DirectoryCB->NameInformation.FileName,
1316 &pObjectInfo->FileId,
1318 sizeof( AFSFileCleanupCB),
1322 if ( NT_SUCCESS( ntStatus))
1325 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1327 if ( pParentObjectInfo != NULL)
1330 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1333 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1336 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1338 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1341 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1345 ntStatus = STATUS_SUCCESS;
1349 // Remove the share access at this time since we may not get the close for sometime on this FO.
1352 IoRemoveShareAccess( pFileObject,
1353 &pFcb->ShareAccess);
1356 // We don't need the name array after the user closes the handle on the file
1359 if( pCcb->NameArray != NULL)
1362 AFSFreeNameArray( pCcb->NameArray);
1364 pCcb->NameArray = NULL;
1368 // Decrement the open child handle count
1371 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1373 if( pParentObjectInfo != NULL)
1376 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1378 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1380 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1381 AFS_TRACE_LEVEL_VERBOSE,
1382 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1387 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1389 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1390 AFS_TRACE_LEVEL_VERBOSE,
1391 "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1395 AFSReleaseResource( &pFcb->NPFcb->Resource);
1400 case AFS_SPECIAL_SHARE_FCB:
1403 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1404 AFS_TRACE_LEVEL_VERBOSE,
1405 "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1406 &pFcb->NPFcb->Resource,
1407 PsGetCurrentThread());
1409 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1412 ASSERT( pFcb->OpenHandleCount != 0);
1415 // Decrement the open child handle count
1418 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1420 if( pParentObjectInfo != NULL &&
1421 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1424 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1426 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1427 AFS_TRACE_LEVEL_VERBOSE,
1428 "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1433 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1435 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1436 AFS_TRACE_LEVEL_VERBOSE,
1437 "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1441 AFSReleaseResource( &pFcb->NPFcb->Resource);
1448 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1449 AFS_TRACE_LEVEL_ERROR,
1450 "AFSCleanup Processing unknown node type %d\n",
1451 pFcb->Header.NodeTypeCode);
1459 if( pResultCB != NULL)
1462 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1465 if( pFileObject != NULL)
1469 // Setup the fileobject flags to indicate cleanup is complete.
1472 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1476 // Complete the request
1479 AFSCompleteRequest( Irp, ntStatus);
1481 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1486 "EXCEPTION - AFSCleanup\n");
1488 AFSDumpTraceFilesFnc();