Windows: VolumeCB->ObjectInfoTree.TreeLock Deadlock
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSWorker.cpp
index 1074d2b..b4adbec 100644 (file)
@@ -70,7 +70,7 @@ AFSInitializeWorkerPool()
         pDevExt->Specific.Library.WorkerCount = 0;
 
         KeInitializeEvent( &pDevExt->Specific.Library.WorkerQueueHasItems,
-                           NotificationEvent,
+                           SynchronizationEvent,
                            FALSE);
 
         //
@@ -152,7 +152,7 @@ AFSInitializeWorkerPool()
         pDevExt->Specific.Library.IOWorkerCount = 0;
 
         KeInitializeEvent( &pDevExt->Specific.Library.IOWorkerQueueHasItems,
-                           NotificationEvent,
+                           SynchronizationEvent,
                            FALSE);
 
         //
@@ -265,7 +265,10 @@ AFSRemoveWorkerPool()
     pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
 
     //
-    // Loop through the workers shutting them down
+    // Loop through the workers shutting them down in two stages.
+    // First, clear AFS_WORKER_PROCESS_REQUESTS so that workers
+    // stop processing requests.  Second, call AFSShutdownWorkerThread()
+    // to wake the workers and wait for them to exit.
     //
 
     pCurrentWorker = pDevExt->Specific.Library.PoolHead;
@@ -273,6 +276,26 @@ AFSRemoveWorkerPool()
     while( index < pDevExt->Specific.Library.WorkerCount)
     {
 
+        ClearFlag( pCurrentWorker->State, AFS_WORKER_PROCESS_REQUESTS);
+
+        pCurrentWorker = pCurrentWorker->fLink;
+
+        if ( pCurrentWorker == NULL)
+        {
+
+            break;
+        }
+
+        index++;
+    }
+
+    pCurrentWorker = pDevExt->Specific.Library.PoolHead;
+
+    index = 0;
+
+    while( index < pDevExt->Specific.Library.WorkerCount)
+    {
+
         ntStatus = AFSShutdownWorkerThread( pCurrentWorker);
 
         pNextWorker = pCurrentWorker->fLink;
@@ -295,7 +318,10 @@ AFSRemoveWorkerPool()
     ExDeleteResourceLite( &pDevExt->Specific.Library.QueueLock);
 
     //
-    // Loop through the IO workers shutting them down
+    // Loop through the IO workers shutting them down in two stages.
+    // First, clear AFS_WORKER_PROCESS_REQUESTS so that workers
+    // stop processing requests.  Second, call AFSShutdownWorkerThread()
+    // to wake the workers and wait for them to exit.
     //
 
     pCurrentWorker = pDevExt->Specific.Library.IOPoolHead;
@@ -305,6 +331,26 @@ AFSRemoveWorkerPool()
     while( index < pDevExt->Specific.Library.IOWorkerCount)
     {
 
+        ClearFlag( pCurrentWorker->State, AFS_WORKER_PROCESS_REQUESTS);
+
+        pCurrentWorker = pCurrentWorker->fLink;
+
+        if ( pCurrentWorker == NULL)
+        {
+
+            break;
+        }
+
+        index++;
+    }
+
+    pCurrentWorker = pDevExt->Specific.Library.IOPoolHead;
+
+    index = 0;
+
+    while( index < pDevExt->Specific.Library.IOWorkerCount)
+    {
+
         ntStatus = AFSShutdownIOWorkerThread( pCurrentWorker);
 
         pNextWorker = pCurrentWorker->fLink;
@@ -515,7 +561,7 @@ AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB)
 //
 // Description:
 //
-//      This function shusdown a worker thread in the pool
+//      This function shutsdown a worker thread in the pool
 //
 // Return:
 //
@@ -534,12 +580,6 @@ AFSShutdownWorkerThread( IN AFSWorkQueueContext *PoolContext)
     {
 
         //
-        // Clear the 'keep processing' flag
-        //
-
-        ClearFlag( PoolContext->State, AFS_WORKER_PROCESS_REQUESTS);
-
-        //
         // Wake up the thread if it is a sleep
         //
 
@@ -585,12 +625,6 @@ AFSShutdownIOWorkerThread( IN AFSWorkQueueContext *PoolContext)
     {
 
         //
-        // Clear the 'keep processing' flag
-        //
-
-        ClearFlag( PoolContext->State, AFS_WORKER_PROCESS_REQUESTS);
-
-        //
         // Wake up the thread if it is a sleep
         //
 
@@ -632,7 +666,6 @@ AFSWorkerThread( IN PVOID Context)
     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
     AFSWorkItem *pWorkItem;
     BOOLEAN freeWorkItem = TRUE;
-    BOOLEAN exitThread = FALSE;
     AFSDeviceExt *pLibraryDevExt = NULL;
     LONG lCount;
 
@@ -646,35 +679,45 @@ AFSWorkerThread( IN PVOID Context)
                 0,
                 FALSE);
 
-
     //
     // Indicate we are initialized
     //
 
     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
 
+    ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
+                                      Executive,
+                                      KernelMode,
+                                      FALSE,
+                                      NULL);
+
     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
     {
 
-        ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
-                                          Executive,
-                                          KernelMode,
-                                          FALSE,
-                                          NULL);
-
         if( !NT_SUCCESS( ntStatus))
         {
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                           AFS_TRACE_LEVEL_ERROR,
                           "AFSWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
+
+            ntStatus = STATUS_SUCCESS;
         }
         else
         {
 
             pWorkItem = AFSRemoveWorkItem();
 
-            if( pWorkItem != NULL)
+            if( pWorkItem == NULL)
+            {
+
+                ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
+                                                  Executive,
+                                                  KernelMode,
+                                                  FALSE,
+                                                  NULL);
+            }
+            else
             {
 
                 freeWorkItem = TRUE;
@@ -737,6 +780,17 @@ AFSWorkerThread( IN PVOID Context)
                         break;
                     }
 
+                    case AFS_WORK_INVALIDATE_OBJECT:
+                    {
+
+                        AFSPerformObjectInvalidate( pWorkItem->Specific.Invalidate.ObjectInfo,
+                                                    pWorkItem->Specific.Invalidate.InvalidateReason);
+
+                        freeWorkItem = TRUE;
+
+                        break;
+                    }
+
                     case AFS_WORK_START_IOS:
                     {
 
@@ -759,10 +813,20 @@ AFSWorkerThread( IN PVOID Context)
 
                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
                 }
+
+                ntStatus = STATUS_SUCCESS;
             }
         }
     } // worker thread loop
 
