Windows: Test for PRSFS_INSERT in redirector interface
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSClose.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
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.
21  *
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.
33  */
34
35 //
36 // File: AFSClose.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSClose
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_CLOSE dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSClose( IN PDEVICE_OBJECT LibDeviceObject,
55           IN PIRP Irp)
56 {
57     UNREFERENCED_PARAMETER(LibDeviceObject);
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
60     AFSFcb *pFcb = NULL;
61     AFSDeviceExt *pDeviceExt = NULL;
62     AFSCcb *pCcb = NULL;
63     AFSObjectInfoCB *pObjectInfo = NULL;
64     AFSDirectoryCB *pDirCB = NULL;
65     LONG lCount;
66
67     __try
68     {
69
70         if( AFSRDRDeviceObject == NULL)
71         {
72
73             //
74             // Let this through, it's an close on the library control device
75             //
76
77             try_return( ntStatus);
78         }
79
80         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
81
82         pIrpSp = IoGetCurrentIrpStackLocation( Irp);
83
84         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
85
86         if( pFcb == NULL)
87         {
88             try_return( ntStatus);
89         }
90
91         pObjectInfo = pFcb->ObjectInformation;
92
93         //
94         // Perform the close functionality depending on the type of node it is
95         //
96
97         switch( pFcb->Header.NodeTypeCode)
98         {
99
100             case AFS_IOCTL_FCB:
101             {
102
103                 AFSPIOCtlOpenCloseRequestCB stPIOCtlClose;
104                 AFSFileID stParentFileId;
105
106                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
107                               AFS_TRACE_LEVEL_VERBOSE,
108                               "AFSClose Acquiring GlobalRoot lock %p EXCL %08lX\n",
109                               &pFcb->NPFcb->Resource,
110                               PsGetCurrentThread());
111
112                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
113                                   TRUE);
114
115                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
116
117                 //
118                 // Send the close to the CM
119                 //
120
121                 RtlZeroMemory( &stPIOCtlClose,
122                                sizeof( AFSPIOCtlOpenCloseRequestCB));
123
124                 stPIOCtlClose.RequestId = pCcb->RequestID;
125
126                 stPIOCtlClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
127
128                 RtlZeroMemory( &stParentFileId,
129                                sizeof( AFSFileID));
130
131                 stParentFileId = pObjectInfo->ParentObjectInformation->FileId;
132
133                 //
134                 // Issue the close request to the service
135                 //
136
137                 AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_CLOSE,
138                                    AFS_REQUEST_FLAG_SYNCHRONOUS,
139                                    &pCcb->AuthGroup,
140                                    NULL,
141                                    &stParentFileId,
142                                    (void *)&stPIOCtlClose,
143                                    sizeof( AFSPIOCtlOpenCloseRequestCB),
144                                    NULL,
145                                    NULL);
146
147                 //
148                 // Remove the Ccb and de-allocate it
149                 //
150
151                 AFSRemoveCcb( pFcb,
152                               pCcb);
153
154                 //
155                 // If this is not the root then decrement the open child reference count
156                 //
157
158                 if( pObjectInfo->ParentObjectInformation != NULL &&
159                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
160                 {
161
162                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
163
164                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
165                                   AFS_TRACE_LEVEL_VERBOSE,
166                                   "AFSClose (IOCtl) Decrement child open ref count on Parent object %p Cnt %d\n",
167                                   pObjectInfo->ParentObjectInformation,
168                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
169                 }
170
171                 AFSReleaseResource( &pFcb->NPFcb->Resource);
172
173                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
174
175                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
176                               AFS_TRACE_LEVEL_VERBOSE,
177                               "AFSClose (IOCtl) Decrement count on Fcb %p Cnt %d\n",
178                               pFcb,
179                               lCount);
180
181                 ASSERT( lCount >= 0);
182
183                 break;
184             }
185
186             case AFS_ROOT_ALL:
187             {
188
189                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
190                               AFS_TRACE_LEVEL_VERBOSE,
191                               "AFSClose Acquiring Special Root ALL lock %p EXCL %08lX\n",
192                               &pFcb->NPFcb->Resource,
193                               PsGetCurrentThread());
194
195                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
196                                 TRUE);
197
198                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
199
200                 //
201                 // Remove the Ccb and de-allocate it
202                 //
203
204                 AFSRemoveCcb( pFcb,
205                               pCcb);
206
207                 AFSReleaseResource( &pFcb->NPFcb->Resource);
208
209                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
210
211                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
212                               AFS_TRACE_LEVEL_VERBOSE,
213                               "AFSClose (RootAll) Decrement count on Fcb %p Cnt %d\n",
214                               pFcb,
215                               lCount);
216
217                 ASSERT( lCount >= 0);
218
219                 break;
220             }
221
222             //
223             // Root, file or directory node
224             //
225
226             case AFS_FILE_FCB:
227             case AFS_ROOT_FCB:
228             case AFS_DIRECTORY_FCB:
229             case AFS_SYMBOLIC_LINK_FCB:
230             case AFS_MOUNT_POINT_FCB:
231             case AFS_DFS_LINK_FCB:
232             case AFS_INVALID_FCB:
233             {
234
235                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
236
237                 //
238                 // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions
239                 //
240
241                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
242                               AFS_TRACE_LEVEL_VERBOSE,
243                               "AFSClose Acquiring Dcb lock %p EXCL %08lX\n",
244                               &pFcb->NPFcb->Resource,
245                               PsGetCurrentThread());
246
247                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
248                                 TRUE);
249
250                 KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount);
251
252                 if( pFcb->OpenReferenceCount == 1 &&
253                     pFcb->Header.NodeTypeCode == AFS_FILE_FCB)
254                 {
255
256                     SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED);
257
258                     //
259                     // Attempt to tear down our extent list for the file
260                     // If there are remaining dirty extents then attempt to
261                     // flush them as well
262                     //
263
264                     if( pFcb->Specific.File.ExtentsDirtyCount)
265                     {
266
267                         AFSFlushExtents( pFcb,
268                                          &pCcb->AuthGroup);
269                     }
270
271                     //
272                     // Wait for any outstanding queued flushes to complete
273                     //
274
275                     AFSWaitOnQueuedFlushes( pFcb);
276
277                     ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 &&
278                             pFcb->Specific.File.QueuedFlushCount == 0);
279
280                     AFSReleaseResource( &pFcb->NPFcb->Resource);
281
282                     //
283                     // Tear 'em down, we'll not be needing them again
284                     //
285
286                     AFSTearDownFcbExtents( pFcb,
287                                            &pCcb->AuthGroup);
288                 }
289                 else
290                 {
291
292                     if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
293                         pFcb->Specific.File.ExtentsDirtyCount &&
294                         (pCcb->GrantedAccess & FILE_WRITE_DATA))
295                     {
296
297                         AFSFlushExtents( pFcb,
298                                          &pCcb->AuthGroup);
299                     }
300
301                     AFSReleaseResource( &pFcb->NPFcb->Resource);
302                 }
303
304                 pDirCB = pCcb->DirectoryCB;
305
306                 //
307                 // Steal the DirOpenReferenceCount from the Ccb
308                 //
309
310                 pCcb->DirectoryCB = NULL;
311
312                 //
313                 // Remove the Ccb and de-allocate it
314                 //
315
316                 AFSRemoveCcb( pFcb,
317                               pCcb);
318
319                 //
320                 // If this entry is deleted then remove the object from the volume tree
321                 //
322
323                 if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED))
324                 {
325
326                     if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB &&
327                         pObjectInfo->Links == 0)
328                     {
329
330                         //
331                         // Stop anything possibly in process
332                         //
333
334                         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
335                                       AFS_TRACE_LEVEL_VERBOSE,
336                                       "AFSClose Acquiring Fcb extents lock %p EXCL %08lX\n",
337                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
338                                       PsGetCurrentThread());
339
340                         AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource,
341                                         TRUE);
342
343                         pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED;
344
345                         KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete,
346                                     0,
347                                     FALSE);
348
349                         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
350                                       AFS_TRACE_LEVEL_VERBOSE,
351                                       "AFSClose Releasing Fcb extents lock %p EXCL %08lX\n",
352                                       &pFcb->NPFcb->Specific.File.ExtentsResource,
353                                       PsGetCurrentThread());
354
355                         AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource);
356                     }
357
358                     AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
359                                     TRUE);
360
361                     AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock,
362                                     TRUE);
363
364                     lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
365
366                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
367                                   AFS_TRACE_LEVEL_VERBOSE,
368                                   "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
369                                   &pDirCB->NameInformation.FileName,
370                                   pDirCB,
371                                   pCcb,
372                                   lCount);
373
374                     ASSERT( lCount >= 0);
375
376                     if( lCount == 0)
377                     {
378
379                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
380                                       AFS_TRACE_LEVEL_VERBOSE,
381                                       "AFSClose Deleting dir entry %p (%p) for %wZ  FID %08lX-%08lX-%08lX-%08lX\n",
382                                       pDirCB,
383                                       pObjectInfo,
384                                       &pDirCB->NameInformation.FileName,
385                                       pObjectInfo->FileId.Cell,
386                                       pObjectInfo->FileId.Volume,
387                                       pObjectInfo->FileId.Vnode,
388                                       pObjectInfo->FileId.Unique);
389
390                         //
391                         // Remove and delete the directory entry from the parent list
392                         //
393
394                         AFSDeleteDirEntry( pObjectInfo->ParentObjectInformation,
395                                            pDirCB);
396
397                         AFSAcquireShared( &pObjectInfo->NonPagedInfo->ObjectInfoLock,
398                                           TRUE);
399
400                         if( pObjectInfo->ObjectReferenceCount <= 0)
401                         {
402
403                             if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE))
404                             {
405
406                                 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
407                                               AFS_TRACE_LEVEL_VERBOSE,
408                                               "AFSClose Removing object %p from volume tree\n",
409                                               pObjectInfo);
410
411                                 AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead,
412                                                     &pObjectInfo->TreeEntry);
413
414                                 ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE);
415                             }
416                         }
417
418                         AFSReleaseResource( &pObjectInfo->NonPagedInfo->ObjectInfoLock);
419                     }
420
421                     AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
422
423                     AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock);
424                 }
425                 else
426                 {
427
428                     lCount = InterlockedDecrement( &pDirCB->DirOpenReferenceCount);
429
430                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
431                                   AFS_TRACE_LEVEL_VERBOSE,
432                                   "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
433                                   &pDirCB->NameInformation.FileName,
434                                   pDirCB,
435                                   pCcb,
436                                   lCount);
437
438                     ASSERT( lCount >= 0);
439                 }
440
441                 //
442                 // If this is not the root then decrement the open child reference count
443                 //
444
445                 if( pObjectInfo != NULL &&
446                     pObjectInfo->ParentObjectInformation != NULL &&
447                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
448                 {
449
450                     InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
451
452                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
453                                   AFS_TRACE_LEVEL_VERBOSE,
454                                   "AFSClose Decrement child open ref count on Parent object %p Cnt %d\n",
455                                   pObjectInfo->ParentObjectInformation,
456                                   pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
457                 }
458
459                 //
460                 // Decrement the reference count on the Fcb. this is protecting it from teardown.
461                 //
462
463                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
464
465                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
466                               AFS_TRACE_LEVEL_VERBOSE,
467                               "AFSClose Decrement count on Fcb %p Cnt %d\n",
468                               pFcb,
469                               lCount);
470
471                 ASSERT( lCount >= 0);
472
473                 break;
474             }
475
476             case AFS_SPECIAL_SHARE_FCB:
477             {
478
479                 AFSPipeOpenCloseRequestCB stPipeClose;
480
481                 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
482
483                 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
484                               AFS_TRACE_LEVEL_VERBOSE,
485                               "AFSClose Acquiring Special Share lock %p EXCL %08lX\n",
486                               &pFcb->NPFcb->Resource,
487                               PsGetCurrentThread());
488
489                 AFSAcquireExcl( &pFcb->NPFcb->Resource,
490                                 TRUE);
491
492                 RtlZeroMemory( &stPipeClose,
493                                sizeof( AFSPipeOpenCloseRequestCB));
494
495                 stPipeClose.RequestId = pCcb->RequestID;
496
497                 stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId;
498
499                 //
500                 // Issue the open request to the service
501                 //
502
503                 /*
504                 AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_CLOSE,
505                                    AFS_REQUEST_FLAG_SYNCHRONOUS,
506                                    &pFcb->AuthGroup,
507                                    &pDirCB->NameInformation.FileName,
508                                    NULL,
509                                    (void *)&stPipeClose,
510                                    sizeof( AFSPipeOpenCloseRequestCB),
511                                    NULL,
512                                    NULL);
513                 */
514
515                 //
516                 // Remove the Ccb and de-allocate it
517                 //
518
519                 AFSRemoveCcb( pFcb,
520                               pCcb);
521
522                 //
523                 // If this is not the root then decrement the open child reference count
524                 //
525
526                 if( pObjectInfo->ParentObjectInformation != NULL &&
527                     pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)
528                 {
529
530                     lCount = InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount);
531
532                     AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
533                                   AFS_TRACE_LEVEL_VERBOSE,
534                                   "AFSClose (Share) Decrement child open ref count on Parent object %p Cnt %d\n",
535                                   pObjectInfo->ParentObjectInformation,
536                                   lCount);
537                 }
538
539                 AFSReleaseResource( &pFcb->NPFcb->Resource);
540
541                 lCount = InterlockedDecrement( &pFcb->OpenReferenceCount);
542
543                 AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING,
544                               AFS_TRACE_LEVEL_VERBOSE,
545                               "AFSClose (Share) Decrement count on Fcb %p Cnt %d\n",
546                               pFcb,
547                               lCount);
548
549                 ASSERT( lCount >= 0);
550
551                 break;
552             }
553
554             default:
555
556                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
557                               AFS_TRACE_LEVEL_ERROR,
558                               "AFSClose Processing unknown node type %d\n",
559                               pFcb->Header.NodeTypeCode);
560
561                 break;
562         }
563
564 try_exit:
565
566         //
567         // Complete the request
568         //
569
570         AFSCompleteRequest( Irp,
571                             ntStatus);
572     }
573     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
574     {
575
576         AFSDbgLogMsg( 0,
577                       0,
578                       "EXCEPTION - AFSClose\n");
579
580         AFSDumpTraceFilesFnc();
581     }
582
583     return ntStatus;
584 }