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;
71 if( AFSRDRDeviceObject == NULL)
75 // Let this through, it's an close on the library control device
78 try_return( ntStatus);
81 pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
83 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
85 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
89 try_return( ntStatus);
92 pObjectInfo = pFcb->ObjectInformation;
95 // Perform the close functionality depending on the type of node it is
98 switch( pFcb->Header.NodeTypeCode)
104 AFSPIOCtlOpenCloseRequestCB stPIOCtlClose;
105 AFSFileID stParentFileId;
107 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
108 AFS_TRACE_LEVEL_VERBOSE,
109 "AFSClose Acquiring GlobalRoot lock %08lX EXCL %08lX\n",
110 &pFcb->NPFcb->Resource,
111 PsGetCurrentThread());
113 AFSAcquireExcl( &pFcb->NPFcb->Resource,
116 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
119 // Send the close to the CM
122 RtlZeroMemory( &stPIOCtlClose,
123 sizeof( AFSPIOCtlOpenCloseRequestCB));
125 stPIOCtlClose.RequestId = pCcb->RequestID;
127 stPIOCtlClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
129 RtlZeroMemory( &stParentFileId,
132 stParentFileId = pObjectInfo->ParentObjectInformation->FileId;
135 // Issue the close request to the service
138 AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_CLOSE,
139 AFS_REQUEST_FLAG_SYNCHRONOUS,
143 (void *)&stPIOCtlClose,
144 sizeof( AFSPIOCtlOpenCloseRequestCB),
148 pDirCB = pCcb->DirectoryCB;
151 // Remove the Ccb and de-allocate it
154 ntStatus = AFSRemoveCcb( pFcb,
157 if( !NT_SUCCESS( ntStatus))
160 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
161 AFS_TRACE_LEVEL_WARNING,
162 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
165 // We can't actually fail a close operation so reset the status
168 ntStatus = STATUS_SUCCESS;
171 lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
173 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
174 AFS_TRACE_LEVEL_VERBOSE,
175 "AFSClose (IOCtl) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
176 &pDirCB->NameInformation.FileName,
181 ASSERT( lCount >= 0);
184 // If this is not the root then decrement the open child reference count
187 if( pObjectInfo->ParentObjectInformation != NULL &&
188 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
191 InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
193 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
194 AFS_TRACE_LEVEL_VERBOSE,
195 "AFSClose (IOCtl) Decrement child open ref count on Parent object %08lX Cnt %d\n",
196 pObjectInfo->ParentObjectInformation,
197 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
200 AFSReleaseResource( &pFcb->NPFcb->Resource);
202 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
204 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
205 AFS_TRACE_LEVEL_VERBOSE,
206 "AFSClose (IOCtl) Decrement count on Fcb %08lX Cnt %d\n",
210 ASSERT( lCount >= 0);
218 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
219 AFS_TRACE_LEVEL_VERBOSE,
220 "AFSClose Acquiring Special Root ALL lock %08lX EXCL %08lX\n",
221 &pFcb->NPFcb->Resource,
222 PsGetCurrentThread());
224 AFSAcquireExcl( &pFcb->NPFcb->Resource,
227 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
229 pDirCB = pCcb->DirectoryCB;
232 // Remove the Ccb and de-allocate it
235 ntStatus = AFSRemoveCcb( pFcb,
238 if( !NT_SUCCESS( ntStatus))
241 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
242 AFS_TRACE_LEVEL_WARNING,
243 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
246 // We can't actually fail a close operation so reset the status
249 ntStatus = STATUS_SUCCESS;
252 lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
254 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
255 AFS_TRACE_LEVEL_VERBOSE,
256 "AFSClose Decrement (Root ALL) count on %wZ DE %p Ccb %p Cnt %d\n",
257 &pDirCB->NameInformation.FileName,
262 ASSERT( lCount >= 0);
264 AFSReleaseResource( &pFcb->NPFcb->Resource);
266 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
268 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
269 AFS_TRACE_LEVEL_VERBOSE,
270 "AFSClose (RootAll) Decrement count on Fcb %08lX Cnt %d\n",
274 ASSERT( lCount >= 0);
280 // Root, file or directory node
285 case AFS_DIRECTORY_FCB:
286 case AFS_SYMBOLIC_LINK_FCB:
287 case AFS_MOUNT_POINT_FCB:
288 case AFS_DFS_LINK_FCB:
289 case AFS_INVALID_FCB:
292 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
295 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
298 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
299 AFS_TRACE_LEVEL_VERBOSE,
300 "AFSClose Acquiring Dcb lock %08lX EXCL %08lX\n",
301 &pFcb->NPFcb->Resource,
302 PsGetCurrentThread());
304 AFSAcquireExcl( &pFcb->NPFcb->Resource,
307 KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount);
309 if( pFcb->OpenReferenceCount == 1 &&
310 pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
313 SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED);
316 // Attempt to tear down our extent list for the file
317 // If there are remaining dirty extents then attempt to
318 // flush them as well
321 if( pFcb->Specific.File.ExtentsDirtyCount)
324 AFSFlushExtents( pFcb,
329 // Wait for any outstanding queued flushes to complete
332 AFSWaitOnQueuedFlushes( pFcb);
334 ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 &&
335 pFcb->Specific.File.QueuedFlushCount == 0);
337 AFSReleaseResource( &pFcb->NPFcb->Resource);
340 // Tear 'em down, we'll not be needing them again
343 AFSTearDownFcbExtents( pFcb,
349 if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
350 pFcb->Specific.File.ExtentsDirtyCount &&
351 (pCcb->GrantedAccess & FILE_WRITE_DATA))
354 AFSFlushExtents( pFcb,
358 AFSReleaseResource( &pFcb->NPFcb->Resource);
361 pDirCB = pCcb->DirectoryCB;
364 // Remove the Ccb and de-allocate it
367 ntStatus = AFSRemoveCcb( pFcb,
370 if( !NT_SUCCESS( ntStatus))
373 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
374 AFS_TRACE_LEVEL_WARNING,
375 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n",
379 // We can't actually fail a close operation so reset the status
382 ntStatus = STATUS_SUCCESS;
386 // If this entry is deleted then remove the object from the volume tree
389 if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED))
392 if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
393 pObjectInfo->Links == 0)
397 // Stop anything possibly in process
400 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
401 AFS_TRACE_LEVEL_VERBOSE,
402 "AFSClose Acquiring Fcb extents lock %08lX EXCL %08lX\n",
403 &pFcb->NPFcb->Specific.File.ExtentsResource,
404 PsGetCurrentThread());
406 AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
409 pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
411 KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
415 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
416 AFS_TRACE_LEVEL_VERBOSE,
417 "AFSClose Releasing Fcb extents lock %08lX EXCL %08lX\n",
418 &pFcb->NPFcb->Specific.File.ExtentsResource,
419 PsGetCurrentThread());
421 AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
424 AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
427 AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
430 lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
432 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
433 AFS_TRACE_LEVEL_VERBOSE,
434 "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
435 &pDirCB->NameInformation.FileName,
440 ASSERT( lCount >= 0);
445 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
446 AFS_TRACE_LEVEL_VERBOSE,
447 "AFSClose Deleting dir entry %08lX (%08lX) for %wZ FID %08lX-%08lX-%08lX-%08lX\n",
450 &pDirCB->NameInformation.FileName,
451 pObjectInfo->FileId.Cell,
452 pObjectInfo->FileId.Volume,
453 pObjectInfo->FileId.Vnode,
454 pObjectInfo->FileId.Unique);
457 // Remove and delete the directory entry from the parent list
460 AFSDeleteDirEntry( pObjectInfo->ParentObjectInformation,
463 AFSAcquireShared( &pObjectInfo->NonPagedInfo->ObjectInfoLock,
466 if( pObjectInfo->ObjectReferenceCount <= 0)
469 if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
472 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
473 AFS_TRACE_LEVEL_VERBOSE,
474 "AFSClose Removing object %08lX from volume tree\n",
477 AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
478 &pObjectInfo->TreeEntry);
480 ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE);
484 AFSReleaseResource( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
487 AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
489 AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
494 lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
496 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
497 AFS_TRACE_LEVEL_VERBOSE,
498 "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
499 &pDirCB->NameInformation.FileName,
504 ASSERT( lCount >= 0);
508 // If this is not the root then decrement the open child reference count
511 if( pObjectInfo != NULL &&
512 pObjectInfo->ParentObjectInformation != NULL &&
513 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
516 InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
518 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
519 AFS_TRACE_LEVEL_VERBOSE,
520 "AFSClose Decrement child open ref count on Parent object %08lX Cnt %d\n",
521 pObjectInfo->ParentObjectInformation,
522 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
526 // Decrement the reference count on the Fcb. this is protecting it from teardown.
529 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
531 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
532 AFS_TRACE_LEVEL_VERBOSE,
533 "AFSClose Decrement count on Fcb %08lX Cnt %d\n",
537 ASSERT( lCount >= 0);
542 case AFS_SPECIAL_SHARE_FCB:
545 AFSPipeOpenCloseRequestCB stPipeClose;
547 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
549 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
550 AFS_TRACE_LEVEL_VERBOSE,
551 "AFSClose Acquiring Special Share lock %08lX EXCL %08lX\n",
552 &pFcb->NPFcb->Resource,
553 PsGetCurrentThread());
555 AFSAcquireExcl( &pFcb->NPFcb->Resource,
558 RtlZeroMemory( &stPipeClose,
559 sizeof( AFSPipeOpenCloseRequestCB));
561 stPipeClose.RequestId = pCcb->RequestID;
563 stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
566 // Issue the open request to the service
570 AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_CLOSE,
571 AFS_REQUEST_FLAG_SYNCHRONOUS,
573 &pDirCB->NameInformation.FileName,
575 (void *)&stPipeClose,
576 sizeof( AFSPipeOpenCloseRequestCB),
581 pDirCB = pCcb->DirectoryCB;
584 // Remove the Ccb and de-allocate it
587 ntStatus = AFSRemoveCcb( pFcb,
590 if( !NT_SUCCESS( ntStatus))
593 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
594 AFS_TRACE_LEVEL_WARNING,
595 "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus);
598 // We can't actually fail a close operation so reset the status
601 ntStatus = STATUS_SUCCESS;
604 lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
606 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
607 AFS_TRACE_LEVEL_VERBOSE,
608 "AFSClose (Share) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
609 &pDirCB->NameInformation.FileName,
614 ASSERT( lCount >= 0);
617 // If this is not the root then decrement the open child reference count
620 if( pObjectInfo->ParentObjectInformation != NULL &&
621 pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
624 lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
626 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
627 AFS_TRACE_LEVEL_VERBOSE,
628 "AFSClose (Share) Decrement child open ref count on Parent object %08lX Cnt %d\n",
629 pObjectInfo->ParentObjectInformation,
633 AFSReleaseResource( &pFcb->NPFcb->Resource);
635 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
637 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
638 AFS_TRACE_LEVEL_VERBOSE,
639 "AFSClose (Share) Decrement count on Fcb %08lX Cnt %d\n",
643 ASSERT( lCount >= 0);
650 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
651 AFS_TRACE_LEVEL_ERROR,
652 "AFSClose Processing unknown node type %d\n",
653 pFcb->Header.NodeTypeCode);
661 // Complete the request
664 AFSCompleteRequest( Irp,
667 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
672 "EXCEPTION - AFSClose\n");
674 AFSDumpTraceFilesFnc();