+    ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
+
+    // Wake up another worker so they too can exit
+
+    KeSetEvent( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems,
+                0,
+                FALSE);
+
     PsTerminateSystemThread( 0);
 
     return;
@@ -776,7 +840,6 @@ AFSIOWorkerThread( IN PVOID Context)
     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context;
     AFSWorkItem *pWorkItem;
     BOOLEAN freeWorkItem = TRUE;
-    BOOLEAN exitThread = FALSE;
     AFSDeviceExt *pLibraryDevExt = NULL, *pRdrDevExt = NULL;
 
     pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension;
@@ -796,28 +859,39 @@ AFSIOWorkerThread( IN PVOID Context)
 
     SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
 
+    ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
+                                      Executive,
+                                      KernelMode,
+                                      FALSE,
+                                      NULL);
+
     while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS))
     {
 
-        ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
-                                          Executive,
-                                          KernelMode,
-                                          FALSE,
-                                          NULL);
-
         if( !NT_SUCCESS( ntStatus))
         {
 
             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                           AFS_TRACE_LEVEL_ERROR,
                           "AFSIOWorkerThread Wait for queue items failed Status %08lX\n", ntStatus);
+
+            ntStatus = STATUS_SUCCESS;
         }
         else
         {
 
             pWorkItem = AFSRemoveIOWorkItem();
 
-            if( pWorkItem != NULL)
+            if( pWorkItem == NULL)
+            {
+
+                ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
+                                                  Executive,
+                                                  KernelMode,
+                                                  FALSE,
+                                                  NULL);
+            }
+            else
             {
 
                 freeWorkItem = TRUE;
@@ -873,10 +947,20 @@ AFSIOWorkerThread( IN PVOID Context)
 
                     ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
                 }
