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 AFSFileCleanupCB stFileCleanup;
69 AFSFileCleanupResultCB *pResultCB = NULL;
70 ULONG ulResultLen = 0;
71 ULONG ulNotificationFlags = 0;
77 if( AFSRDRDeviceObject == NULL)
81 // Let this through, it's a cleanup on the library control device
84 try_return( ntStatus);
87 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 pRootFcb = pObjectInfo->VolumeCB->RootFcb;
109 RtlZeroMemory( &stFileCleanup,
110 sizeof( AFSFileCleanupCB));
112 stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId();
114 stFileCleanup.Identifier = (ULONGLONG)pFileObject;
117 // Allocate our return buffer
120 pResultCB = (AFSFileCleanupResultCB *)AFSExAllocatePoolWithTag( PagedPool,
122 AFS_GENERIC_MEMORY_32_TAG);
124 if( pResultCB == NULL)
127 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
130 RtlZeroMemory( pResultCB,
133 ulResultLen = PAGE_SIZE;
137 // Perform the cleanup functionality depending on the type of node it is
140 switch( pFcb->Header.NodeTypeCode)
146 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
147 AFS_TRACE_LEVEL_VERBOSE,
148 "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
149 &pFcb->NPFcb->Resource,
150 PsGetCurrentThread());
152 AFSAcquireExcl( &pFcb->NPFcb->Resource,
155 ASSERT( pFcb->OpenHandleCount != 0);
157 AFSReleaseResource( &pFcb->NPFcb->Resource);
159 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
161 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
162 AFS_TRACE_LEVEL_VERBOSE,
163 "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n",
167 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
168 &pControlDeviceExt->Specific.Control.DirNotifyList,
177 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
178 AFS_TRACE_LEVEL_VERBOSE,
179 "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n",
180 &pFcb->NPFcb->Resource,
181 PsGetCurrentThread());
183 AFSAcquireExcl( &pFcb->NPFcb->Resource,
186 ASSERT( pFcb->OpenHandleCount != 0);
189 // Decrement the open child handle count
192 if( pObjectInfo->ParentObjectInformation != NULL &&
193 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
196 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
198 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
199 AFS_TRACE_LEVEL_VERBOSE,
200 "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n",
201 pObjectInfo->ParentObjectInformation,
205 AFSReleaseResource( &pFcb->NPFcb->Resource);
207 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
209 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
210 AFS_TRACE_LEVEL_VERBOSE,
211 "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n",
219 // This Fcb represents a file
226 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
229 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
230 AFS_TRACE_LEVEL_VERBOSE,
231 "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n",
232 &pFcb->NPFcb->Resource,
233 PsGetCurrentThread());
235 AFSAcquireExcl( &pFcb->NPFcb->Resource,
239 // If the handle has write permission ...
242 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) &&
243 CcIsFileCached( pIrpSp->FileObject))
249 CcFlushCache( &pFcb->NPFcb->SectionObjectPointers,
254 if( !NT_SUCCESS( stIoSB.Status))
257 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
258 AFS_TRACE_LEVEL_ERROR,
259 "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n",
261 pObjectInfo->FileId.Cell,
262 pObjectInfo->FileId.Volume,
263 pObjectInfo->FileId.Vnode,
264 pObjectInfo->FileId.Unique,
268 ntStatus = stIoSB.Status;
271 __except( EXCEPTION_EXECUTE_HANDLER)
274 ntStatus = GetExceptionCode();
279 // Uninitialize the cache map. This call is unconditional.
282 AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
283 AFS_TRACE_LEVEL_VERBOSE,
284 "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n",
288 CcUninitializeCacheMap( pFileObject,
293 // Unlock all outstanding locks on the file, again, unconditionally
296 (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock,
298 IoGetRequestorProcess( Irp),
302 // Tell the service to unlock all on the file
305 ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL;
308 // Perform some final common processing
311 ASSERT( pFcb->OpenHandleCount != 0);
313 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
316 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
319 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
321 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
324 stFileCleanup.AllocationSize = pObjectInfo->EndOfFile;
326 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
328 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
331 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
333 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
336 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
339 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
341 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
344 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
347 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
349 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
352 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME))
355 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
357 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME);
361 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME))
364 stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime;
368 // If the count has dropped to one and there is a pending delete
369 // then delete the node. The final count will be decremented just
370 // before the Fcb->NPFcb->Resource is released.
373 if( pFcb->OpenHandleCount == 1 &&
374 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
378 // Stop anything possibly in process
381 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
382 AFS_TRACE_LEVEL_VERBOSE,
383 "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n",
384 &pFcb->NPFcb->Specific.File.ExtentsResource,
385 PsGetCurrentThread());
387 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
390 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
392 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
396 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
397 AFS_TRACE_LEVEL_VERBOSE,
398 "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n",
399 &pFcb->NPFcb->Specific.File.ExtentsResource,
400 PsGetCurrentThread());
402 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
405 // Before telling the server about the deleted file, tear down all extents for
409 AFSTearDownFcbExtents( pFcb,
412 ntStatus = STATUS_SUCCESS;
414 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
417 // Indicate the file access mode that is being released
420 stFileCleanup.FileAccess = pCcb->FileAccess;
423 // Push the request to the service
426 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
427 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
429 &pCcb->DirectoryCB->NameInformation.FileName,
430 &pObjectInfo->FileId,
432 sizeof( AFSFileCleanupCB),
436 if( !NT_SUCCESS( ntStatus) &&
437 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
440 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
441 AFS_TRACE_LEVEL_ERROR,
442 "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n",
446 ntStatus = STATUS_SUCCESS;
448 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
453 ntStatus = STATUS_SUCCESS;
455 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
456 AFS_TRACE_LEVEL_VERBOSE,
457 "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n",
461 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
463 ASSERT( pObjectInfo->ParentObjectInformation != NULL);
465 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
468 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
471 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
473 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
478 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
482 // Now that the service has the entry has deleted we need to remove it from the parent
483 // tree so another lookup on the node will fail
486 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
489 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
490 AFS_TRACE_LEVEL_VERBOSE,
491 "AFSCleanup DE %p for %wZ removing entry\n",
493 &pCcb->DirectoryCB->NameInformation.FileName);
495 AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
501 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
502 AFS_TRACE_LEVEL_VERBOSE,
503 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
505 &pCcb->DirectoryCB->NameInformation.FileName);
508 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
510 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
512 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
513 (ULONG)FILE_ACTION_REMOVED);
520 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
523 ULONG ulNotifyFilter = 0;
525 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
527 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
529 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
531 (ULONG)ulNotifyFilter,
532 (ULONG)FILE_ACTION_MODIFIED);
536 // Attempt to flush any dirty extents to the server. This may be a little
537 // aggressive, to flush whenever the handle is closed, but it ensures
541 if( (pCcb->GrantedAccess & FILE_WRITE_DATA) &&
542 pFcb->Specific.File.ExtentsDirtyCount != 0)
545 AFSFlushExtents( pFcb,
549 if( pFcb->OpenHandleCount == 1)
553 // Wait for any outstanding queued flushes to complete
556 AFSWaitOnQueuedFlushes( pFcb);
558 ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE;
562 // Indicate the file access mode that is being released
565 stFileCleanup.FileAccess = pCcb->FileAccess;
568 // Push the request to the service
571 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
572 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
574 &pCcb->DirectoryCB->NameInformation.FileName,
575 &pObjectInfo->FileId,
577 sizeof( AFSFileCleanupCB),
581 if ( NT_SUCCESS( ntStatus))
584 if ( pObjectInfo->ParentObjectInformation != NULL)
587 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
590 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
593 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
595 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
598 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
602 ntStatus = STATUS_SUCCESS;
606 // Remove the share access at this time since we may not get the close for sometime on this FO.
609 IoRemoveShareAccess( pFileObject,
613 // We don't need the name array after the user closes the handle on the file
616 if( pCcb->NameArray != NULL)
619 AFSFreeNameArray( pCcb->NameArray);
621 pCcb->NameArray = NULL;
625 // Decrement the open child handle count
628 if( pObjectInfo->ParentObjectInformation != NULL)
631 ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
633 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
635 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
636 AFS_TRACE_LEVEL_VERBOSE,
637 "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n",
638 pObjectInfo->ParentObjectInformation,
642 AFSReleaseResource( &pFcb->NPFcb->Resource);
644 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE))
647 // The ObjectReferenceCount will be freed by AFSPerformObjectInvalidate
650 InterlockedIncrement( &pObjectInfo->ObjectReferenceCount);
652 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_PURGE_ON_CLOSE);
654 AFSPerformObjectInvalidate( pObjectInfo,
655 AFS_INVALIDATE_DATA_VERSION);
658 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
660 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
661 AFS_TRACE_LEVEL_VERBOSE,
662 "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n",
670 // Root or directory node
677 // Set the root Fcb to this node
683 // Fall through to below
687 case AFS_DIRECTORY_FCB:
691 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
694 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
695 AFS_TRACE_LEVEL_VERBOSE,
696 "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n",
697 &pFcb->NPFcb->Resource,
698 PsGetCurrentThread());
700 AFSAcquireExcl( &pFcb->NPFcb->Resource,
704 // Perform some final common processing
707 ASSERT( pFcb->OpenHandleCount != 0);
709 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
712 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
715 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
717 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
720 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
722 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
725 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
727 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
730 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
733 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
735 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
738 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
741 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
743 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
748 // If the count has dropped to one and there is a pending delete
749 // then delete the node. The final count will be decremented just
750 // before the Fcb->NPFcb->Resource is released.
753 if( pFcb->OpenHandleCount == 1 &&
754 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
758 // Try to notify the service about the delete
761 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
764 // Indicate the file access mode that is being released
767 stFileCleanup.FileAccess = pCcb->FileAccess;
770 // Push the request to the service
773 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
774 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
776 &pCcb->DirectoryCB->NameInformation.FileName,
777 &pObjectInfo->FileId,
779 sizeof( AFSFileCleanupCB),
783 if( !NT_SUCCESS( ntStatus) &&
784 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
787 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
788 AFS_TRACE_LEVEL_ERROR,
789 "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n",
793 ntStatus = STATUS_SUCCESS;
795 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
800 ntStatus = STATUS_SUCCESS;
802 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
803 AFS_TRACE_LEVEL_VERBOSE,
804 "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n",
808 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
810 ASSERT( pObjectInfo->ParentObjectInformation != NULL);
812 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
815 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
818 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
820 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
825 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
829 // Now that the service has the entry has deleted we need to remove it from the parent
830 // tree so another lookup on the node will fail
833 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
836 AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
842 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
843 AFS_TRACE_LEVEL_VERBOSE,
844 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
846 &pCcb->DirectoryCB->NameInformation.FileName);
849 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
851 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
853 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
854 (ULONG)FILE_ACTION_REMOVED);
860 // If there have been any updates to the node then push it to
867 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
870 ULONG ulNotifyFilter = 0;
872 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
874 if( pObjectInfo->ParentObjectInformation != NULL)
877 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
879 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
881 (ULONG)ulNotifyFilter,
882 (ULONG)FILE_ACTION_MODIFIED);
887 // Indicate the file access mode that is being released
890 stFileCleanup.FileAccess = pCcb->FileAccess;
892 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
893 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
895 &pCcb->DirectoryCB->NameInformation.FileName,
896 &pObjectInfo->FileId,
898 sizeof( AFSFileCleanupCB),
902 if ( NT_SUCCESS( ntStatus))
905 if ( pObjectInfo->ParentObjectInformation != NULL)
908 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
911 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
914 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
916 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
919 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
923 ntStatus = STATUS_SUCCESS;
927 // Release the notification for this directory if there is one
930 FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync,
931 &pControlDeviceExt->Specific.Control.DirNotifyList,
935 // Remove the share access at this time since we may not get the close for sometime on this FO.
938 IoRemoveShareAccess( pFileObject,
942 // We don't need the name array after the user closes the handle on the file
945 if( pCcb->NameArray != NULL)
948 AFSFreeNameArray( pCcb->NameArray);
950 pCcb->NameArray = NULL;
954 // Decrement the open child handle count
957 if( pObjectInfo->ParentObjectInformation != NULL)
960 ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
962 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
964 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
965 AFS_TRACE_LEVEL_VERBOSE,
966 "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n",
967 pObjectInfo->ParentObjectInformation,
971 AFSReleaseResource( &pFcb->NPFcb->Resource);
973 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
975 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
976 AFS_TRACE_LEVEL_VERBOSE,
977 "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n",
984 case AFS_SYMBOLIC_LINK_FCB:
985 case AFS_MOUNT_POINT_FCB:
986 case AFS_DFS_LINK_FCB:
987 case AFS_INVALID_FCB:
991 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
994 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
995 AFS_TRACE_LEVEL_VERBOSE,
996 "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n",
997 &pFcb->NPFcb->Resource,
998 PsGetCurrentThread());
1000 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1004 // Perform some final common processing
1007 ASSERT( pFcb->OpenHandleCount != 0);
1009 if( pFcb->ObjectInformation->ParentObjectInformation != NULL)
1012 stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId;
1015 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1017 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1020 stFileCleanup.FileAttributes = pObjectInfo->FileAttributes;
1022 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME))
1025 stFileCleanup.CreateTime = pObjectInfo->CreationTime;
1027 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME);
1030 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME))
1033 stFileCleanup.ChangeTime = pObjectInfo->ChangeTime;
1035 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME);
1038 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME))
1041 stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime;
1043 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME);
1048 // If the count has dropped to one and there is a pending delete
1049 // then delete the node. The final count will be decremented just
1050 // before the Fcb->NPFcb->Resource is released.
1053 if( pFcb->OpenHandleCount == 1 &&
1054 BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1058 // Try to notify the service about the delete
1061 ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED;
1064 // Indicate the file access mode that is being released
1067 stFileCleanup.FileAccess = pCcb->FileAccess;
1070 // Push the request to the service
1073 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1074 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1076 &pCcb->DirectoryCB->NameInformation.FileName,
1077 &pObjectInfo->FileId,
1079 sizeof( AFSFileCleanupCB),
1083 if( !NT_SUCCESS( ntStatus) &&
1084 ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
1087 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1088 AFS_TRACE_LEVEL_ERROR,
1089 "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n",
1090 &pCcb->FullFileName,
1093 ntStatus = STATUS_SUCCESS;
1095 ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE);
1100 ntStatus = STATUS_SUCCESS;
1102 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1103 AFS_TRACE_LEVEL_VERBOSE,
1104 "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n",
1105 &pCcb->FullFileName,
1108 SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED);
1110 ASSERT( pObjectInfo->ParentObjectInformation != NULL);
1112 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
1115 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1)
1118 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
1120 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
1124 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = pResultCB->ParentDataVersion.QuadPart;
1128 // Now that the service has the entry has deleted we need to remove it from the parent
1129 // tree so another lookup on the node will fail
1132 if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE))
1135 AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation,
1141 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1142 AFS_TRACE_LEVEL_VERBOSE,
1143 "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n",
1145 &pCcb->DirectoryCB->NameInformation.FileName);
1148 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1150 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1152 (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME,
1153 (ULONG)FILE_ACTION_REMOVED);
1159 // If there have been any updates to the node then push it to
1166 if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED))
1169 ULONG ulNotifyFilter = 0;
1171 ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED);
1173 if( pObjectInfo->ParentObjectInformation != NULL)
1176 ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES);
1178 AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation,
1180 (ULONG)ulNotifyFilter,
1181 (ULONG)FILE_ACTION_MODIFIED);
1186 // Indicate the file access mode that is being released
1189 stFileCleanup.FileAccess = pCcb->FileAccess;
1191 ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING,
1192 ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS,
1194 &pCcb->DirectoryCB->NameInformation.FileName,
1195 &pObjectInfo->FileId,
1197 sizeof( AFSFileCleanupCB),
1201 if ( NT_SUCCESS( ntStatus))
1204 if ( pObjectInfo->ParentObjectInformation != NULL)
1207 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
1210 if ( pObjectInfo->ParentObjectInformation->DataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart)
1213 SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
1215 pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;
1218 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1222 ntStatus = STATUS_SUCCESS;
1226 // Remove the share access at this time since we may not get the close for sometime on this FO.
1229 IoRemoveShareAccess( pFileObject,
1230 &pFcb->ShareAccess);
1233 // We don't need the name array after the user closes the handle on the file
1236 if( pCcb->NameArray != NULL)
1239 AFSFreeNameArray( pCcb->NameArray);
1241 pCcb->NameArray = NULL;
1245 // Decrement the open child handle count
1248 if( pObjectInfo->ParentObjectInformation != NULL)
1251 ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0);
1253 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1255 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1256 AFS_TRACE_LEVEL_VERBOSE,
1257 "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1258 pObjectInfo->ParentObjectInformation,
1262 AFSReleaseResource( &pFcb->NPFcb->Resource);
1264 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1266 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1267 AFS_TRACE_LEVEL_VERBOSE,
1268 "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n",
1275 case AFS_SPECIAL_SHARE_FCB:
1278 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1279 AFS_TRACE_LEVEL_VERBOSE,
1280 "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n",
1281 &pFcb->NPFcb->Resource,
1282 PsGetCurrentThread());
1284 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1287 ASSERT( pFcb->OpenHandleCount != 0);
1290 // Decrement the open child handle count
1293 if( pObjectInfo->ParentObjectInformation != NULL &&
1294 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0)
1297 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount);
1299 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1300 AFS_TRACE_LEVEL_VERBOSE,
1301 "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n",
1302 pObjectInfo->ParentObjectInformation,
1306 AFSReleaseResource( &pFcb->NPFcb->Resource);
1308 lCount = InterlockedDecrement( &pFcb->OpenHandleCount);
1310 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
1311 AFS_TRACE_LEVEL_VERBOSE,
1312 "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n",
1321 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1322 AFS_TRACE_LEVEL_WARNING,
1323 "AFSCleanup Processing unknown node type %d\n",
1324 pFcb->Header.NodeTypeCode);
1332 if( pResultCB != NULL)
1335 AFSExFreePool( pResultCB);
1338 if( pFileObject != NULL)
1342 // Setup the fileobject flags to indicate cleanup is complete.
1345 SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE);
1349 // Complete the request
1352 AFSCompleteRequest( Irp, ntStatus);
1354 __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
1359 "EXCEPTION - AFSCleanup\n");