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);
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);
325 // Uninitialize the cache map. This call is unconditional.
328 AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING,
329 AFS_TRACE_LEVEL_VERBOSE,
330 "AFSCleanup Tearing down cache map for Fcb %p FileObject %p\n",
334 CcUninitializeCacheMap( pFileObject,
339 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
340 AFS_TRACE_LEVEL_VERBOSE,
341 "AFSCleanup Releasing Fcb SectionObject lock %p EXCL %08lX\n",
342 &pFcb->NPFcb->SectionObjectResource,
343 PsGetCurrentThread()));
345 AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource);
347 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
348 AFS_TRACE_LEVEL_VERBOSE,
349 "AFSCleanup Acquiring Fcb lock %p EXCL %08lX\n",
350 &pFcb->NPFcb->Resource,
351 PsGetCurrentThread()));
353 AFSAcquireExcl( &pFcb->NPFcb->Resource,
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;
385 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
388 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
390 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
392 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
395 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
397 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
400 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
403 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
405 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
408 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
411 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
413 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
416 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
419 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
421 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
425 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
428 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
432 // If the count has dropped to one and there is a pending delete
433 // then delete the node. The final count will be decremented just
434 // before the Fcb->NPFcb->Resource is released.
437 if( pFcb->OpenHandleCount == 1 &&
438 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
441 ntStatus = STATUS_SUCCESS;
443 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
446 // Indicate the file access mode that is being released
449 stFileCleanup.FileAccess = pCcb->FileAccess;
452 // Push the request to the service
455 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
456 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
458 &pCcb->DirectoryCB->NameInformation.FileName,
459 &pObjectInfo->FileId,
460 pObjectInfo->VolumeCB->VolumeInformation.Cell,
461 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
463 sizeof( AFSFileCleanupCB),
467 if( !NT_SUCCESS( ntStatus) &&
468 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
471 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
472 AFS_TRACE_LEVEL_ERROR,
473 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
477 ntStatus = STATUS_SUCCESS;
479 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
484 ntStatus = STATUS_SUCCESS;
486 if ( --pObjectInfo->Links < 1)
490 // Stop anything possibly in process
493 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
494 AFS_TRACE_LEVEL_VERBOSE,
495 "AFSCleanup Acquiring Fcb extents lock %p EXCL %08lX\n",
496 &pFcb->NPFcb->Specific.File.ExtentsResource,
497 PsGetCurrentThread()));
499 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
502 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
504 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
509 // The file has been deleted since the Link count is zero
512 AFSDeleteFcbExtents( pFcb);
514 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
515 AFS_TRACE_LEVEL_VERBOSE,
516 "AFSCleanup Releasing Fcb extents lock %p EXCL %08lX\n",
517 &pFcb->NPFcb->Specific.File.ExtentsResource,
518 PsGetCurrentThread()));
520 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
523 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
524 AFS_TRACE_LEVEL_VERBOSE,
525 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
529 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
531 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
533 ASSERT( pParentObjectInfo != NULL);
535 if ( pParentObjectInfo != NULL)
538 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
541 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
544 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
546 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
551 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
555 // Now that the service has the entry has deleted we need to remove it from the parent
556 // tree so another lookup on the node will fail
559 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
562 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
563 AFS_TRACE_LEVEL_VERBOSE,
564 "AFSCleanup DE %p for %wZ removing entry\n",
566 &pCcb->DirectoryCB->NameInformation.FileName));
568 AFSRemoveNameEntry( pParentObjectInfo,
574 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
575 AFS_TRACE_LEVEL_VERBOSE,
576 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
578 &pCcb->DirectoryCB->NameInformation.FileName));
581 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
583 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
585 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
586 (ULONG)FILE_ACTION_REMOVED);
590 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
593 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
594 AFS_TRACE_LEVEL_VERBOSE,
595 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
597 &pCcb->DirectoryCB->NameInformation.FileName));
605 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
606 pParentObjectInfo != NULL)
609 ULONG ulNotifyFilter = 0;
611 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
613 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
615 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
617 (ULONG)ulNotifyFilter,
618 (ULONG)FILE_ACTION_MODIFIED);
623 // Whenever a handle with write access or the last handle is closed
624 // notify the service to FSync the file. If the redirector is holding
625 // dirty extents, flush them to the service. This is a bit aggressive
626 // but it ensures cache coherency.
629 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) || (pFcb->OpenHandleCount == 1))
632 if ( pFcb->Specific.File.ExtentsDirtyCount != 0)
635 AFSFlushExtents( pFcb,
639 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
642 if( pFcb->OpenHandleCount == 1)
646 // Wait for any outstanding queued flushes to complete
649 AFSWaitOnQueuedFlushes( pFcb);
651 AFSTearDownFcbExtents( pFcb,
656 // Indicate the file access mode that is being released
659 stFileCleanup.FileAccess = pCcb->FileAccess;
662 // Remove the share access at this time since we may not get the close for sometime on this FO.
665 IoRemoveShareAccess( pFileObject,
670 // We don't need the name array after the user closes the handle on the file
673 if( pCcb->NameArray != NULL)
676 AFSFreeNameArray( pCcb->NameArray);
678 pCcb->NameArray = NULL;
682 // Release the Fcb Resource across the call to the service
683 // which may block for quite a while if flushing of the
687 AFSReleaseResource( &pFcb->NPFcb->Resource);
690 // Push the request to the service
693 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
694 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
696 &pCcb->DirectoryCB->NameInformation.FileName,
697 &pObjectInfo->FileId,
698 pObjectInfo->VolumeCB->VolumeInformation.Cell,
699 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
701 sizeof( AFSFileCleanupCB),
706 // Regain exclusive access to the Fcb
709 AFSAcquireExcl( &pFcb->NPFcb->Resource,
712 if ( NT_SUCCESS( ntStatus))
715 if ( pParentObjectInfo != NULL)
718 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
721 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
724 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
726 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
729 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
733 ntStatus = STATUS_SUCCESS;
737 // Decrement the open child handle count
740 if( pParentObjectInfo != NULL)
743 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
745 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
747 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
748 AFS_TRACE_LEVEL_VERBOSE,
749 "AFSCleanup (File) Decrement child open handle count on Parent object %p Cnt %d\n",
755 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
757 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
758 AFS_TRACE_LEVEL_VERBOSE,
759 "AFSCleanup (File) Decrement handle count on Fcb %p Cnt %d\n",
763 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
766 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
769 lCount = AFSObjectInfoIncrement( pObjectInfo,
770 AFS_OBJECT_REFERENCE_INVALIDATION);
772 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
773 AFS_TRACE_LEVEL_VERBOSE,
774 "AFSCleanup Setting Purge on Close Increment count on object %p Cnt %d\n",
778 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
780 AFSReleaseResource( &pFcb->NPFcb->Resource);
782 AFSPerformObjectInvalidate( pObjectInfo,
783 AFS_INVALIDATE_DATA_VERSION);
788 AFSReleaseResource( &pFcb->NPFcb->Resource);
795 // Root or directory node
802 // Set the root Fcb to this node
808 // Fall through to below
812 case AFS_DIRECTORY_FCB:
816 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
819 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
820 AFS_TRACE_LEVEL_VERBOSE,
821 "AFSCleanup Acquiring Dcb lock %p EXCL %08lX\n",
822 &pFcb->NPFcb->Resource,
823 PsGetCurrentThread()));
825 AFSAcquireExcl( &pFcb->NPFcb->Resource,
829 // Perform some final common processing
832 ASSERT( pFcb->OpenHandleCount != 0);
834 if( pParentObjectInfo != NULL)
837 stFileCleanup.ParentId = pParentObjectInfo->FileId;
840 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
842 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
845 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
847 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
850 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
852 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
855 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
858 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
860 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
863 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
866 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
868 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
873 // If the count has dropped to one and there is a pending delete
874 // then delete the node. The final count will be decremented just
875 // before the Fcb->NPFcb->Resource is released.
878 if( pFcb->OpenHandleCount == 1 &&
879 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
883 // Try to notify the service about the delete
886 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
889 // Indicate the file access mode that is being released
892 stFileCleanup.FileAccess = pCcb->FileAccess;
895 // Push the request to the service
898 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
899 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
901 &pCcb->DirectoryCB->NameInformation.FileName,
902 &pObjectInfo->FileId,
903 pObjectInfo->VolumeCB->VolumeInformation.Cell,
904 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
906 sizeof( AFSFileCleanupCB),
910 if( !NT_SUCCESS( ntStatus) &&
911 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
914 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
915 AFS_TRACE_LEVEL_ERROR,
916 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
920 ntStatus = STATUS_SUCCESS;
922 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
927 ntStatus = STATUS_SUCCESS;
929 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
930 AFS_TRACE_LEVEL_VERBOSE,
931 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
935 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
937 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
939 ASSERT( pParentObjectInfo != NULL);
941 if ( pParentObjectInfo != NULL)
944 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
947 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
950 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
952 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
957 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
961 // Now that the service has the entry has deleted we need to remove it from the parent
962 // tree so another lookup on the node will fail
965 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
968 AFSRemoveNameEntry( pParentObjectInfo,
974 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
975 AFS_TRACE_LEVEL_VERBOSE,
976 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
978 &pCcb->DirectoryCB->NameInformation.FileName));
981 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
983 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
985 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
986 (ULONG)FILE_ACTION_REMOVED);
990 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
993 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
994 AFS_TRACE_LEVEL_VERBOSE,
995 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
997 &pCcb->DirectoryCB->NameInformation.FileName));
1004 // If there have been any updates to the node then push it to
1011 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1012 pParentObjectInfo != NULL)
1015 ULONG ulNotifyFilter = 0;
1017 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1019 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1021 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1023 (ULONG)ulNotifyFilter,
1024 (ULONG)FILE_ACTION_MODIFIED);
1028 // Indicate the file access mode that is being released
1031 stFileCleanup.FileAccess = pCcb->FileAccess;
1033 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1034 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1036 &pCcb->DirectoryCB->NameInformation.FileName,
1037 &pObjectInfo->FileId,
1038 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1039 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1041 sizeof( AFSFileCleanupCB),
1045 if ( NT_SUCCESS( ntStatus))
1048 if ( pParentObjectInfo != NULL)
1051 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1054 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1057 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1059 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1062 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1066 ntStatus = STATUS_SUCCESS;
1070 // Release the notification for this directory if there is one
1073 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
1074 &pControlDeviceExt->Specific.Control.DirNotifyList,
1078 // Remove the share access at this time since we may not get the close for sometime on this FO.
1081 IoRemoveShareAccess( pFileObject,
1082 &pFcb->ShareAccess);
1085 // We don't need the name array after the user closes the handle on the file
1088 if( pCcb->NameArray != NULL)
1091 AFSFreeNameArray( pCcb->NameArray);
1093 pCcb->NameArray = NULL;
1097 // Decrement the open child handle count
1100 if( pParentObjectInfo != NULL)
1103 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1105 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1107 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1108 AFS_TRACE_LEVEL_VERBOSE,
1109 "AFSCleanup (Dir) Decrement child open handle count on Parent object %p Cnt %d\n",
1114 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1116 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1117 AFS_TRACE_LEVEL_VERBOSE,
1118 "AFSCleanup (Dir) Decrement handle count on Fcb %p Cnt %d\n",
1122 AFSReleaseResource( &pFcb->NPFcb->Resource);
1127 case AFS_SYMBOLIC_LINK_FCB:
1128 case AFS_MOUNT_POINT_FCB:
1129 case AFS_DFS_LINK_FCB:
1130 case AFS_INVALID_FCB:
1134 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1137 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1138 AFS_TRACE_LEVEL_VERBOSE,
1139 "AFSCleanup (MP/SL) Acquiring Dcb lock %p EXCL %08lX\n",
1140 &pFcb->NPFcb->Resource,
1141 PsGetCurrentThread()));
1143 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1147 // Perform some final common processing
1150 ASSERT( pFcb->OpenHandleCount != 0);
1152 if( pParentObjectInfo != NULL)
1155 stFileCleanup.ParentId = pParentObjectInfo->FileId;
1158 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1160 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1163 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1165 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1168 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1170 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1173 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1176 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1178 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1181 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1184 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1186 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1191 // If the count has dropped to one and there is a pending delete
1192 // then delete the node. The final count will be decremented just
1193 // before the Fcb->NPFcb->Resource is released.
1196 if( pFcb->OpenHandleCount == 1 &&
1197 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1201 // Try to notify the service about the delete
1204 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1207 // Indicate the file access mode that is being released
1210 stFileCleanup.FileAccess = pCcb->FileAccess;
1213 // Push the request to the service
1216 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1217 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1219 &pCcb->DirectoryCB->NameInformation.FileName,
1220 &pObjectInfo->FileId,
1221 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1222 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1224 sizeof( AFSFileCleanupCB),
1228 if( !NT_SUCCESS( ntStatus) &&
1229 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1232 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1233 AFS_TRACE_LEVEL_ERROR,
1234 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1235 &pCcb->FullFileName,
1238 ntStatus = STATUS_SUCCESS;
1240 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1245 ntStatus = STATUS_SUCCESS;
1247 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1248 AFS_TRACE_LEVEL_VERBOSE,
1249 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1250 &pCcb->FullFileName,
1251 pCcb->DirectoryCB));
1253 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1255 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1257 ASSERT( pParentObjectInfo != NULL);
1259 if ( pParentObjectInfo != NULL)
1262 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1265 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1268 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1270 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1274 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1278 // Now that the service has the entry has deleted we need to remove it from the parent
1279 // tree so another lookup on the node will fail
1282 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1285 AFSRemoveNameEntry( pParentObjectInfo,
1291 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1292 AFS_TRACE_LEVEL_VERBOSE,
1293 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1295 &pCcb->DirectoryCB->NameInformation.FileName));
1298 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1300 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1302 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1303 (ULONG)FILE_ACTION_REMOVED);
1308 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1311 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1312 AFS_TRACE_LEVEL_VERBOSE,
1313 "AFSCleanup DE %p for %wZ NOT removing entry due to pParentObjectInfo == NULL\n",
1315 &pCcb->DirectoryCB->NameInformation.FileName));
1322 // If there have been any updates to the node then push it to
1329 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED) &&
1330 pParentObjectInfo != NULL)
1333 ULONG ulNotifyFilter = 0;
1335 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1337 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1339 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1341 (ULONG)ulNotifyFilter,
1342 (ULONG)FILE_ACTION_MODIFIED);
1346 // Indicate the file access mode that is being released
1349 stFileCleanup.FileAccess = pCcb->FileAccess;
1351 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1352 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1354 &pCcb->DirectoryCB->NameInformation.FileName,
1355 &pObjectInfo->FileId,
1356 pObjectInfo->VolumeCB->VolumeInformation.Cell,
1357 pObjectInfo->VolumeCB->VolumeInformation.CellLength,
1359 sizeof( AFSFileCleanupCB),
1363 if ( NT_SUCCESS( ntStatus))
1366 if ( pParentObjectInfo != NULL)
1369 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1372 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1375 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1377 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1380 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1384 ntStatus = STATUS_SUCCESS;
1388 // Remove the share access at this time since we may not get the close for sometime on this FO.
1391 IoRemoveShareAccess( pFileObject,
1392 &pFcb->ShareAccess);
1395 // We don't need the name array after the user closes the handle on the file
1398 if( pCcb->NameArray != NULL)
1401 AFSFreeNameArray( pCcb->NameArray);
1403 pCcb->NameArray = NULL;
1407 // Decrement the open child handle count
1410 if( pParentObjectInfo != NULL)
1413 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1415 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1417 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1418 AFS_TRACE_LEVEL_VERBOSE,
1419 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %p Cnt %d\n",
1424 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1426 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1427 AFS_TRACE_LEVEL_VERBOSE,
1428 "AFSCleanup (MP/SL) Decrement handle count on Fcb %p Cnt %d\n",
1432 AFSReleaseResource( &pFcb->NPFcb->Resource);
1437 case AFS_SPECIAL_SHARE_FCB:
1440 AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING,
1441 AFS_TRACE_LEVEL_VERBOSE,
1442 "AFSCleanup Acquiring SPECIAL SHARE lock %p EXCL %08lX\n",
1443 &pFcb->NPFcb->Resource,
1444 PsGetCurrentThread()));
1446 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1449 ASSERT( pFcb->OpenHandleCount != 0);
1452 // Decrement the open child handle count
1455 if( pParentObjectInfo != NULL &&
1456 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1459 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1461 AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
1462 AFS_TRACE_LEVEL_VERBOSE,
1463 "AFSCleanup (Share) Decrement child open handle count on Parent object %p Cnt %d\n",
1468 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1470 AFSDbgTrace(( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1471 AFS_TRACE_LEVEL_VERBOSE,
1472 "AFSCleanup (Share) Decrement handle count on Fcb %p Cnt %d\n",
1476 AFSReleaseResource( &pFcb->NPFcb->Resource);
1483 AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
1484 AFS_TRACE_LEVEL_ERROR,
1485 "AFSCleanup Processing unknown node type %d\n",
1486 pFcb->Header.NodeTypeCode));
1494 if ( pParentObjectInfo != NULL)
1497 AFSReleaseObjectInfo( &pParentObjectInfo);
1500 if( pResultCB != NULL)
1503 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1506 if( pFileObject != NULL)
1510 // Setup the fileobject flags to indicate cleanup is complete.
1513 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1517 // Complete the request
1520 AFSCompleteRequest( Irp, ntStatus);
1522 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1527 "EXCEPTION - AFSCleanup\n"));
1529 AFSDumpTraceFilesFnc();