+
+                ntStatus = STATUS_SUCCESS;
             }
         }
     } // worker thread loop
 
+    ClearFlag( pPoolContext->State, AFS_WORKER_INITIALIZED);
+
+    // Wake up another IOWorker so they too can exit
+
+    KeSetEvent( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems,
+                0,
+                FALSE);
+
     PsTerminateSystemThread( 0);
 
     return;
@@ -890,7 +974,6 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
     AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->VolumeWorkerContext;
     AFSDeviceExt *pControlDeviceExt = NULL;
     AFSDeviceExt *pRDRDeviceExt = NULL;
-    BOOLEAN exitThread = FALSE;
     LARGE_INTEGER DueTime;
     LONG TimeOut;
     KTIMER Timer;
@@ -899,6 +982,8 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
     AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL;
     BOOLEAN bReleaseVolumeLock = FALSE;
     AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL;
+    AFSFcb *pFcb = NULL;
+    LONG lFileType;
     LARGE_INTEGER liCurrentTime;
     BOOLEAN bVolumeObject = FALSE;
     LONG lCount;
@@ -973,8 +1058,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                 continue;
             }
 
-            if( pVolumeCB->ObjectInfoListHead == NULL &&
-                pVolumeCB != AFSGlobalRoot)
+            if( pVolumeCB->ObjectInfoListHead == NULL)
             {
 
                 AFSReleaseResource( pVolumeCB->VolumeLock);
@@ -1107,19 +1191,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                 if( pCurrentObject->Fcb != NULL)
                                 {
 
-                                    //
-                                    // Acquire and drop the Fcb resource to synchronize
-                                    // with a potentially active AFSCleanup() which sets
-                                    // the OpenReferenceCount to zero while holding the
-                                    // resource.
-                                    //
-
-                                    AFSAcquireExcl( &pCurrentObject->Fcb->NPFcb->Resource,
-                                                    TRUE);
-
-                                    AFSReleaseResource( &pCurrentObject->Fcb->NPFcb->Resource);
-
-                                    AFSRemoveFcb( pCurrentObject->Fcb);
+                                    AFSRemoveFcb( &pCurrentObject->Fcb);
                                 }
 
                                 if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL)
@@ -1128,7 +1200,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                     if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL)
                                     {
 
-                                        AFSRemoveFcb( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+                                        AFSRemoveFcb( &pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
                                     }
 
                                     AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
@@ -1142,7 +1214,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
 
                                 AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
                                               AFS_TRACE_LEVEL_VERBOSE,
-                                              "AFSPrimaryWorker Deleting deleted object %08lX\n",
+                                              "AFSPrimaryVolumeWorkerThread Deleting deleted object %08lX\n",
                                               pCurrentObject);
 
                                 AFSDeleteObjectInfo( pCurrentObject);
@@ -1295,9 +1367,11 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
 
                                     pCurrentChildObject = pCurrentDirEntry->ObjectInformation;
 
+                                    pFcb = NULL;
+
                                     AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
                                                   AFS_TRACE_LEVEL_VERBOSE,
-                                                  "AFSPrimaryWorker Deleting DE %wZ Object %08lX\n",
+                                                  "AFSPrimaryVolumeWorkerThread Deleting DE %wZ Object %08lX\n",
                                                   &pCurrentDirEntry->NameInformation.FileName,
                                                   pCurrentChildObject);
 
