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.
39 #include "AFSCommon.h"
46 // This function is the IRP_MJ_CLOSE dispatch handler
50 // A status is returned for the handling of this request
54 AFSClose( IN PDEVICE_OBJECT LibDeviceObject,
58 NTSTATUS ntStatus = STATUS_SUCCESS;
59 ULONG ulRequestType = 0;
60 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
62 AFSDeviceExt *pDeviceExt = NULL;
64 AFSObjectInfoCB *pObjectInfo = NULL;
65 AFSDirectoryCB *pDirCB = NULL;
70 if( AFSRDRDeviceObject == NULL)
74 // Let this through, it's an close on the library control device
77 try_return( ntStatus);
80 pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
82 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
84 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
88 try_return( ntStatus);
91 pObjectInfo = pFcb->ObjectInformation;
94 // Perform the close functionality depending on the type of node it is
97 switch( pFcb->Header.NodeTypeCode)
103 AFSPIOCtlOpenCloseRequestCB stPIOCtlClose;
104 AFSFileID stParentFileId;
106 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
107 AFS_TRACE_LEVEL_VERBOSE,
108 "AFSClose Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
109 &pFcb->NPFcb->Resource,
110 PsGetCurrentThread());
112 AFSAcquireExcl( &pFcb->NPFcb->Resource,
115 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
118 // Send the close to the CM
121 RtlZeroMemory( &stPIOCtlClose,
122 sizeof( AFSPIOCtlOpenCloseRequestCB));
124 stPIOCtlClose.RequestId = pCcb->RequestID;
126 stPIOCtlClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
128 RtlZeroMemory( &stParentFileId,
131 stParentFileId = pObjectInfo->ParentObjectInformation->FileId;
134 // Issue the close request to the service
137 AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_CLOSE,
138 AFS_REQUEST_FLAG_SYNCHRONOUS,
142 (void *)&stPIOCtlClose,
143 sizeof( AFSPIOCtlOpenCloseRequestCB),
147 pDirCB = pCcb->DirectoryCB;
150 // Remove the Ccb and de-allocate it
153 ntStatus = AFSRemoveCcb( pFcb,
156 if( !NT_SUCCESS( ntStatus))
159 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
160 AFS_TRACE_LEVEL_WARNING,
161 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
164 // We can't actually fail a close operation so reset the status
167 ntStatus = STATUS_SUCCESS;
170 ASSERT( pDirCB->OpenReferenceCount > 0);
172 InterlockedDecrement( &pDirCB->OpenReferenceCount);
174 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
175 AFS_TRACE_LEVEL_VERBOSE,
176 "AFSClose (IOCtl) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
177 &pDirCB->NameInformation.FileName,
180 pDirCB->OpenReferenceCount);
183 // If this is not the root then decrement the open child reference count
186 if( pObjectInfo->ParentObjectInformation != NULL &&
187 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
190 InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
192 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
193 AFS_TRACE_LEVEL_VERBOSE,
194 "AFSClose (IOCtl) Decrement child open ref count on Parent object %08lX Cnt %d\n",
195 pObjectInfo->ParentObjectInformation,
196 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
199 AFSReleaseResource( &pFcb->NPFcb->Resource);
201 ASSERT( pFcb->OpenReferenceCount != 0);
203 InterlockedDecrement( &pFcb->OpenReferenceCount);
205 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
206 AFS_TRACE_LEVEL_VERBOSE,
207 "AFSClose (IOCtl) Decrement count on Fcb %08lX Cnt %d\n",
209 pFcb->OpenReferenceCount);
217 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
218 AFS_TRACE_LEVEL_VERBOSE,
219 "AFSClose Acquiring Special Root ALL lock %08lX EXCL %08lX\n",
220 &pFcb->NPFcb->Resource,
221 PsGetCurrentThread());
223 AFSAcquireExcl( &pFcb->NPFcb->Resource,
226 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
228 pDirCB = pCcb->DirectoryCB;
231 // Remove the Ccb and de-allocate it
234 ntStatus = AFSRemoveCcb( pFcb,
237 if( !NT_SUCCESS( ntStatus))
240 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
241 AFS_TRACE_LEVEL_WARNING,
242 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
245 // We can't actually fail a close operation so reset the status
248 ntStatus = STATUS_SUCCESS;
251 ASSERT( pDirCB->OpenReferenceCount > 0);
253 InterlockedDecrement( &pDirCB->OpenReferenceCount);
255 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
256 AFS_TRACE_LEVEL_VERBOSE,
257 "AFSClose Decrement (Root ALL) count on %wZ DE %p Ccb %p Cnt %d\n",
258 &pDirCB->NameInformation.FileName,
261 pDirCB->OpenReferenceCount);
263 AFSReleaseResource( &pFcb->NPFcb->Resource);
265 ASSERT( pFcb->OpenReferenceCount > 0);
267 InterlockedDecrement( &pFcb->OpenReferenceCount);
269 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
270 AFS_TRACE_LEVEL_VERBOSE,
271 "AFSClose (RootAll) Decrement count on Fcb %08lX Cnt %d\n",
273 pFcb->OpenReferenceCount);
279 // Root, file or directory node
284 case AFS_DIRECTORY_FCB:
285 case AFS_SYMBOLIC_LINK_FCB:
286 case AFS_MOUNT_POINT_FCB:
287 case AFS_DFS_LINK_FCB:
288 case AFS_INVALID_FCB:
291 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
294 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
297 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
298 AFS_TRACE_LEVEL_VERBOSE,
299 "AFSClose Acquiring Dcb lock %08lX EXCL %08lX\n",
300 &pFcb->NPFcb->Resource,
301 PsGetCurrentThread());
303 AFSAcquireExcl( &pFcb->NPFcb->Resource,
306 KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount);
308 pDirCB = pCcb->DirectoryCB;
311 // If this entry is deleted then remove the object from the volume tree
314 if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED))
317 if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
321 // Stop anything possibly in process
324 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
325 AFS_TRACE_LEVEL_VERBOSE,
326 "AFSClose Acquiring Fcb extents lock %08lX EXCL %08lX\n",
327 &pFcb->NPFcb->Specific.File.ExtentsResource,
328 PsGetCurrentThread());
330 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
333 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
335 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
339 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
340 AFS_TRACE_LEVEL_VERBOSE,
341 "AFSClose Releasing Fcb extents lock %08lX EXCL %08lX\n",
342 &pFcb->NPFcb->Specific.File.ExtentsResource,
343 PsGetCurrentThread());
345 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
348 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
351 AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
354 if ( pDirCB->OpenReferenceCount == 0)
358 "AFSClose (Other) OpenReferenceCount is Zero on DE %08lX Ccb %08lX FileName %wZ\n",
361 &pDirCB->NameInformation.FileName);
364 ASSERT( pDirCB->OpenReferenceCount > 0);
366 InterlockedDecrement( &pDirCB->OpenReferenceCount);
368 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
369 AFS_TRACE_LEVEL_VERBOSE,
370 "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
371 &pDirCB->NameInformation.FileName,
374 pDirCB->OpenReferenceCount);
376 if( pDirCB->OpenReferenceCount == 0)
379 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
380 AFS_TRACE_LEVEL_VERBOSE,
381 "AFSClose Deleting dir entry %08lX (%08lX) for %wZ FID %08lX-%08lX-%08lX-%08lX\n",
384 &pDirCB->NameInformation.FileName,
385 pObjectInfo->FileId.Cell,
386 pObjectInfo->FileId.Volume,
387 pObjectInfo->FileId.Vnode,
388 pObjectInfo->FileId.Unique);
391 // Remove and delete the directory entry from the parent list
394 AFSDeleteDirEntry( pObjectInfo->ParentObjectInformation,
397 if( pObjectInfo->ObjectReferenceCount <= 0)
400 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
403 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
404 AFS_TRACE_LEVEL_VERBOSE,
405 "AFSClose Removing object %08lX from volume tree\n",
408 AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
409 &pObjectInfo->TreeEntry);
411 ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE);
414 SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED);
418 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
420 AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
425 ASSERT( pDirCB->OpenReferenceCount > 0);
427 InterlockedDecrement( &pDirCB->OpenReferenceCount);
429 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
430 AFS_TRACE_LEVEL_VERBOSE,
431 "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
432 &pDirCB->NameInformation.FileName,
435 pDirCB->OpenReferenceCount);
439 // If this is not the root then decrement the open child reference count
442 if( pObjectInfo != NULL &&
443 pObjectInfo->ParentObjectInformation != NULL &&
444 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
447 InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
449 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
450 AFS_TRACE_LEVEL_VERBOSE,
451 "AFSClose Decrement child open ref count on Parent object %08lX Cnt %d\n",
452 pObjectInfo->ParentObjectInformation,
453 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
456 if( pFcb->OpenReferenceCount == 1 &&
457 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
460 SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED);
463 // Attempt to tear down our extent list for the file
464 // If there are remaining dirty extents then attempt to
465 // flush them as well
468 if( pFcb->Specific.File.ExtentsDirtyCount)
471 AFSFlushExtents( pFcb,
476 // Wait for any outstanding queued flushes to complete
479 AFSWaitOnQueuedFlushes( pFcb);
481 ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 &&
482 pFcb->Specific.File.QueuedFlushCount == 0);
484 AFSReleaseResource( &pFcb->NPFcb->Resource);
487 // Tear 'em down, we'll not be needing them again
490 if( AFSTearDownFcbExtents( pFcb,
495 // Indicate to the service that the file required complete flushing to the
499 AFSProcessRequest( AFS_REQUEST_TYPE_FLUSH_FILE,
500 AFS_REQUEST_FLAG_SYNCHRONOUS,
503 &pFcb->ObjectInformation->FileId,
513 if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
514 pFcb->Specific.File.ExtentsDirtyCount &&
515 (pCcb->GrantedAccess & FILE_WRITE_DATA))
518 AFSFlushExtents( pFcb,
522 AFSReleaseResource( &pFcb->NPFcb->Resource);
526 // Remove the Ccb and de-allocate it
529 ntStatus = AFSRemoveCcb( pFcb,
532 if( !NT_SUCCESS( ntStatus))
535 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
536 AFS_TRACE_LEVEL_WARNING,
537 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n",
541 // We can't actually fail a close operation so reset the status
544 ntStatus = STATUS_SUCCESS;
548 // Decrement the reference count on the Fcb. this is protecting it from teardown.
551 ASSERT( pFcb->OpenReferenceCount != 0);
553 InterlockedDecrement( &pFcb->OpenReferenceCount);
555 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
556 AFS_TRACE_LEVEL_VERBOSE,
557 "AFSClose Decrement count on Fcb %08lX Cnt %d\n",
559 pFcb->OpenReferenceCount);
564 case AFS_SPECIAL_SHARE_FCB:
567 AFSPipeOpenCloseRequestCB stPipeClose;
569 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
570 AFS_TRACE_LEVEL_VERBOSE,
571 "AFSClose Acquiring Special Share lock %08lX EXCL %08lX\n",
572 &pFcb->NPFcb->Resource,
573 PsGetCurrentThread());
575 AFSAcquireExcl( &pFcb->NPFcb->Resource,
578 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
580 pDirCB = pCcb->DirectoryCB;
582 RtlZeroMemory( &stPipeClose,
583 sizeof( AFSPipeOpenCloseRequestCB));
585 stPipeClose.RequestId = pCcb->RequestID;
587 stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
590 // Issue the open request to the service
594 AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_CLOSE,
595 AFS_REQUEST_FLAG_SYNCHRONOUS,
597 &pDirCB->NameInformation.FileName,
599 (void *)&stPipeClose,
600 sizeof( AFSPipeOpenCloseRequestCB),
606 // Remove the Ccb and de-allocate it
609 ntStatus = AFSRemoveCcb( pFcb,
612 if( !NT_SUCCESS( ntStatus))
615 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
616 AFS_TRACE_LEVEL_WARNING,
617 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
620 // We can't actually fail a close operation so reset the status
623 ntStatus = STATUS_SUCCESS;
626 ASSERT( pDirCB->OpenReferenceCount > 0);
628 InterlockedDecrement( &pDirCB->OpenReferenceCount);
630 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
631 AFS_TRACE_LEVEL_VERBOSE,
632 "AFSClose (Share) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
633 &pDirCB->NameInformation.FileName,
636 pDirCB->OpenReferenceCount);
639 // If this is not the root then decrement the open child reference count
642 if( pObjectInfo->ParentObjectInformation != NULL &&
643 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
646 InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
648 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
649 AFS_TRACE_LEVEL_VERBOSE,
650 "AFSClose (Share) Decrement child open ref count on Parent object %08lX Cnt %d\n",
651 pObjectInfo->ParentObjectInformation,
652 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
655 AFSReleaseResource( &pFcb->NPFcb->Resource);
657 ASSERT( pFcb->OpenReferenceCount != 0);
659 InterlockedDecrement( &pFcb->OpenReferenceCount);
661 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
662 AFS_TRACE_LEVEL_VERBOSE,
663 "AFSClose (Share) Decrement count on Fcb %08lX Cnt %d\n",
665 pFcb->OpenReferenceCount);
672 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
673 AFS_TRACE_LEVEL_ERROR,
674 "AFSClose Processing unknown node type %d\n",
675 pFcb->Header.NodeTypeCode);
683 // Complete the request
686 AFSCompleteRequest( Irp,
689 __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
694 "EXCEPTION - AFSClose\n");