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 if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_PARENT_FID))
112 pParentObjectInfo = AFSFindObjectInfo( pObjectInfo->VolumeCB,
113 &pObjectInfo->ParentFileId);
116 pRootFcb = pObjectInfo->VolumeCB->RootFcb;
118 RtlZeroMemory( &stFileCleanup,
119 sizeof( AFSFileCleanupCB));
121 stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
123 stFileCleanup.Identifier = (ULONGLONG)pFileObject;
126 // Allocate our return buffer
129 pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
131 AFS_GENERIC_MEMORY_32_TAG);
133 if( pResultCB == NULL)
136 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
139 RtlZeroMemory( pResultCB,
142 ulResultLen = PAGE_SIZE;
146 // Perform the cleanup functionality depending on the type of node it is
149 switch( pFcb->Header.NodeTypeCode)
155 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
156 AFS_TRACE_LEVEL_VERBOSE,
157 "AFSCleanup Acquiring GlobalRoot lock %p EXCL %08lX\n",
158 &pFcb->NPFcb->Resource,
159 PsGetCurrentThread());
161 AFSAcquireExcl( &pFcb->NPFcb->Resource,
164 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
165 &pControlDeviceExt->Specific.Control.DirNotifyList,
168 ASSERT( pFcb->OpenHandleCount != 0);
170 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
172 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
173 AFS_TRACE_LEVEL_VERBOSE,
174 "AFSCleanup (RootAll) Decrement handle count on Fcb %p Cnt %d\n",
178 AFSReleaseResource( &pFcb->NPFcb->Resource);
186 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
187 AFS_TRACE_LEVEL_VERBOSE,
188 "AFSCleanup Acquiring PIOCtl lock %p EXCL %08lX\n",
189 &pFcb->NPFcb->Resource,
190 PsGetCurrentThread());
192 AFSAcquireExcl( &pFcb->NPFcb->Resource,
195 ASSERT( pFcb->OpenHandleCount != 0);
198 // Decrement the open child handle count
201 if( pParentObjectInfo != NULL &&
202 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
205 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
207 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
208 AFS_TRACE_LEVEL_VERBOSE,
209 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %p Cnt %d\n",
214 AFSReleaseResource( &pFcb->NPFcb->Resource);
216 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
218 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
219 AFS_TRACE_LEVEL_VERBOSE,
220 "AFSCleanup (IOCtl) Decrement handle count on Fcb %p Cnt %d\n",
228 // This Fcb represents a file
235 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
238 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
239 AFS_TRACE_LEVEL_VERBOSE,
240 "AFSCleanup Acquiring Fcb SectionObject lock %p EXCL %08lX\n",
241 &pFcb->NPFcb->SectionObjectResource,
242 PsGetCurrentThread());
244 AFSAcquireExcl( &pFcb->NPFcb->SectionObjectResource,
248 // If the handle has write permission ...
251 if( ((pCcb->GrantedAccess & FILE_WRITE_DATA) || pFcb->OpenHandleCount == 1) &&
252 CcIsFileCached( pIrpSp->FileObject))
258 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
263 if( !NT_SUCCESS( stIoSB.Status))
266 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
267 AFS_TRACE_LEVEL_ERROR,
268 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
270 pObjectInfo->FileId.Cell,
271 pObjectInfo->FileId.Volume,
272 pObjectInfo->FileId.Vnode,
273 pObjectInfo->FileId.Unique,
277 ntStatus = stIoSB.Status;
280 if ( ( pFcb->OpenHandleCount == 1 ||
281 BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE)) &&
282 pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL)
285 if ( !CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers,
291 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
292 AFS_TRACE_LEVEL_WARNING,
293 "AFSCleanup CcPurgeCacheSection failure FID %08lX-%08lX-%08lX-%08lX\n",
294 pObjectInfo->FileId.Cell,
295 pObjectInfo->FileId.Volume,
296 pObjectInfo->FileId.Vnode,
297 pObjectInfo->FileId.Unique);
299 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
303 ClearFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
307 __except( EXCEPTION_EXECUTE_HANDLER)
310 ntStatus = GetExceptionCode();
314 "EXCEPTION - AFSCleanup Cc FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n",
315 pObjectInfo->FileId.Cell,
316 pObjectInfo->FileId.Volume,
317 pObjectInfo->FileId.Vnode,
318 pObjectInfo->FileId.Unique,
321 SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
326 // Uninitialize the cache map. This call is unconditional.
329 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
330 AFS_TRACE_LEVEL_VERBOSE,
331 "AFSCleanup Tearing down cache map for Fcb %p FileObject %p\n",
335 CcUninitializeCacheMap( pFileObject,
340 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
341 AFS_TRACE_LEVEL_VERBOSE,
342 "AFSCleanup Releasing Fcb SectionObject lock %p EXCL %08lX\n",
343 &pFcb->NPFcb->SectionObjectResource,
344 PsGetCurrentThread());
346 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
348 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
349 AFS_TRACE_LEVEL_VERBOSE,
350 "AFSCleanup Acquiring Fcb lock %p EXCL %08lX\n",
351 &pFcb->NPFcb->Resource,
352 PsGetCurrentThread());
354 AFSAcquireExcl( &pFcb->NPFcb->Resource,
358 // Unlock all outstanding locks on the file, again, unconditionally
361 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
363 IoGetRequestorProcess( Irp),
367 // Tell the service to unlock all on the file
370 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
373 // Perform some final common processing
376 ASSERT( pFcb->OpenHandleCount != 0);
378 if( pParentObjectInfo != NULL)
381 stFileCleanup.ParentId = pParentObjectInfo->FileId;
384 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
386 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
389 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
391 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
393 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
396 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
398 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
401 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
404 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
406 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
409 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
412 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
414 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
417 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
420 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
422 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
426 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
429 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
433 // If the count has dropped to one and there is a pending delete
434 // then delete the node. The final count will be decremented just
435 // before the Fcb->NPFcb->Resource is released.
438 if( pFcb->OpenHandleCount == 1 &&
439 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
442 ntStatus = STATUS_SUCCESS;
444 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
447 // Indicate the file access mode that is being released
450 stFileCleanup.FileAccess = pCcb->FileAccess;
453 // Push the request to the service
456 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
457 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
459 &pCcb->DirectoryCB->NameInformation.FileName,
460 &pObjectInfo->FileId,
461 pObjectInfo->VolumeCB->VolumeInformation.Cell,
462 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
464 sizeof( AFSFileCleanupCB),
468 if( !NT_SUCCESS( ntStatus) &&
469 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
472 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
473 AFS_TRACE_LEVEL_ERROR,
474 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
478 ntStatus = STATUS_SUCCESS;
480 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
485 ntStatus = STATUS_SUCCESS;
487 if ( --pObjectInfo->Links < 1)
491 // Stop anything possibly in process
494 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
495 AFS_TRACE_LEVEL_VERBOSE,
496 "AFSCleanup Acquiring Fcb extents lock %p EXCL %08lX\n",
497 &pFcb->NPFcb->Specific.File.ExtentsResource,
498 PsGetCurrentThread());
500 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
503 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
505 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
510 // The file has been deleted since the Link count is zero
513 AFSDeleteFcbExtents( pFcb);
515 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
516 AFS_TRACE_LEVEL_VERBOSE,
517 "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
518 &pFcb->NPFcb->Specific.File.ExtentsResource,
519 PsGetCurrentThread());
521 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
524 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
525 AFS_TRACE_LEVEL_VERBOSE,
526 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
530 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
532 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
534 ASSERT( pParentObjectInfo != NULL);
536 if ( pParentObjectInfo != NULL)
539 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
542 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
545 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
547 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
552 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
556 // Now that the service has the entry has deleted we need to remove it from the parent
557 // tree so another lookup on the node will fail
560 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
563 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
564 AFS_TRACE_LEVEL_VERBOSE,
565 "AFSCleanup DE %p for %wZ removing entry\n",
567 &pCcb->DirectoryCB->NameInformation.FileName);
569 AFSRemoveNameEntry( pParentObjectInfo,
575 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
576 AFS_TRACE_LEVEL_VERBOSE,
577 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
579 &pCcb->DirectoryCB->NameInformation.FileName);
582 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
584 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
586 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
587 (ULONG)FILE_ACTION_REMOVED);
591 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
594 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
595 AFS_TRACE_LEVEL_VERBOSE,
596 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
598 &pCcb->DirectoryCB->NameInformation.FileName);
606 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
607 pParentObjectInfo != NULL)
610 ULONG ulNotifyFilter = 0;
612 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
614 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
616 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
618 (ULONG)ulNotifyFilter,
619 (ULONG)FILE_ACTION_MODIFIED);
624 // Whenever a handle with write access or the last handle is closed
625 // notify the service to FSync the file. If the redirector is holding
626 // dirty extents, flush them to the service. This is a bit aggressive
627 // but it ensures cache coherency.
630 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
633 if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
636 AFSFlushExtents( pFcb,
640 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
643 if( pFcb->OpenHandleCount == 1)
647 // Wait for any outstanding queued flushes to complete
650 AFSWaitOnQueuedFlushes( pFcb);
652 AFSTearDownFcbExtents( pFcb,
657 // Indicate the file access mode that is being released
660 stFileCleanup.FileAccess = pCcb->FileAccess;
663 // Remove the share access at this time since we may not get the close for sometime on this FO.
666 IoRemoveShareAccess( pFileObject,
671 // We don't need the name array after the user closes the handle on the file
674 if( pCcb->NameArray != NULL)
677 AFSFreeNameArray( pCcb->NameArray);
679 pCcb->NameArray = NULL;
683 // Release the Fcb Resource across the call to the service
684 // which may block for quite a while if flushing of the
688 AFSReleaseResource( &pFcb->NPFcb->Resource);
691 // Push the request to the service
694 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
695 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
697 &pCcb->DirectoryCB->NameInformation.FileName,
698 &pObjectInfo->FileId,
699 pObjectInfo->VolumeCB->VolumeInformation.Cell,
700 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
702 sizeof( AFSFileCleanupCB),
707 // Regain exclusive access to the Fcb
710 AFSAcquireExcl( &pFcb->NPFcb->Resource,
713 if ( NT_SUCCESS( ntStatus))
716 if ( pParentObjectInfo != NULL)
719 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
722 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
725 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
727 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
730 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
734 ntStatus = STATUS_SUCCESS;
738 // Decrement the open child handle count
741 if( pParentObjectInfo != NULL)
744 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
746 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
748 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
749 AFS_TRACE_LEVEL_VERBOSE,
750 "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
756 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
758 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
759 AFS_TRACE_LEVEL_VERBOSE,
760 "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
764 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
767 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
770 lCount = AFSObjectInfoIncrement( pObjectInfo,
771 AFS_OBJECT_REFERENCE_INVALIDATION);
773 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
774 AFS_TRACE_LEVEL_VERBOSE,
775 "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
779 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
781 AFSReleaseResource( &pFcb->NPFcb->Resource);
783 AFSPerformObjectInvalidate( pObjectInfo,
784 AFS_INVALIDATE_DATA_VERSION);
789 AFSReleaseResource( &pFcb->NPFcb->Resource);
796 // Root or directory node
803 // Set the root Fcb to this node
809 // Fall through to below
813 case AFS_DIRECTORY_FCB:
817 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
820 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
821 AFS_TRACE_LEVEL_VERBOSE,
822 "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
823 &pFcb->NPFcb->Resource,
824 PsGetCurrentThread());
826 AFSAcquireExcl( &pFcb->NPFcb->Resource,
830 // Perform some final common processing
833 ASSERT( pFcb->OpenHandleCount != 0);
835 if( pParentObjectInfo != NULL)
838 stFileCleanup.ParentId = pParentObjectInfo->FileId;
841 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
843 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
846 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
848 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
851 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
853 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
856 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
859 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
861 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
864 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
867 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
869 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
874 // If the count has dropped to one and there is a pending delete
875 // then delete the node. The final count will be decremented just
876 // before the Fcb->NPFcb->Resource is released.
879 if( pFcb->OpenHandleCount == 1 &&
880 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
884 // Try to notify the service about the delete
887 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
890 // Indicate the file access mode that is being released
893 stFileCleanup.FileAccess = pCcb->FileAccess;
896 // Push the request to the service
899 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
900 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
902 &pCcb->DirectoryCB->NameInformation.FileName,
903 &pObjectInfo->FileId,
904 pObjectInfo->VolumeCB->VolumeInformation.Cell,
905 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
907 sizeof( AFSFileCleanupCB),
911 if( !NT_SUCCESS( ntStatus) &&
912 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
915 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
916 AFS_TRACE_LEVEL_ERROR,
917 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
921 ntStatus = STATUS_SUCCESS;
923 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
928 ntStatus = STATUS_SUCCESS;
930 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
931 AFS_TRACE_LEVEL_VERBOSE,
932 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
936 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
938 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
940 ASSERT( pParentObjectInfo != NULL);
942 if ( pParentObjectInfo != NULL)
945 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
948 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
951 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
953 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
958 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
962 // Now that the service has the entry has deleted we need to remove it from the parent
963 // tree so another lookup on the node will fail
966 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
969 AFSRemoveNameEntry( pParentObjectInfo,
975 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
976 AFS_TRACE_LEVEL_VERBOSE,
977 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
979 &pCcb->DirectoryCB->NameInformation.FileName);
982 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
984 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
986 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
987 (ULONG)FILE_ACTION_REMOVED);
991 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
994 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
995 AFS_TRACE_LEVEL_VERBOSE,
996 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
998 &pCcb->DirectoryCB->NameInformation.FileName);
1005 // If there have been any updates to the node then push it to
1012 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1013 pParentObjectInfo != NULL)
1016 ULONG ulNotifyFilter = 0;
1018 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1020 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1022 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1024 (ULONG)ulNotifyFilter,
1025 (ULONG)FILE_ACTION_MODIFIED);
1029 // Indicate the file access mode that is being released
1032 stFileCleanup.FileAccess = pCcb->FileAccess;
1034 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1035 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1037 &pCcb->DirectoryCB->NameInformation.FileName,
1038 &pObjectInfo->FileId,
1039 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1040 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1042 sizeof( AFSFileCleanupCB),
1046 if ( NT_SUCCESS( ntStatus))
1049 if ( pParentObjectInfo != NULL)
1052 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1055 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1058 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1060 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1063 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1067 ntStatus = STATUS_SUCCESS;
1071 // Release the notification for this directory if there is one
1074 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1075 &pControlDeviceExt->Specific.Control.DirNotifyList,
1079 // Remove the share access at this time since we may not get the close for sometime on this FO.
1082 IoRemoveShareAccess( pFileObject,
1083 &pFcb->ShareAccess);
1086 // We don't need the name array after the user closes the handle on the file
1089 if( pCcb->NameArray != NULL)
1092 AFSFreeNameArray( pCcb->NameArray);
1094 pCcb->NameArray = NULL;
1098 // Decrement the open child handle count
1101 if( pParentObjectInfo != NULL)
1104 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1106 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1108 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1109 AFS_TRACE_LEVEL_VERBOSE,
1110 "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1115 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1117 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1118 AFS_TRACE_LEVEL_VERBOSE,
1119 "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1123 AFSReleaseResource( &pFcb->NPFcb->Resource);
1128 case AFS_SYMBOLIC_LINK_FCB:
1129 case AFS_MOUNT_POINT_FCB:
1130 case AFS_DFS_LINK_FCB:
1131 case AFS_INVALID_FCB:
1135 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1138 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1139 AFS_TRACE_LEVEL_VERBOSE,
1140 "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1141 &pFcb->NPFcb->Resource,
1142 PsGetCurrentThread());
1144 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1148 // Perform some final common processing
1151 ASSERT( pFcb->OpenHandleCount != 0);
1153 if( pParentObjectInfo != NULL)
1156 stFileCleanup.ParentId = pParentObjectInfo->FileId;
1159 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1161 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1164 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1166 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1169 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1171 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1174 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1177 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1179 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1182 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1185 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1187 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1192 // If the count has dropped to one and there is a pending delete
1193 // then delete the node. The final count will be decremented just
1194 // before the Fcb->NPFcb->Resource is released.
1197 if( pFcb->OpenHandleCount == 1 &&
1198 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1202 // Try to notify the service about the delete
1205 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1208 // Indicate the file access mode that is being released
1211 stFileCleanup.FileAccess = pCcb->FileAccess;
1214 // Push the request to the service
1217 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1218 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1220 &pCcb->DirectoryCB->NameInformation.FileName,
1221 &pObjectInfo->FileId,
1222 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1223 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1225 sizeof( AFSFileCleanupCB),
1229 if( !NT_SUCCESS( ntStatus) &&
1230 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1233 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1234 AFS_TRACE_LEVEL_ERROR,
1235 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1236 &pCcb->FullFileName,
1239 ntStatus = STATUS_SUCCESS;
1241 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1246 ntStatus = STATUS_SUCCESS;
1248 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1249 AFS_TRACE_LEVEL_VERBOSE,
1250 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1251 &pCcb->FullFileName,
1254 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1256 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1258 ASSERT( pParentObjectInfo != NULL);
1260 if ( pParentObjectInfo != NULL)
1263 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1266 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1269 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1271 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1275 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1279 // Now that the service has the entry has deleted we need to remove it from the parent
1280 // tree so another lookup on the node will fail
1283 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1286 AFSRemoveNameEntry( pParentObjectInfo,
1292 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1293 AFS_TRACE_LEVEL_VERBOSE,
1294 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1296 &pCcb->DirectoryCB->NameInformation.FileName);
1299 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1301 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1303 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1304 (ULONG)FILE_ACTION_REMOVED);
1309 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1312 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1313 AFS_TRACE_LEVEL_VERBOSE,
1314 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1316 &pCcb->DirectoryCB->NameInformation.FileName);
1323 // If there have been any updates to the node then push it to
1330 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1331 pParentObjectInfo != NULL)
1334 ULONG ulNotifyFilter = 0;
1336 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1338 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1340 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1342 (ULONG)ulNotifyFilter,
1343 (ULONG)FILE_ACTION_MODIFIED);
1347 // Indicate the file access mode that is being released
1350 stFileCleanup.FileAccess = pCcb->FileAccess;
1352 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1353 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1355 &pCcb->DirectoryCB->NameInformation.FileName,
1356 &pObjectInfo->FileId,
1357 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1358 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1360 sizeof( AFSFileCleanupCB),
1364 if ( NT_SUCCESS( ntStatus))
1367 if ( pParentObjectInfo != NULL)
1370 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1373 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1376 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1378 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1381 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1385 ntStatus = STATUS_SUCCESS;
1389 // Remove the share access at this time since we may not get the close for sometime on this FO.
1392 IoRemoveShareAccess( pFileObject,
1393 &pFcb->ShareAccess);
1396 // We don't need the name array after the user closes the handle on the file
1399 if( pCcb->NameArray != NULL)
1402 AFSFreeNameArray( pCcb->NameArray);
1404 pCcb->NameArray = NULL;
1408 // Decrement the open child handle count
1411 if( pParentObjectInfo != NULL)
1414 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1416 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1418 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1419 AFS_TRACE_LEVEL_VERBOSE,
1420 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1425 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1427 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1428 AFS_TRACE_LEVEL_VERBOSE,
1429 "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1433 AFSReleaseResource( &pFcb->NPFcb->Resource);
1438 case AFS_SPECIAL_SHARE_FCB:
1441 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1442 AFS_TRACE_LEVEL_VERBOSE,
1443 "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1444 &pFcb->NPFcb->Resource,
1445 PsGetCurrentThread());
1447 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1450 ASSERT( pFcb->OpenHandleCount != 0);
1453 // Decrement the open child handle count
1456 if( pParentObjectInfo != NULL &&
1457 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1460 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1462 AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1463 AFS_TRACE_LEVEL_VERBOSE,
1464 "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1469 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1471 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1472 AFS_TRACE_LEVEL_VERBOSE,
1473 "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1477 AFSReleaseResource( &pFcb->NPFcb->Resource);
1484 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1485 AFS_TRACE_LEVEL_ERROR,
1486 "AFSCleanup Processing unknown node type %d\n",
1487 pFcb->Header.NodeTypeCode);
1495 if ( pParentObjectInfo != NULL)
1498 AFSReleaseObjectInfo( &pParentObjectInfo);
1501 if( pResultCB != NULL)
1504 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1507 if( pFileObject != NULL)
1511 // Setup the fileobject flags to indicate cleanup is complete.
1514 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1518 // Complete the request
1521 AFSCompleteRequest( Irp, ntStatus);
1523 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1528 "EXCEPTION - AFSCleanup\n");
1530 AFSDumpTraceFilesFnc();