@@ -1310,26 +1384,9 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                         if( pCurrentChildObject->Fcb != NULL)
                                         {
 
-                                            if( pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE)
-                                            {
-
-                                                AFSCleanupFcb( pCurrentChildObject->Fcb,
-                                                               TRUE);
-                                            }
+                                            pFcb = (AFSFcb *) InterlockedCompareExchangePointer( (PVOID *)&pCurrentChildObject->Fcb, NULL, (PVOID)pCurrentChildObject->Fcb);
 
-                                            //
-                                            // Acquire and drop the Fcb resource to synchronize
-                                            // with a potentially active AFSCleanup() which sets
-                                            // the OpenReferenceCount to zero while holding the
-                                            // resource.
-                                            //
-
-                                            AFSAcquireExcl( &pCurrentChildObject->Fcb->NPFcb->Resource,
-                                                            TRUE);
-
-                                            AFSReleaseResource( &pCurrentChildObject->Fcb->NPFcb->Resource);
-
-                                            AFSRemoveFcb( pCurrentChildObject->Fcb);
+                                            lFileType = pCurrentChildObject->FileType;
                                         }
 
                                         if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY &&
@@ -1339,7 +1396,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                             if( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL)
                                             {
 
-                                                AFSRemoveFcb( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
+                                                AFSRemoveFcb( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb);
                                             }
 
                                             AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation);
@@ -1353,13 +1410,36 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
 
                                         AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING,
                                                       AFS_TRACE_LEVEL_VERBOSE,
-                                                      "AFSPrimaryWorker Deleting object %08lX\n",
+                                                      "AFSPrimaryVolumeWorkerThread Deleting object %08lX\n",
                                                       pCurrentChildObject);
 
                                         AFSDeleteObjectInfo( pCurrentChildObject);
                                     }
 
                                     pCurrentDirEntry = pNextDirEntry;
+
+                                    if ( pFcb != NULL)
+                                    {
+
+                                        if( lFileType == AFS_FILE_TYPE_FILE)
+                                        {
+                                            //
+                                            // We must not hold pVolumeCB->ObjectInfoTree.TreeLock exclusive
+                                            // across an AFSCleanupFcb call since it can deadlock with an
+                                            // invalidation call from the service.
+                                            //
+
+                                            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
+
+                                            AFSCleanupFcb( pFcb,
+                                                           TRUE);
+
+                                            AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
+                                                            TRUE);
+                                        }
+
+                                        AFSRemoveFcb( &pFcb);
+                                    }
                                 }
 
                                 pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL;
@@ -1376,7 +1456,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
 
                                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT,
                                               AFS_TRACE_LEVEL_VERBOSE,
-                                              "AFSPrimaryWorker Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
+                                              "AFSPrimaryVolumeWorkerThread Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n",
                                               pCurrentObject->FileId.Cell,
                                               pCurrentObject->FileId.Volume,
                                               pCurrentObject->FileId.Vnode,
@@ -1449,51 +1529,16 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                               pCurrentObject->Fcb->OpenReferenceCount == 0))
                         {
 
-                            AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
-
-                            if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock,
-                                                FALSE))
-                            {
-
-                                if( pCurrentObject->Fcb != NULL)
-                                {
-
-                                    AFSCleanupFcb( pCurrentObject->Fcb,
-                                                   TRUE);
-
-                                    //
-                                    // Acquire and drop the Fcb resource to synchronize
-                                    // with a potentially active AFSCleanup() which sets
-                                    // the OpenReferenceCount to zero while holding the
-                                    // resource.
-                                    //
-
-                                    AFSAcquireExcl( &pCurrentObject->Fcb->NPFcb->Resource,
-                                                    TRUE);
-
-                                    AFSReleaseResource( &pCurrentObject->Fcb->NPFcb->Resource);
-
-                                    AFSRemoveFcb( pCurrentObject->Fcb);
-                                }
-
-                                AFSDeleteObjectInfo( pCurrentObject);
-
-                                AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
-
-                                pCurrentObject = pNextObject;
+                            pFcb = (AFSFcb *) InterlockedCompareExchangePointer( (PVOID *)&pCurrentObject->Fcb, NULL, (PVOID)pCurrentObject->Fcb);
 
-                                continue;
-                            }
-                            else
+                            if( pFcb != NULL)
                             {
 
-                                bReleaseVolumeLock = FALSE;
+                                AFSCleanupFcb( pFcb,
+                                               TRUE);
 
-                                break;
+                                AFSRemoveFcb( &pFcb);
                             }
-                        }
-                        else if( pCurrentObject->Fcb != NULL)
-                        {
 
                             AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock);
 
