2 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 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
238 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
239 AFS_TRACE_LEVEL_VERBOSE,
240 "AFSCleanup Acquiring Fcb lock %p EXCL %08lX\n",
241 &pFcb->NPFcb->Resource,
242 PsGetCurrentThread()));
244 AFSAcquireExcl( &pFcb->NPFcb->Resource,
247 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
248 AFS_TRACE_LEVEL_VERBOSE,
249 "AFSCleanup Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
250 &pFcb->NPFcb->SectionObjectResource,
251 PsGetCurrentThread()));
253 AFSAcquireExcl( &pFcb->NPFcb->SectionObjectResource,
260 // If the handle has write permission ...
263 if( ((pCcb->GrantedAccess & FILE_WRITE_DATA) || pFcb->OpenHandleCount == 1) &&
264 CcIsFileCached( pIrpSp->FileObject))
267 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
272 if( !NT_SUCCESS( stIoSB.Status))
275 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
276 AFS_TRACE_LEVEL_ERROR,
277 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
279 pObjectInfo->FileId.Cell,
280 pObjectInfo->FileId.Volume,
281 pObjectInfo->FileId.Vnode,
282 pObjectInfo->FileId.Unique,
284 stIoSB.Information));
286 ntStatus = stIoSB.Status;
289 if ( ( pFcb->OpenHandleCount == 1 ||
290 BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE)) &&
291 pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL)
294 if ( !CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers,
300 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
301 AFS_TRACE_LEVEL_WARNING,
302 "AFSCleanup CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
303 pObjectInfo->FileId.Cell,
304 pObjectInfo->FileId.Volume,
305 pObjectInfo->FileId.Vnode,
306 pObjectInfo->FileId.Unique));
308 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
312 ClearFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
318 // Uninitialize the cache map. This call is unconditional.
321 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
322 AFS_TRACE_LEVEL_VERBOSE,
323 "AFSCleanup Tearing down cache map for Fcb %p FileObject %p\n",
327 CcUninitializeCacheMap( pFileObject,
331 __except( EXCEPTION_EXECUTE_HANDLER)
334 ntStatus = GetExceptionCode();
338 "EXCEPTION - AFSCleanup Cc FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
339 pObjectInfo->FileId.Cell,
340 pObjectInfo->FileId.Volume,
341 pObjectInfo->FileId.Vnode,
342 pObjectInfo->FileId.Unique,
345 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
348 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT,
349 AFS_TRACE_LEVEL_VERBOSE,
350 "AFSCleanup Releasing Fcb SectionObject lock %p EXCL %08lX\n",
351 &pFcb->NPFcb->SectionObjectResource,
352 PsGetCurrentThread()));
354 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
357 // Unlock all outstanding locks on the file, again, unconditionally
360 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
362 IoGetRequestorProcess( Irp),
366 // Tell the service to unlock all on the file
369 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
372 // Perform some final common processing
375 ASSERT( pFcb->OpenHandleCount != 0);
377 if( pParentObjectInfo != NULL)
380 stFileCleanup.ParentId = pParentObjectInfo->FileId;
383 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
386 // If the file has been modified set the last write time in ObjectInfo to 'now'
387 // unless the last write time was set via this File Object. Then tell the
388 // following code to write the time.
390 if ( BooleanFlagOn( pFileObject->Flags, FO_FILE_MODIFIED) &&
391 !BooleanFlagOn( pCcb->Flags, CCB_FLAG_LAST_WRITE_TIME_SET)) {
393 SetFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
395 SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME);
397 KeQuerySystemTime(&pFcb->ObjectInformation->LastWriteTime);
400 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
403 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
405 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
407 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
410 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
412 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
415 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
418 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
420 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
423 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
426 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
428 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
431 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
434 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
436 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME);
441 // If the count has dropped to one and there is a pending delete
442 // then delete the node. The final count will be decremented just
443 // before the Fcb->NPFcb->Resource is released.
446 if( pFcb->OpenHandleCount == 1 &&
447 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
450 ntStatus = STATUS_SUCCESS;
452 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
455 // Indicate the file access mode that is being released
458 stFileCleanup.FileAccess = pCcb->FileAccess;
461 // Push the request to the service
464 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
465 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
467 &pCcb->DirectoryCB->NameInformation.FileName,
468 &pObjectInfo->FileId,
469 pObjectInfo->VolumeCB->VolumeInformation.Cell,
470 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
472 sizeof( AFSFileCleanupCB),
476 if( !NT_SUCCESS( ntStatus) &&
477 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
480 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
481 AFS_TRACE_LEVEL_ERROR,
482 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
486 ntStatus = STATUS_SUCCESS;
488 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
493 ntStatus = STATUS_SUCCESS;
495 if ( --pObjectInfo->Links < 1)
499 // Stop anything possibly in process
502 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
503 AFS_TRACE_LEVEL_VERBOSE,
504 "AFSCleanup Acquiring Fcb extents lock %p EXCL %08lX\n",
505 &pFcb->NPFcb->Specific.File.ExtentsResource,
506 PsGetCurrentThread()));
508 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
511 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
513 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
518 // The file has been deleted since the Link count is zero
521 AFSDeleteFcbExtents( pFcb);
523 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
524 AFS_TRACE_LEVEL_VERBOSE,
525 "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
526 &pFcb->NPFcb->Specific.File.ExtentsResource,
527 PsGetCurrentThread()));
529 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
532 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
533 AFS_TRACE_LEVEL_VERBOSE,
534 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
538 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
540 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
542 ASSERT( pParentObjectInfo != NULL);
544 if ( pParentObjectInfo != NULL)
547 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
550 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
553 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
555 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
560 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
564 // Now that the service has the entry has deleted we need to remove it from the parent
565 // tree so another lookup on the node will fail
568 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
571 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
572 AFS_TRACE_LEVEL_VERBOSE,
573 "AFSCleanup DE %p for %wZ removing entry\n",
575 &pCcb->DirectoryCB->NameInformation.FileName));
577 AFSRemoveNameEntry( pParentObjectInfo,
583 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
584 AFS_TRACE_LEVEL_VERBOSE,
585 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
587 &pCcb->DirectoryCB->NameInformation.FileName));
590 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
592 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
594 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
595 (ULONG)FILE_ACTION_REMOVED);
599 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
602 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
603 AFS_TRACE_LEVEL_VERBOSE,
604 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
606 &pCcb->DirectoryCB->NameInformation.FileName));
614 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
615 pParentObjectInfo != NULL)
618 ULONG ulNotifyFilter = 0;
620 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
622 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
624 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
626 (ULONG)ulNotifyFilter,
627 (ULONG)FILE_ACTION_MODIFIED);
632 // Whenever a handle with write access or the last handle is closed
633 // notify the service to FSync the file. If the redirector is holding
634 // dirty extents, flush them to the service. This is a bit aggressive
635 // but it ensures cache coherency.
638 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
641 if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
644 AFSFlushExtents( pFcb,
648 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
651 if( pFcb->OpenHandleCount == 1)
655 // Wait for any outstanding queued flushes to complete
658 AFSWaitOnQueuedFlushes( pFcb);
660 AFSTearDownFcbExtents( pFcb,
665 // Indicate the file access mode that is being released
668 stFileCleanup.FileAccess = pCcb->FileAccess;
671 // Remove the share access at this time since we may not get the close for sometime on this FO.
674 IoRemoveShareAccess( pFileObject,
679 // We don't need the name array after the user closes the handle on the file
682 if( pCcb->NameArray != NULL)
685 AFSFreeNameArray( pCcb->NameArray);
687 pCcb->NameArray = NULL;
691 // Release the Fcb Resource across the call to the service
692 // which may block for quite a while if flushing of the
696 AFSReleaseResource( &pFcb->NPFcb->Resource);
699 // Push the request to the service
702 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
703 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
705 &pCcb->DirectoryCB->NameInformation.FileName,
706 &pObjectInfo->FileId,
707 pObjectInfo->VolumeCB->VolumeInformation.Cell,
708 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
710 sizeof( AFSFileCleanupCB),
715 // Regain exclusive access to the Fcb
718 AFSAcquireExcl( &pFcb->NPFcb->Resource,
721 if ( NT_SUCCESS( ntStatus))
724 if ( pParentObjectInfo != NULL)
727 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
730 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
733 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
735 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
738 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
742 ntStatus = STATUS_SUCCESS;
746 // Decrement the open child handle count
749 if( pParentObjectInfo != NULL)
752 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
754 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
756 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
757 AFS_TRACE_LEVEL_VERBOSE,
758 "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
764 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
766 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
767 AFS_TRACE_LEVEL_VERBOSE,
768 "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
772 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
775 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
778 lCount = AFSObjectInfoIncrement( pObjectInfo,
779 AFS_OBJECT_REFERENCE_INVALIDATION);
781 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
782 AFS_TRACE_LEVEL_VERBOSE,
783 "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
787 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
789 AFSReleaseResource( &pFcb->NPFcb->Resource);
791 AFSPerformObjectInvalidate( pObjectInfo,
792 AFS_INVALIDATE_DATA_VERSION);
797 AFSReleaseResource( &pFcb->NPFcb->Resource);
804 // Root or directory node
811 // Set the root Fcb to this node
817 // Fall through to below
821 case AFS_DIRECTORY_FCB:
825 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
828 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
829 AFS_TRACE_LEVEL_VERBOSE,
830 "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
831 &pFcb->NPFcb->Resource,
832 PsGetCurrentThread()));
834 AFSAcquireExcl( &pFcb->NPFcb->Resource,
838 // Perform some final common processing
841 ASSERT( pFcb->OpenHandleCount != 0);
843 if( pParentObjectInfo != NULL)
846 stFileCleanup.ParentId = pParentObjectInfo->FileId;
849 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
851 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
854 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
856 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
859 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
861 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
864 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
867 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
869 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
872 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
875 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
877 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
882 // If the count has dropped to one and there is a pending delete
883 // then delete the node. The final count will be decremented just
884 // before the Fcb->NPFcb->Resource is released.
887 if( pFcb->OpenHandleCount == 1 &&
888 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
892 // Try to notify the service about the delete
895 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
898 // Indicate the file access mode that is being released
901 stFileCleanup.FileAccess = pCcb->FileAccess;
904 // Push the request to the service
907 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
908 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
910 &pCcb->DirectoryCB->NameInformation.FileName,
911 &pObjectInfo->FileId,
912 pObjectInfo->VolumeCB->VolumeInformation.Cell,
913 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
915 sizeof( AFSFileCleanupCB),
919 if( !NT_SUCCESS( ntStatus) &&
920 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
923 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
924 AFS_TRACE_LEVEL_ERROR,
925 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
929 ntStatus = STATUS_SUCCESS;
931 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
936 ntStatus = STATUS_SUCCESS;
938 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
939 AFS_TRACE_LEVEL_VERBOSE,
940 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
944 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
946 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
948 ASSERT( pParentObjectInfo != NULL);
950 if ( pParentObjectInfo != NULL)
953 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
956 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
959 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
961 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
966 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
970 // Now that the service has the entry has deleted we need to remove it from the parent
971 // tree so another lookup on the node will fail
974 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
977 AFSRemoveNameEntry( pParentObjectInfo,
983 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
984 AFS_TRACE_LEVEL_VERBOSE,
985 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
987 &pCcb->DirectoryCB->NameInformation.FileName));
990 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
992 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
994 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
995 (ULONG)FILE_ACTION_REMOVED);
999 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1002 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1003 AFS_TRACE_LEVEL_VERBOSE,
1004 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1006 &pCcb->DirectoryCB->NameInformation.FileName));
1013 // If there have been any updates to the node then push it to
1020 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1021 pParentObjectInfo != NULL)
1024 ULONG ulNotifyFilter = 0;
1026 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1028 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1030 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1032 (ULONG)ulNotifyFilter,
1033 (ULONG)FILE_ACTION_MODIFIED);
1037 // Indicate the file access mode that is being released
1040 stFileCleanup.FileAccess = pCcb->FileAccess;
1042 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1043 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1045 &pCcb->DirectoryCB->NameInformation.FileName,
1046 &pObjectInfo->FileId,
1047 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1048 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1050 sizeof( AFSFileCleanupCB),
1054 if ( NT_SUCCESS( ntStatus))
1057 if ( pParentObjectInfo != NULL)
1060 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1063 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1066 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1068 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1071 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1075 ntStatus = STATUS_SUCCESS;
1079 // Release the notification for this directory if there is one
1082 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1083 &pControlDeviceExt->Specific.Control.DirNotifyList,
1087 // Remove the share access at this time since we may not get the close for sometime on this FO.
1090 IoRemoveShareAccess( pFileObject,
1091 &pFcb->ShareAccess);
1094 // We don't need the name array after the user closes the handle on the file
1097 if( pCcb->NameArray != NULL)
1100 AFSFreeNameArray( pCcb->NameArray);
1102 pCcb->NameArray = NULL;
1106 // Decrement the open child handle count
1109 if( pParentObjectInfo != NULL)
1112 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1114 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1116 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1117 AFS_TRACE_LEVEL_VERBOSE,
1118 "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1123 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1125 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1126 AFS_TRACE_LEVEL_VERBOSE,
1127 "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1131 AFSReleaseResource( &pFcb->NPFcb->Resource);
1136 case AFS_SYMBOLIC_LINK_FCB:
1137 case AFS_MOUNT_POINT_FCB:
1138 case AFS_DFS_LINK_FCB:
1139 case AFS_INVALID_FCB:
1143 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1146 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1147 AFS_TRACE_LEVEL_VERBOSE,
1148 "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1149 &pFcb->NPFcb->Resource,
1150 PsGetCurrentThread()));
1152 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1156 // Perform some final common processing
1159 ASSERT( pFcb->OpenHandleCount != 0);
1161 if( pParentObjectInfo != NULL)
1164 stFileCleanup.ParentId = pParentObjectInfo->FileId;
1167 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1169 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1172 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1174 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1177 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1179 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1182 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1185 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1187 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1190 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1193 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1195 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1200 // If the count has dropped to one and there is a pending delete
1201 // then delete the node. The final count will be decremented just
1202 // before the Fcb->NPFcb->Resource is released.
1205 if( pFcb->OpenHandleCount == 1 &&
1206 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1210 // Try to notify the service about the delete
1213 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1216 // Indicate the file access mode that is being released
1219 stFileCleanup.FileAccess = pCcb->FileAccess;
1222 // Push the request to the service
1225 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1226 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1228 &pCcb->DirectoryCB->NameInformation.FileName,
1229 &pObjectInfo->FileId,
1230 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1231 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1233 sizeof( AFSFileCleanupCB),
1237 if( !NT_SUCCESS( ntStatus) &&
1238 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1241 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1242 AFS_TRACE_LEVEL_ERROR,
1243 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1244 &pCcb->FullFileName,
1247 ntStatus = STATUS_SUCCESS;
1249 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1254 ntStatus = STATUS_SUCCESS;
1256 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1257 AFS_TRACE_LEVEL_VERBOSE,
1258 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1259 &pCcb->FullFileName,
1260 pCcb->DirectoryCB));
1262 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1264 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1266 ASSERT( pParentObjectInfo != NULL);
1268 if ( pParentObjectInfo != NULL)
1271 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1274 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1277 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1279 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1283 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1287 // Now that the service has the entry has deleted we need to remove it from the parent
1288 // tree so another lookup on the node will fail
1291 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1294 AFSRemoveNameEntry( pParentObjectInfo,
1300 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1301 AFS_TRACE_LEVEL_VERBOSE,
1302 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1304 &pCcb->DirectoryCB->NameInformation.FileName));
1307 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1309 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1311 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1312 (ULONG)FILE_ACTION_REMOVED);
1317 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1320 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1321 AFS_TRACE_LEVEL_VERBOSE,
1322 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1324 &pCcb->DirectoryCB->NameInformation.FileName));
1331 // If there have been any updates to the node then push it to
1338 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1339 pParentObjectInfo != NULL)
1342 ULONG ulNotifyFilter = 0;
1344 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1346 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1348 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1350 (ULONG)ulNotifyFilter,
1351 (ULONG)FILE_ACTION_MODIFIED);
1355 // Indicate the file access mode that is being released
1358 stFileCleanup.FileAccess = pCcb->FileAccess;
1360 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1361 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1363 &pCcb->DirectoryCB->NameInformation.FileName,
1364 &pObjectInfo->FileId,
1365 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1366 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1368 sizeof( AFSFileCleanupCB),
1372 if ( NT_SUCCESS( ntStatus))
1375 if ( pParentObjectInfo != NULL)
1378 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1381 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1384 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1386 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1389 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1393 ntStatus = STATUS_SUCCESS;
1397 // Remove the share access at this time since we may not get the close for sometime on this FO.
1400 IoRemoveShareAccess( pFileObject,
1401 &pFcb->ShareAccess);
1404 // We don't need the name array after the user closes the handle on the file
1407 if( pCcb->NameArray != NULL)
1410 AFSFreeNameArray( pCcb->NameArray);
1412 pCcb->NameArray = NULL;
1416 // Decrement the open child handle count
1419 if( pParentObjectInfo != NULL)
1422 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1424 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1426 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1427 AFS_TRACE_LEVEL_VERBOSE,
1428 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1433 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1435 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1436 AFS_TRACE_LEVEL_VERBOSE,
1437 "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1441 AFSReleaseResource( &pFcb->NPFcb->Resource);
1446 case AFS_SPECIAL_SHARE_FCB:
1449 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1450 AFS_TRACE_LEVEL_VERBOSE,
1451 "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1452 &pFcb->NPFcb->Resource,
1453 PsGetCurrentThread()));
1455 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1458 ASSERT( pFcb->OpenHandleCount != 0);
1461 // Decrement the open child handle count
1464 if( pParentObjectInfo != NULL &&
1465 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1468 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1470 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1471 AFS_TRACE_LEVEL_VERBOSE,
1472 "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1477 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1479 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1480 AFS_TRACE_LEVEL_VERBOSE,
1481 "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1485 AFSReleaseResource( &pFcb->NPFcb->Resource);
1492 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1493 AFS_TRACE_LEVEL_ERROR,
1494 "AFSCleanup Processing unknown node type %d\n",
1495 pFcb->Header.NodeTypeCode));
1503 if ( pParentObjectInfo != NULL)
1506 AFSReleaseObjectInfo( &pParentObjectInfo);
1509 if( pResultCB != NULL)
1512 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1515 if( pFileObject != NULL)
1519 // Setup the fileobject flags to indicate cleanup is complete.
1522 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1526 // Complete the request
1529 AFSCompleteRequest( Irp, ntStatus);
1531 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1536 "EXCEPTION - AFSCleanup\n"));
1538 AFSDumpTraceFilesFnc();