2 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011, 2012, 2013 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
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16 * nor the names of their contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission from Kernel Drivers, LLC and Your File System, Inc.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // File: AFSCleanup.cpp
37 #include "AFSCommon.h"
40 // Function: AFSCleanup
44 // This function is the IRP_MJ_CLEANUP dispatch handler
48 // A status is returned for the handling of this request
52 AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject,
55 UNREFERENCED_PARAMETER(LibDeviceObject);
56 NTSTATUS ntStatus = STATUS_SUCCESS;
57 AFSDeviceExt *pDeviceExt = NULL;
58 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
61 PFILE_OBJECT pFileObject = NULL;
62 AFSFcb *pRootFcb = NULL;
63 AFSDeviceExt *pControlDeviceExt = NULL;
64 IO_STATUS_BLOCK stIoSB;
65 AFSObjectInfoCB *pObjectInfo = NULL;
66 AFSObjectInfoCB *pParentObjectInfo = NULL;
67 AFSFileCleanupCB stFileCleanup;
68 AFSFileCleanupResultCB *pResultCB = NULL;
69 ULONG ulResultLen = 0;
70 ULONG ulNotificationFlags = 0;
76 if( AFSRDRDeviceObject == NULL)
80 // Let this through, it's a cleanup on the library control device
83 try_return( ntStatus);
86 pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
88 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
91 // Set some initial variables to make processing easier
94 pFileObject = pIrpSp->FileObject;
96 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
98 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
102 try_return( ntStatus);
105 pObjectInfo = pFcb->ObjectInformation;
107 if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
110 pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
111 &pObjectInfo->ParentFileId,
115 pRootFcb = pObjectInfo->VolumeCB->RootFcb;
117 RtlZeroMemory( &stFileCleanup,
118 sizeof( AFSFileCleanupCB));
120 stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
122 stFileCleanup.Identifier = (ULONGLONG)pFileObject;
125 // Allocate our return buffer
128 pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
130 AFS_GENERIC_MEMORY_32_TAG);
132 if( pResultCB == NULL)
135 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
138 RtlZeroMemory( pResultCB,
141 ulResultLen = PAGE_SIZE;
145 // Perform the cleanup functionality depending on the type of node it is
148 switch( pFcb->Header.NodeTypeCode)
154 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
155 AFS_TRACE_LEVEL_VERBOSE,
156 "AFSCleanup Acquiring GlobalRoot lock %p EXCL %08lX\n",
157 &pFcb->NPFcb->Resource,
158 PsGetCurrentThread()));
160 AFSAcquireExcl( &pFcb->NPFcb->Resource,
163 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
164 &pControlDeviceExt->Specific.Control.DirNotifyList,
167 ASSERT( pFcb->OpenHandleCount != 0);
169 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
171 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
172 AFS_TRACE_LEVEL_VERBOSE,
173 "AFSCleanup (RootAll) Decrement handle count on Fcb %p Cnt %d\n",
177 AFSReleaseResource( &pFcb->NPFcb->Resource);
185 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
186 AFS_TRACE_LEVEL_VERBOSE,
187 "AFSCleanup Acquiring PIOCtl lock %p EXCL %08lX\n",
188 &pFcb->NPFcb->Resource,
189 PsGetCurrentThread()));
191 AFSAcquireExcl( &pFcb->NPFcb->Resource,
194 ASSERT( pFcb->OpenHandleCount != 0);
197 // Decrement the open child handle count
200 if( pParentObjectInfo != NULL &&
201 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
204 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
206 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
207 AFS_TRACE_LEVEL_VERBOSE,
208 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %p Cnt %d\n",
213 AFSReleaseResource( &pFcb->NPFcb->Resource);
215 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
217 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
218 AFS_TRACE_LEVEL_VERBOSE,
219 "AFSCleanup (IOCtl) Decrement handle count on Fcb %p Cnt %d\n",
227 // This Fcb represents a file
234 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
237 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
238 AFS_TRACE_LEVEL_VERBOSE,
239 "AFSCleanup Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
240 &pFcb->NPFcb->SectionObjectResource,
241 PsGetCurrentThread()));
243 AFSAcquireExcl( &pFcb->NPFcb->SectionObjectResource,
250 // If the handle has write permission ...
253 if( ((pCcb->GrantedAccess & FILE_WRITE_DATA) || pFcb->OpenHandleCount == 1) &&
254 CcIsFileCached( pIrpSp->FileObject))
257 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
262 if( !NT_SUCCESS( stIoSB.Status))
265 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
266 AFS_TRACE_LEVEL_ERROR,
267 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
269 pObjectInfo->FileId.Cell,
270 pObjectInfo->FileId.Volume,
271 pObjectInfo->FileId.Vnode,
272 pObjectInfo->FileId.Unique,
274 stIoSB.Information));
276 ntStatus = stIoSB.Status;
279 if ( ( pFcb->OpenHandleCount == 1 ||
280 BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE)) &&
281 pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL)
284 if ( !CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers,
290 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
291 AFS_TRACE_LEVEL_WARNING,
292 "AFSCleanup CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
293 pObjectInfo->FileId.Cell,
294 pObjectInfo->FileId.Volume,
295 pObjectInfo->FileId.Vnode,
296 pObjectInfo->FileId.Unique));
298 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
302 ClearFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
308 // Uninitialize the cache map. This call is unconditional.
311 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
312 AFS_TRACE_LEVEL_VERBOSE,
313 "AFSCleanup Tearing down cache map for Fcb %p FileObject %p\n",
317 CcUninitializeCacheMap( pFileObject,
321 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()))
324 ntStatus = GetExceptionCode();
328 "EXCEPTION - AFSCleanup Cc FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
329 pObjectInfo->FileId.Cell,
330 pObjectInfo->FileId.Volume,
331 pObjectInfo->FileId.Vnode,
332 pObjectInfo->FileId.Unique,
335 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
338 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
339 AFS_TRACE_LEVEL_VERBOSE,
340 "AFSCleanup Releasing Fcb SectionObject lock %p EXCL %08lX\n",
341 &pFcb->NPFcb->SectionObjectResource,
342 PsGetCurrentThread()));
344 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
346 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
347 AFS_TRACE_LEVEL_VERBOSE,
348 "AFSCleanup Acquiring Fcb lock %p EXCL %08lX\n",
349 &pFcb->NPFcb->Resource,
350 PsGetCurrentThread()));
352 AFSAcquireExcl( &pFcb->NPFcb->Resource,
356 // Unlock all outstanding locks on the file, again, unconditionally
359 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
361 IoGetRequestorProcess( Irp),
365 // Tell the service to unlock all on the file
368 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
371 // Perform some final common processing
374 ASSERT( pFcb->OpenHandleCount != 0);
376 if( pParentObjectInfo != NULL)
379 stFileCleanup.ParentId = pParentObjectInfo->FileId;
382 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
384 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
387 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
389 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
391 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
394 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
396 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
399 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
402 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
404 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
407 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
410 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
412 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
415 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
418 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
420 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
424 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
427 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
431 // If the count has dropped to one and there is a pending delete
432 // then delete the node. The final count will be decremented just
433 // before the Fcb->NPFcb->Resource is released.
436 if( pFcb->OpenHandleCount == 1 &&
437 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
440 ntStatus = STATUS_SUCCESS;
442 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
445 // Indicate the file access mode that is being released
448 stFileCleanup.FileAccess = pCcb->FileAccess;
451 // Push the request to the service
454 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
455 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
457 &pCcb->DirectoryCB->NameInformation.FileName,
458 &pObjectInfo->FileId,
459 pObjectInfo->VolumeCB->VolumeInformation.Cell,
460 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
462 sizeof( AFSFileCleanupCB),
466 if( !NT_SUCCESS( ntStatus) &&
467 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
470 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
471 AFS_TRACE_LEVEL_ERROR,
472 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
476 ntStatus = STATUS_SUCCESS;
478 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
483 ntStatus = STATUS_SUCCESS;
485 if ( --pObjectInfo->Links < 1)
489 // Stop anything possibly in process
492 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
493 AFS_TRACE_LEVEL_VERBOSE,
494 "AFSCleanup Acquiring Fcb extents lock %p EXCL %08lX\n",
495 &pFcb->NPFcb->Specific.File.ExtentsResource,
496 PsGetCurrentThread()));
498 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
501 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
503 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
508 // The file has been deleted since the Link count is zero
511 AFSDeleteFcbExtents( pFcb);
513 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
514 AFS_TRACE_LEVEL_VERBOSE,
515 "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
516 &pFcb->NPFcb->Specific.File.ExtentsResource,
517 PsGetCurrentThread()));
519 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
522 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
523 AFS_TRACE_LEVEL_VERBOSE,
524 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
528 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
530 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
532 ASSERT( pParentObjectInfo != NULL);
534 if ( pParentObjectInfo != NULL)
537 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
540 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
543 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
545 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
550 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
554 // Now that the service has the entry has deleted we need to remove it from the parent
555 // tree so another lookup on the node will fail
558 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
561 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
562 AFS_TRACE_LEVEL_VERBOSE,
563 "AFSCleanup DE %p for %wZ removing entry\n",
565 &pCcb->DirectoryCB->NameInformation.FileName));
567 AFSRemoveNameEntry( pParentObjectInfo,
573 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
574 AFS_TRACE_LEVEL_VERBOSE,
575 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
577 &pCcb->DirectoryCB->NameInformation.FileName));
580 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
582 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
584 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
585 (ULONG)FILE_ACTION_REMOVED);
589 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
592 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
593 AFS_TRACE_LEVEL_VERBOSE,
594 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
596 &pCcb->DirectoryCB->NameInformation.FileName));
604 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
605 pParentObjectInfo != NULL)
608 ULONG ulNotifyFilter = 0;
610 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
612 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
614 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
616 (ULONG)ulNotifyFilter,
617 (ULONG)FILE_ACTION_MODIFIED);
622 // Whenever a handle with write access or the last handle is closed
623 // notify the service to FSync the file. If the redirector is holding
624 // dirty extents, flush them to the service. This is a bit aggressive
625 // but it ensures cache coherency.
628 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
631 if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
634 AFSFlushExtents( pFcb,
638 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
641 if( pFcb->OpenHandleCount == 1)
645 // Wait for any outstanding queued flushes to complete
648 AFSWaitOnQueuedFlushes( pFcb);
650 AFSTearDownFcbExtents( pFcb,
655 // Indicate the file access mode that is being released
658 stFileCleanup.FileAccess = pCcb->FileAccess;
661 // Remove the share access at this time since we may not get the close for sometime on this FO.
664 IoRemoveShareAccess( pFileObject,
669 // We don't need the name array after the user closes the handle on the file
672 if( pCcb->NameArray != NULL)
675 AFSFreeNameArray( pCcb->NameArray);
677 pCcb->NameArray = NULL;
681 // Release the Fcb Resource across the call to the service
682 // which may block for quite a while if flushing of the
686 AFSReleaseResource( &pFcb->NPFcb->Resource);
689 // Push the request to the service
692 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
693 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
695 &pCcb->DirectoryCB->NameInformation.FileName,
696 &pObjectInfo->FileId,
697 pObjectInfo->VolumeCB->VolumeInformation.Cell,
698 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
700 sizeof( AFSFileCleanupCB),
705 // Regain exclusive access to the Fcb
708 AFSAcquireExcl( &pFcb->NPFcb->Resource,
711 if ( NT_SUCCESS( ntStatus))
714 if ( pParentObjectInfo != NULL)
717 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
720 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
723 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
725 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
728 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
732 ntStatus = STATUS_SUCCESS;
736 // Decrement the open child handle count
739 if( pParentObjectInfo != NULL)
742 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
744 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
746 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
747 AFS_TRACE_LEVEL_VERBOSE,
748 "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
754 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
756 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
757 AFS_TRACE_LEVEL_VERBOSE,
758 "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
762 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
765 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
768 lCount = AFSObjectInfoIncrement( pObjectInfo,
769 AFS_OBJECT_REFERENCE_INVALIDATION);
771 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
772 AFS_TRACE_LEVEL_VERBOSE,
773 "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
777 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
779 AFSReleaseResource( &pFcb->NPFcb->Resource);
781 AFSPerformObjectInvalidate( pObjectInfo,
782 AFS_INVALIDATE_DATA_VERSION);
787 AFSReleaseResource( &pFcb->NPFcb->Resource);
794 // Root or directory node
801 // Set the root Fcb to this node
807 // Fall through to below
811 case AFS_DIRECTORY_FCB:
815 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
818 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
819 AFS_TRACE_LEVEL_VERBOSE,
820 "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
821 &pFcb->NPFcb->Resource,
822 PsGetCurrentThread()));
824 AFSAcquireExcl( &pFcb->NPFcb->Resource,
828 // Perform some final common processing
831 ASSERT( pFcb->OpenHandleCount != 0);
833 if( pParentObjectInfo != NULL)
836 stFileCleanup.ParentId = pParentObjectInfo->FileId;
839 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
841 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
844 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
846 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
849 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
851 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
854 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
857 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
859 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
862 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
865 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
867 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
872 // If the count has dropped to one and there is a pending delete
873 // then delete the node. The final count will be decremented just
874 // before the Fcb->NPFcb->Resource is released.
877 if( pFcb->OpenHandleCount == 1 &&
878 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
882 // Try to notify the service about the delete
885 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
888 // Indicate the file access mode that is being released
891 stFileCleanup.FileAccess = pCcb->FileAccess;
894 // Push the request to the service
897 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
898 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
900 &pCcb->DirectoryCB->NameInformation.FileName,
901 &pObjectInfo->FileId,
902 pObjectInfo->VolumeCB->VolumeInformation.Cell,
903 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
905 sizeof( AFSFileCleanupCB),
909 if( !NT_SUCCESS( ntStatus) &&
910 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
913 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
914 AFS_TRACE_LEVEL_ERROR,
915 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
919 ntStatus = STATUS_SUCCESS;
921 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
926 ntStatus = STATUS_SUCCESS;
928 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
929 AFS_TRACE_LEVEL_VERBOSE,
930 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
934 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
936 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
938 ASSERT( pParentObjectInfo != NULL);
940 if ( pParentObjectInfo != NULL)
943 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
946 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
949 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
951 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
956 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
960 // Now that the service has the entry has deleted we need to remove it from the parent
961 // tree so another lookup on the node will fail
964 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
967 AFSRemoveNameEntry( pParentObjectInfo,
973 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
974 AFS_TRACE_LEVEL_VERBOSE,
975 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
977 &pCcb->DirectoryCB->NameInformation.FileName));
980 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
982 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
984 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
985 (ULONG)FILE_ACTION_REMOVED);
989 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
992 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
993 AFS_TRACE_LEVEL_VERBOSE,
994 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
996 &pCcb->DirectoryCB->NameInformation.FileName));
1003 // If there have been any updates to the node then push it to
1010 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1011 pParentObjectInfo != NULL)
1014 ULONG ulNotifyFilter = 0;
1016 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1018 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1020 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1022 (ULONG)ulNotifyFilter,
1023 (ULONG)FILE_ACTION_MODIFIED);
1027 // Indicate the file access mode that is being released
1030 stFileCleanup.FileAccess = pCcb->FileAccess;
1032 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1033 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1035 &pCcb->DirectoryCB->NameInformation.FileName,
1036 &pObjectInfo->FileId,
1037 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1038 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1040 sizeof( AFSFileCleanupCB),
1044 if ( NT_SUCCESS( ntStatus))
1047 if ( pParentObjectInfo != NULL)
1050 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1053 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1056 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1058 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1061 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1065 ntStatus = STATUS_SUCCESS;
1069 // Release the notification for this directory if there is one
1072 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1073 &pControlDeviceExt->Specific.Control.DirNotifyList,
1077 // Remove the share access at this time since we may not get the close for sometime on this FO.
1080 IoRemoveShareAccess( pFileObject,
1081 &pFcb->ShareAccess);
1084 // We don't need the name array after the user closes the handle on the file
1087 if( pCcb->NameArray != NULL)
1090 AFSFreeNameArray( pCcb->NameArray);
1092 pCcb->NameArray = NULL;
1096 // Decrement the open child handle count
1099 if( pParentObjectInfo != NULL)
1102 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1104 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1106 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1107 AFS_TRACE_LEVEL_VERBOSE,
1108 "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1113 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1115 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1116 AFS_TRACE_LEVEL_VERBOSE,
1117 "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1121 AFSReleaseResource( &pFcb->NPFcb->Resource);
1126 case AFS_SYMBOLIC_LINK_FCB:
1127 case AFS_MOUNT_POINT_FCB:
1128 case AFS_DFS_LINK_FCB:
1129 case AFS_INVALID_FCB:
1133 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1136 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1137 AFS_TRACE_LEVEL_VERBOSE,
1138 "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1139 &pFcb->NPFcb->Resource,
1140 PsGetCurrentThread()));
1142 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1146 // Perform some final common processing
1149 ASSERT( pFcb->OpenHandleCount != 0);
1151 if( pParentObjectInfo != NULL)
1154 stFileCleanup.ParentId = pParentObjectInfo->FileId;
1157 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1159 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1162 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1164 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1167 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1169 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1172 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1175 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1177 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1180 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1183 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1185 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1190 // If the count has dropped to one and there is a pending delete
1191 // then delete the node. The final count will be decremented just
1192 // before the Fcb->NPFcb->Resource is released.
1195 if( pFcb->OpenHandleCount == 1 &&
1196 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1200 // Try to notify the service about the delete
1203 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1206 // Indicate the file access mode that is being released
1209 stFileCleanup.FileAccess = pCcb->FileAccess;
1212 // Push the request to the service
1215 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1216 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1218 &pCcb->DirectoryCB->NameInformation.FileName,
1219 &pObjectInfo->FileId,
1220 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1221 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1223 sizeof( AFSFileCleanupCB),
1227 if( !NT_SUCCESS( ntStatus) &&
1228 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1231 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1232 AFS_TRACE_LEVEL_ERROR,
1233 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1234 &pCcb->FullFileName,
1237 ntStatus = STATUS_SUCCESS;
1239 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1244 ntStatus = STATUS_SUCCESS;
1246 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1247 AFS_TRACE_LEVEL_VERBOSE,
1248 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1249 &pCcb->FullFileName,
1250 pCcb->DirectoryCB));
1252 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1254 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1256 ASSERT( pParentObjectInfo != NULL);
1258 if ( pParentObjectInfo != NULL)
1261 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1264 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1267 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1269 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1273 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1277 // Now that the service has the entry has deleted we need to remove it from the parent
1278 // tree so another lookup on the node will fail
1281 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1284 AFSRemoveNameEntry( pParentObjectInfo,
1290 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1291 AFS_TRACE_LEVEL_VERBOSE,
1292 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1294 &pCcb->DirectoryCB->NameInformation.FileName));
1297 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1299 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1301 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1302 (ULONG)FILE_ACTION_REMOVED);
1307 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1310 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1311 AFS_TRACE_LEVEL_VERBOSE,
1312 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1314 &pCcb->DirectoryCB->NameInformation.FileName));
1321 // If there have been any updates to the node then push it to
1328 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1329 pParentObjectInfo != NULL)
1332 ULONG ulNotifyFilter = 0;
1334 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1336 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1338 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1340 (ULONG)ulNotifyFilter,
1341 (ULONG)FILE_ACTION_MODIFIED);
1345 // Indicate the file access mode that is being released
1348 stFileCleanup.FileAccess = pCcb->FileAccess;
1350 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1351 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1353 &pCcb->DirectoryCB->NameInformation.FileName,
1354 &pObjectInfo->FileId,
1355 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1356 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1358 sizeof( AFSFileCleanupCB),
1362 if ( NT_SUCCESS( ntStatus))
1365 if ( pParentObjectInfo != NULL)
1368 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1371 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1374 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1376 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1379 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1383 ntStatus = STATUS_SUCCESS;
1387 // Remove the share access at this time since we may not get the close for sometime on this FO.
1390 IoRemoveShareAccess( pFileObject,
1391 &pFcb->ShareAccess);
1394 // We don't need the name array after the user closes the handle on the file
1397 if( pCcb->NameArray != NULL)
1400 AFSFreeNameArray( pCcb->NameArray);
1402 pCcb->NameArray = NULL;
1406 // Decrement the open child handle count
1409 if( pParentObjectInfo != NULL)
1412 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1414 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1416 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1417 AFS_TRACE_LEVEL_VERBOSE,
1418 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1423 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1425 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1426 AFS_TRACE_LEVEL_VERBOSE,
1427 "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1431 AFSReleaseResource( &pFcb->NPFcb->Resource);
1436 case AFS_SPECIAL_SHARE_FCB:
1439 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1440 AFS_TRACE_LEVEL_VERBOSE,
1441 "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1442 &pFcb->NPFcb->Resource,
1443 PsGetCurrentThread()));
1445 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1448 ASSERT( pFcb->OpenHandleCount != 0);
1451 // Decrement the open child handle count
1454 if( pParentObjectInfo != NULL &&
1455 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1458 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1460 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1461 AFS_TRACE_LEVEL_VERBOSE,
1462 "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1467 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1469 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1470 AFS_TRACE_LEVEL_VERBOSE,
1471 "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1475 AFSReleaseResource( &pFcb->NPFcb->Resource);
1482 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1483 AFS_TRACE_LEVEL_ERROR,
1484 "AFSCleanup Processing unknown node type %d\n",
1485 pFcb->Header.NodeTypeCode));
1493 if ( pParentObjectInfo != NULL)
1496 AFSReleaseObjectInfo( &pParentObjectInfo);
1499 if( pResultCB != NULL)
1502 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1505 if( pFileObject != NULL)
1509 // Setup the fileobject flags to indicate cleanup is complete.
1512 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1516 // Complete the request
1519 AFSCompleteRequest( Irp, ntStatus);
1521 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1526 "EXCEPTION - AFSCleanup\n"));
1528 AFSDumpTraceFilesFnc();