@@ -1501,8 +1546,7 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                                 FALSE))
                             {
 
-                                AFSCleanupFcb( pCurrentObject->Fcb,
-                                               FALSE);
+                                AFSDeleteObjectInfo( pCurrentObject);
 
                                 AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock);
 
@@ -1518,6 +1562,12 @@ AFSPrimaryVolumeWorkerThread( IN PVOID Context)
                                 break;
                             }
                         }
+                        else if( pCurrentObject->Fcb != NULL)
+                        {
+
+                            AFSCleanupFcb( pCurrentObject->Fcb,
+                                           FALSE);
+                        }
                     }
 
                     pCurrentObject = pNextObject;
@@ -1850,14 +1900,19 @@ AFSRemoveWorkItem()
         {
 
             pDevExt->Specific.Library.QueueTail = NULL;
+        }
+        else
+        {
 
-            KeResetEvent(&(pDevExt->Specific.Library.WorkerQueueHasItems));
+            //
+            // Wake up another worker
+            //
+
+            KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems),
+                        0,
+                        FALSE);
         }
     }
-    else
-    {
-        KeResetEvent(&(pDevExt->Specific.Library.WorkerQueueHasItems));
-    }
 
     AFSReleaseResource( &pDevExt->Specific.Library.QueueLock);
 
@@ -1904,14 +1959,19 @@ AFSRemoveIOWorkItem()
         {
 
             pDevExt->Specific.Library.IOQueueTail = NULL;
+        }
+        else
+        {
 
-            KeResetEvent(&(pDevExt->Specific.Library.IOWorkerQueueHasItems));
+            //
+            // Wake up another worker
+            //
+
+            KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems),
+                        0,
+                        FALSE);
         }
     }
-    else
-    {
-        KeResetEvent(&(pDevExt->Specific.Library.IOWorkerQueueHasItems));
-    }
 
     AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock);
 
@@ -2508,3 +2568,77 @@ try_exit:
 
     return ntStatus;
 }
+
+NTSTATUS
+AFSQueueInvalidateObject( IN AFSObjectInfoCB *ObjectInfo,
+                          IN ULONG InvalidateReason)
+{
+
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSWorkItem *pWorkItem = NULL;
+
+    __try
+    {
+
+        pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool,
+                                                                 sizeof(AFSWorkItem),
+                                                                 AFS_WORK_ITEM_TAG);
+        if (NULL == pWorkItem)
+        {
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING,
+                          AFS_TRACE_LEVEL_ERROR,
+                          "AFSQueueInvalidateObject Failed to allocate work item\n");
+
+            try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES );
+        }
+
+        RtlZeroMemory( pWorkItem,
+                       sizeof(AFSWorkItem));
+
+        pWorkItem->Size = sizeof( AFSWorkItem);
+
+        pWorkItem->RequestType = AFS_WORK_INVALIDATE_OBJECT;
+
+        pWorkItem->Specific.Invalidate.ObjectInfo = ObjectInfo;
+
+        pWorkItem->Specific.Invalidate.InvalidateReason = InvalidateReason;
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "AFSQueueInvalidateObject Workitem %08lX\n",
+                      pWorkItem);
+
+        ntStatus = AFSQueueWorkerRequest( pWorkItem);
+
+try_exit:
+
+        AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING,
+                      AFS_TRACE_LEVEL_VERBOSE,
+                      "AFSQueueInvalidateObject Request complete Status %08lX\n",
+                      ntStatus);
+
+        if( !NT_SUCCESS( ntStatus))
+        {
+
+            if( pWorkItem != NULL)
+            {
+                ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG);
+            }
+
+            AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
+                          AFS_TRACE_LEVEL_ERROR,
+                          "AFSQueueInvalidateObject Failed to queue request Status %08lX\n",
+                          ntStatus);
+        }
+    }
+    __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) )
+    {
+
+        AFSDbgLogMsg( 0,
+                      0,
+                      "EXCEPTION - AFSQueueInvalidateObject\n");
+    }
+
+    return ntStatus;
+}