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,
58 NTSTATUS ntStatus = STATUS_SUCCESS;
59 AFSDeviceExt *pDeviceExt = NULL;
60 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
63 PFILE_OBJECT pFileObject = NULL;
64 AFSFcb *pRootFcb = NULL;
65 AFSDeviceExt *pControlDeviceExt = NULL;
66 IO_STATUS_BLOCK stIoSB;
67 AFSObjectInfoCB *pObjectInfo = NULL;
68 AFSObjectInfoCB *pParentObjectInfo = NULL;
69 AFSFileCleanupCB stFileCleanup;
70 AFSFileCleanupResultCB *pResultCB = NULL;
71 ULONG ulResultLen = 0;
72 ULONG ulNotificationFlags = 0;
78 if( AFSRDRDeviceObject == NULL)
82 // Let this through, it's a cleanup on the library control device
85 try_return( ntStatus);
88 pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
90 pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
93 // Set some initial variables to make processing easier
96 pFileObject = pIrpSp->FileObject;
98 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
100 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
104 try_return( ntStatus);
107 pObjectInfo = pFcb->ObjectInformation;
109 pRootFcb = pObjectInfo->VolumeCB->RootFcb;
111 RtlZeroMemory( &stFileCleanup,
112 sizeof( AFSFileCleanupCB));
114 stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
116 stFileCleanup.Identifier = (ULONGLONG)pFileObject;
119 // Allocate our return buffer
122 pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
124 AFS_GENERIC_MEMORY_32_TAG);
126 if( pResultCB == NULL)
129 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
132 RtlZeroMemory( pResultCB,
135 ulResultLen = PAGE_SIZE;
139 // Perform the cleanup functionality depending on the type of node it is
142 switch( pFcb->Header.NodeTypeCode)
148 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
149 AFS_TRACE_LEVEL_VERBOSE,
150 "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
151 &pFcb->NPFcb->Resource,
152 PsGetCurrentThread());
154 AFSAcquireExcl( &pFcb->NPFcb->Resource,
157 ASSERT( pFcb->OpenHandleCount != 0);
159 AFSReleaseResource( &pFcb->NPFcb->Resource);
161 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
163 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
164 AFS_TRACE_LEVEL_VERBOSE,
165 "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n",
169 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
170 &pControlDeviceExt->Specific.Control.DirNotifyList,
179 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
180 AFS_TRACE_LEVEL_VERBOSE,
181 "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n",
182 &pFcb->NPFcb->Resource,
183 PsGetCurrentThread());
185 AFSAcquireExcl( &pFcb->NPFcb->Resource,
188 ASSERT( pFcb->OpenHandleCount != 0);
191 // Decrement the open child handle count
194 if( pObjectInfo->ParentObjectInformation != NULL &&
195 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
198 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
200 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
201 AFS_TRACE_LEVEL_VERBOSE,
202 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n",
203 pObjectInfo->ParentObjectInformation,
207 AFSReleaseResource( &pFcb->NPFcb->Resource);
209 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
211 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
212 AFS_TRACE_LEVEL_VERBOSE,
213 "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n",
221 // This Fcb represents a file
228 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
231 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
232 AFS_TRACE_LEVEL_VERBOSE,
233 "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n",
234 &pFcb->NPFcb->Resource,
235 PsGetCurrentThread());
237 AFSAcquireExcl( &pFcb->NPFcb->Resource,
241 // If the handle has write permission ...
244 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) &&
245 CcIsFileCached( pIrpSp->FileObject))
251 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
256 if( !NT_SUCCESS( stIoSB.Status))
259 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
260 AFS_TRACE_LEVEL_ERROR,
261 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
263 pObjectInfo->FileId.Cell,
264 pObjectInfo->FileId.Volume,
265 pObjectInfo->FileId.Vnode,
266 pObjectInfo->FileId.Unique,
270 ntStatus = stIoSB.Status;
273 __except( EXCEPTION_EXECUTE_HANDLER)
276 ntStatus = GetExceptionCode();
281 // Uninitialize the cache map. This call is unconditional.
284 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
285 AFS_TRACE_LEVEL_VERBOSE,
286 "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n",
290 CcUninitializeCacheMap( pFileObject,
295 // Unlock all outstanding locks on the file, again, unconditionally
298 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
300 IoGetRequestorProcess( Irp),
304 // Tell the service to unlock all on the file
307 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
310 // Perform some final common processing
313 ASSERT( pFcb->OpenHandleCount != 0);
315 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
318 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
321 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
323 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
326 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
328 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
330 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
333 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
335 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
338 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
341 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
343 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
346 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
349 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
351 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
354 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
357 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
359 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
363 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
366 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
370 // If the count has dropped to one and there is a pending delete
371 // then delete the node. The final count will be decremented just
372 // before the Fcb->NPFcb->Resource is released.
375 if( pFcb->OpenHandleCount == 1 &&
376 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
380 // Stop anything possibly in process
383 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
384 AFS_TRACE_LEVEL_VERBOSE,
385 "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n",
386 &pFcb->NPFcb->Specific.File.ExtentsResource,
387 PsGetCurrentThread());
389 AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource,
392 pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
394 KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete,
399 // Before telling the server about the deleted file, tear down all extents for
403 AFSTearDownFcbExtents( pFcb,
406 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
407 AFS_TRACE_LEVEL_VERBOSE,
408 "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n",
409 &pFcb->NPFcb->Specific.File.ExtentsResource,
410 PsGetCurrentThread());
412 AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource);
414 ntStatus = STATUS_SUCCESS;
416 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
419 // Indicate the file access mode that is being released
422 stFileCleanup.FileAccess = pCcb->FileAccess;
425 // Push the request to the service
428 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
429 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
431 &pCcb->DirectoryCB->NameInformation.FileName,
432 &pObjectInfo->FileId,
434 sizeof( AFSFileCleanupCB),
438 if( !NT_SUCCESS( ntStatus) &&
439 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
442 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
443 AFS_TRACE_LEVEL_ERROR,
444 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
448 ntStatus = STATUS_SUCCESS;
450 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
455 ntStatus = STATUS_SUCCESS;
457 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
458 AFS_TRACE_LEVEL_VERBOSE,
459 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
463 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
465 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
467 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
469 ASSERT( pParentObjectInfo != NULL);
471 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
474 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
477 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
479 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
484 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
488 // Now that the service has the entry has deleted we need to remove it from the parent
489 // tree so another lookup on the node will fail
492 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
495 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
496 AFS_TRACE_LEVEL_VERBOSE,
497 "AFSCleanup DE %p for %wZ removing entry\n",
499 &pCcb->DirectoryCB->NameInformation.FileName);
501 AFSRemoveNameEntry( pParentObjectInfo,
507 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
508 AFS_TRACE_LEVEL_VERBOSE,
509 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
511 &pCcb->DirectoryCB->NameInformation.FileName);
514 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
516 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
518 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
519 (ULONG)FILE_ACTION_REMOVED);
526 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
529 ULONG ulNotifyFilter = 0;
531 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
533 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
535 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
537 (ULONG)ulNotifyFilter,
538 (ULONG)FILE_ACTION_MODIFIED);
542 // Attempt to flush any dirty extents to the server. This may be a little
543 // aggressive, to flush whenever the handle is closed, but it ensures
547 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) &&
548 pFcb->Specific.File.ExtentsDirtyCount != 0)
551 AFSFlushExtents( pFcb,
554 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
557 if( pFcb->OpenHandleCount == 1)
561 // Wait for any outstanding queued flushes to complete
564 AFSWaitOnQueuedFlushes( pFcb);
566 AFSTearDownFcbExtents( pFcb,
571 // Indicate the file access mode that is being released
574 stFileCleanup.FileAccess = pCcb->FileAccess;
577 // Remove the share access at this time since we may not get the close for sometime on this FO.
580 IoRemoveShareAccess( pFileObject,
585 // We don't need the name array after the user closes the handle on the file
588 if( pCcb->NameArray != NULL)
591 AFSFreeNameArray( pCcb->NameArray);
593 pCcb->NameArray = NULL;
597 // Release the Fcb Resource across the call to the service
598 // which may block for quite a while if flushing of the
602 AFSReleaseResource( &pFcb->NPFcb->Resource);
605 // Push the request to the service
608 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
609 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
611 &pCcb->DirectoryCB->NameInformation.FileName,
612 &pObjectInfo->FileId,
614 sizeof( AFSFileCleanupCB),
619 // Regain exclusive access to the Fcb
622 AFSAcquireExcl( &pFcb->NPFcb->Resource,
625 if ( NT_SUCCESS( ntStatus))
628 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
630 if ( pParentObjectInfo != NULL)
633 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
636 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
639 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
641 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
644 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
648 ntStatus = STATUS_SUCCESS;
652 // Decrement the open child handle count
655 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
657 if( pParentObjectInfo != NULL)
660 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
662 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
664 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
665 AFS_TRACE_LEVEL_VERBOSE,
666 "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
672 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
674 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
675 AFS_TRACE_LEVEL_VERBOSE,
676 "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n",
680 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
683 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
686 AFSObjectInfoIncrement( pObjectInfo);
688 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
690 AFSReleaseResource( &pFcb->NPFcb->Resource);
692 AFSPerformObjectInvalidate( pObjectInfo,
693 AFS_INVALIDATE_DATA_VERSION);
698 AFSReleaseResource( &pFcb->NPFcb->Resource);
705 // Root or directory node
712 // Set the root Fcb to this node
718 // Fall through to below
722 case AFS_DIRECTORY_FCB:
726 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
729 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
730 AFS_TRACE_LEVEL_VERBOSE,
731 "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
732 &pFcb->NPFcb->Resource,
733 PsGetCurrentThread());
735 AFSAcquireExcl( &pFcb->NPFcb->Resource,
739 // Perform some final common processing
742 ASSERT( pFcb->OpenHandleCount != 0);
744 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
747 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
750 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
752 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
755 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
757 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
760 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
762 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
765 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
768 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
770 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
773 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
776 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
778 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
783 // If the count has dropped to one and there is a pending delete
784 // then delete the node. The final count will be decremented just
785 // before the Fcb->NPFcb->Resource is released.
788 if( pFcb->OpenHandleCount == 1 &&
789 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
793 // Try to notify the service about the delete
796 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
799 // Indicate the file access mode that is being released
802 stFileCleanup.FileAccess = pCcb->FileAccess;
805 // Push the request to the service
808 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
809 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
811 &pCcb->DirectoryCB->NameInformation.FileName,
812 &pObjectInfo->FileId,
814 sizeof( AFSFileCleanupCB),
818 if( !NT_SUCCESS( ntStatus) &&
819 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
822 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
823 AFS_TRACE_LEVEL_ERROR,
824 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
828 ntStatus = STATUS_SUCCESS;
830 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
835 ntStatus = STATUS_SUCCESS;
837 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
838 AFS_TRACE_LEVEL_VERBOSE,
839 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
843 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
845 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
847 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
849 ASSERT( pParentObjectInfo != NULL);
851 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
854 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
857 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
859 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
864 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
868 // Now that the service has the entry has deleted we need to remove it from the parent
869 // tree so another lookup on the node will fail
872 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
875 AFSRemoveNameEntry( pParentObjectInfo,
881 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
882 AFS_TRACE_LEVEL_VERBOSE,
883 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
885 &pCcb->DirectoryCB->NameInformation.FileName);
888 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
890 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
892 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
893 (ULONG)FILE_ACTION_REMOVED);
899 // If there have been any updates to the node then push it to
906 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
909 ULONG ulNotifyFilter = 0;
911 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
913 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
915 if( pParentObjectInfo != NULL)
918 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
920 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
922 (ULONG)ulNotifyFilter,
923 (ULONG)FILE_ACTION_MODIFIED);
928 // Indicate the file access mode that is being released
931 stFileCleanup.FileAccess = pCcb->FileAccess;
933 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
934 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
936 &pCcb->DirectoryCB->NameInformation.FileName,
937 &pObjectInfo->FileId,
939 sizeof( AFSFileCleanupCB),
943 if ( NT_SUCCESS( ntStatus))
946 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
948 if ( pParentObjectInfo != NULL)
951 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
954 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
957 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
959 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
962 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
966 ntStatus = STATUS_SUCCESS;
970 // Release the notification for this directory if there is one
973 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
974 &pControlDeviceExt->Specific.Control.DirNotifyList,
978 // Remove the share access at this time since we may not get the close for sometime on this FO.
981 IoRemoveShareAccess( pFileObject,
985 // We don't need the name array after the user closes the handle on the file
988 if( pCcb->NameArray != NULL)
991 AFSFreeNameArray( pCcb->NameArray);
993 pCcb->NameArray = NULL;
997 // Decrement the open child handle count
1000 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1002 if( pParentObjectInfo != NULL)
1005 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1007 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1009 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1010 AFS_TRACE_LEVEL_VERBOSE,
1011 "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1016 AFSReleaseResource( &pFcb->NPFcb->Resource);
1018 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1020 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1021 AFS_TRACE_LEVEL_VERBOSE,
1022 "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
1029 case AFS_SYMBOLIC_LINK_FCB:
1030 case AFS_MOUNT_POINT_FCB:
1031 case AFS_DFS_LINK_FCB:
1032 case AFS_INVALID_FCB:
1036 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
1039 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1040 AFS_TRACE_LEVEL_VERBOSE,
1041 "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
1042 &pFcb->NPFcb->Resource,
1043 PsGetCurrentThread());
1045 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1049 // Perform some final common processing
1052 ASSERT( pFcb->OpenHandleCount != 0);
1054 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
1057 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
1060 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1062 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1065 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1067 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1070 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1072 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1075 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1078 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1080 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1083 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1086 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1088 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1093 // If the count has dropped to one and there is a pending delete
1094 // then delete the node. The final count will be decremented just
1095 // before the Fcb->NPFcb->Resource is released.
1098 if( pFcb->OpenHandleCount == 1 &&
1099 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1103 // Try to notify the service about the delete
1106 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1109 // Indicate the file access mode that is being released
1112 stFileCleanup.FileAccess = pCcb->FileAccess;
1115 // Push the request to the service
1118 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1119 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1121 &pCcb->DirectoryCB->NameInformation.FileName,
1122 &pObjectInfo->FileId,
1124 sizeof( AFSFileCleanupCB),
1128 if( !NT_SUCCESS( ntStatus) &&
1129 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1132 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1133 AFS_TRACE_LEVEL_ERROR,
1134 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1135 &pCcb->FullFileName,
1138 ntStatus = STATUS_SUCCESS;
1140 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1145 ntStatus = STATUS_SUCCESS;
1147 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1148 AFS_TRACE_LEVEL_VERBOSE,
1149 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1150 &pCcb->FullFileName,
1153 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1155 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1157 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1159 ASSERT( pParentObjectInfo != NULL);
1161 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1164 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1167 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1169 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1173 pParentObjectInfo->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1177 // Now that the service has the entry has deleted we need to remove it from the parent
1178 // tree so another lookup on the node will fail
1181 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1184 AFSRemoveNameEntry( pParentObjectInfo,
1190 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1191 AFS_TRACE_LEVEL_VERBOSE,
1192 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1194 &pCcb->DirectoryCB->NameInformation.FileName);
1197 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1199 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1201 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1202 (ULONG)FILE_ACTION_REMOVED);
1208 // If there have been any updates to the node then push it to
1215 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1218 ULONG ulNotifyFilter = 0;
1220 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1222 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1224 if( pParentObjectInfo != NULL)
1227 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1229 AFSFsRtlNotifyFullReportChange( pParentObjectInfo,
1231 (ULONG)ulNotifyFilter,
1232 (ULONG)FILE_ACTION_MODIFIED);
1237 // Indicate the file access mode that is being released
1240 stFileCleanup.FileAccess = pCcb->FileAccess;
1242 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1243 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1245 &pCcb->DirectoryCB->NameInformation.FileName,
1246 &pObjectInfo->FileId,
1248 sizeof( AFSFileCleanupCB),
1252 if ( NT_SUCCESS( ntStatus))
1255 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1257 if ( pParentObjectInfo != NULL)
1260 AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1263 if ( pParentObjectInfo->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1266 SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
1268 pParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1;
1271 AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1275 ntStatus = STATUS_SUCCESS;
1279 // Remove the share access at this time since we may not get the close for sometime on this FO.
1282 IoRemoveShareAccess( pFileObject,
1283 &pFcb->ShareAccess);
1286 // We don't need the name array after the user closes the handle on the file
1289 if( pCcb->NameArray != NULL)
1292 AFSFreeNameArray( pCcb->NameArray);
1294 pCcb->NameArray = NULL;
1298 // Decrement the open child handle count
1301 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1303 if( pParentObjectInfo != NULL)
1306 ASSERT( pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0);
1308 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1310 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1311 AFS_TRACE_LEVEL_VERBOSE,
1312 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1317 AFSReleaseResource( &pFcb->NPFcb->Resource);
1319 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1321 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1322 AFS_TRACE_LEVEL_VERBOSE,
1323 "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
1330 case AFS_SPECIAL_SHARE_FCB:
1333 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1334 AFS_TRACE_LEVEL_VERBOSE,
1335 "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1336 &pFcb->NPFcb->Resource,
1337 PsGetCurrentThread());
1339 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1342 ASSERT( pFcb->OpenHandleCount != 0);
1345 // Decrement the open child handle count
1348 pParentObjectInfo = pObjectInfo->ParentObjectInformation;
1350 if( pParentObjectInfo != NULL &&
1351 pParentObjectInfo->Specific.Directory.ChildOpenHandleCount > 0)
1354 lCount = InterlockedDecrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount);
1356 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1357 AFS_TRACE_LEVEL_VERBOSE,
1358 "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1363 AFSReleaseResource( &pFcb->NPFcb->Resource);
1365 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1367 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1368 AFS_TRACE_LEVEL_VERBOSE,
1369 "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1378 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1379 AFS_TRACE_LEVEL_WARNING,
1380 "AFSCleanup Processing unknown node type %d\n",
1381 pFcb->Header.NodeTypeCode);
1389 if( pResultCB != NULL)
1392 AFSExFreePoolWithTag( pResultCB, AFS_GENERIC_MEMORY_32_TAG);
1395 if( pFileObject != NULL)
1399 // Setup the fileobject flags to indicate cleanup is complete.
1402 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1406 // Complete the request
1409 AFSCompleteRequest( Irp, ntStatus);
1411 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
1416 "EXCEPTION - AFSCleanup\n");
1418 AFSDumpTraceFilesFnc();