windows-vista-resume-smb-binding-20080202
[openafs.git] / src / WINNT / afsd / afsd_service.c
index 2f6e3d7..e0d3576 100644 (file)
@@ -9,6 +9,7 @@
 #include <setjmp.h>
 #include "afsd.h"
 #include "afsd_init.h"
+#include "lanahelper.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <winsock2.h>
@@ -37,12 +38,9 @@ HANDLE hAFSDMainThread = NULL;
 HANDLE hAFSDWorkerThread[WORKER_THREADS];
 #endif
 
-/* for the IFS version, set the event DoTerminate, on which all
-   worker threads wait.  they will exit, and then everything else
-   can uninitialize. */
-HANDLE WaitToTerminate, DoTerminate;
+HANDLE WaitToTerminate;
 
-int GlobalStatus;
+static int GlobalStatus;
 
 #ifdef JUMP
 unsigned int MainThreadId;
@@ -52,13 +50,20 @@ jmp_buf notifier_jmp;
 extern int traceOnPanic;
 extern HANDLE afsi_file;
 
-int powerEventsRegistered = 0;
+static int powerEventsRegistered = 0;
+extern int powerStateSuspended = 0;
 
 /*
  * Notifier function for use by osi_panic
  */
 static void afsd_notifier(char *msgp, char *filep, long line)
 {
+#ifdef AFSIFS
+    int i;
+#endif
+    if (!msgp)
+        msgp = "unspecified assert";
+
     if (filep)
        LogEvent(EVENTLOG_ERROR_TYPE, MSG_SERVICE_ERROR_STOP_WITH_MSG_AND_LOCATION, 
                  filep, line, msgp);
@@ -73,6 +78,10 @@ static void afsd_notifier(char *msgp, char *filep, long line)
     buf_ForceTrace(TRUE);
 
     afsi_log("--- begin dump ---");
+    cm_MemDumpDirStats(afsi_file, "a", 0);
+    cm_MemDumpBPlusStats(afsi_file, "a", 0);
+    cm_DumpCells(afsi_file, "a", 0);
+    cm_DumpVolumes(afsi_file, "a", 0);
     cm_DumpSCache(afsi_file, "a", 0);
 #ifdef keisa
     cm_dnlcDump(afsi_file, "a");
@@ -82,13 +91,12 @@ static void afsd_notifier(char *msgp, char *filep, long line)
     afsi_log("--- end   dump ---");
     
 #ifdef DEBUG
-    DebugBreak();      
+    if (IsDebuggerPresent())
+        DebugBreak();  
 #endif
 
-#ifndef AFSIFS
     SetEvent(WaitToTerminate);
-#else
-    SetEvent(DoTerminate);
+#ifdef AFSIFS
     WaitForMultipleObjects(WORKER_THREADS, hAFSDWorkerThread, TRUE, INFINITE);
     for (i = 0; i < WORKER_THREADS; i++)
         CloseHandle(hAFSDWorkerThread[i]);
@@ -175,7 +183,8 @@ afsd_ServiceControlHandler(DWORD ctrlCode)
             afsi_log("SERVICE_CONTROL_SHUTDOWN");
 
         /* Write all dirty buffers back to server */
-        buf_CleanAndReset();
+       if ( !lana_OnlyLoopback() )
+           buf_CleanAndReset();
 
         /* Force trace if requested */
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
@@ -197,11 +206,7 @@ afsd_ServiceControlHandler(DWORD ctrlCode)
         }
 
       doneTrace:
-#ifndef AFSIFS
         SetEvent(WaitToTerminate);
-#else
-        SetEvent(DoTerminate);
-#endif
         break;
 
     case SERVICE_CONTROL_INTERROGATE:
@@ -234,11 +239,22 @@ afsd_ServiceControlHandlerEx(
     DWORD dummyLen, doTrace;
     long code;
     DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
+    OSVERSIONINFO osVersion;
+
+    /* Get the version of Windows */
+    memset(&osVersion, 0x00, sizeof(osVersion));
+    osVersion.dwOSVersionInfoSize = sizeof(osVersion);
+    GetVersionEx(&osVersion);
 
     switch (ctrlCode) 
     {
     case SERVICE_CONTROL_SHUTDOWN:
     case SERVICE_CONTROL_STOP:
+       if (ctrlCode == SERVICE_CONTROL_SHUTDOWN)
+           afsi_log("SERVICE_CONTROL_SHUTDOWN");
+       else
+            afsi_log("SERVICE_CONTROL_STOP");
+
         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
         ServiceStatus.dwWin32ExitCode = NO_ERROR;
         ServiceStatus.dwCheckPoint = 1;
@@ -247,7 +263,8 @@ afsd_ServiceControlHandlerEx(
         SetServiceStatus(StatusHandle, &ServiceStatus);
 
         /* Write all dirty buffers back to server */
-        buf_CleanAndReset();
+       if ( !lana_OnlyLoopback() )
+           buf_CleanAndReset();
 
         /* Force trace if requested */
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
@@ -269,11 +286,7 @@ afsd_ServiceControlHandlerEx(
         }
 
       doneTrace:
-#ifndef AFSIFS
         SetEvent(WaitToTerminate);
-#else
-        SetEvent(DoTerminate);
-#endif
         dwRet = NO_ERROR;
         break;
 
@@ -307,34 +320,56 @@ afsd_ServiceControlHandlerEx(
                 case PBT_APMQUERYSUSPEND:       
                     afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND"); 
                     /* Write all dirty buffers back to server */
-                    buf_CleanAndReset();
+                   if ( !lana_OnlyLoopback() ) {
+                       buf_CleanAndReset();
+                        cm_SuspendSCache();
+                    }
+                    afsi_log("SERVICE_CONTROL_APMQUERYSUSPEND buf_CleanAndReset complete"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMQUERYSTANDBY:                                                         
                     afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY"); 
                     /* Write all dirty buffers back to server */
-                    buf_CleanAndReset();
+                   if ( !lana_OnlyLoopback() ) {
+                       buf_CleanAndReset();
+                        cm_SuspendSCache();
+                    }
+                    afsi_log("SERVICE_CONTROL_APMQUERYSTANDBY buf_CleanAndReset complete"); 
                     dwRet = NO_ERROR;                                                             
                     break;                                                                        
                                                                                                                          
                     /* allow remaining case PBT_WhatEver */                                           
                 case PBT_APMSUSPEND:                         
-                    afsi_log("SERVICE_CONTROL_APMSUSPEND"); 
+                    afsi_log("SERVICE_CONTROL_APMSUSPEND");
+                   powerStateSuspended = 1;
+                   if (osVersion.dwMajorVersion >= 6) {
+                        cm_SuspendSCache();
+                       smb_StopListeners(0);
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMSTANDBY:                  
                     afsi_log("SERVICE_CONTROL_APMSTANDBY"); 
+                   powerStateSuspended = 1;
+                   if (osVersion.dwMajorVersion >= 6) {
+                        cm_SuspendSCache();
+                       smb_StopListeners(0);
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMRESUMECRITICAL:             
                     afsi_log("SERVICE_CONTROL_APMRESUMECRITICAL"); 
+                   if (osVersion.dwMajorVersion >= 6)
+                       smb_RestartListeners(0);
                     dwRet = NO_ERROR;                       
                     break;                                  
                 case PBT_APMRESUMESUSPEND:                                                        
+                   /* User logged in after suspend */
                     afsi_log("SERVICE_CONTROL_APMRESUMESUSPEND"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
-                case PBT_APMRESUMESTANDBY:                                                        
+                case PBT_APMRESUMESTANDBY:            
+                   /* User logged in after standby */
                     afsi_log("SERVICE_CONTROL_APMRESUMESTANDBY"); 
                     dwRet = NO_ERROR;                       
                     break;                                  
@@ -354,8 +389,13 @@ afsd_ServiceControlHandlerEx(
 #endif
                     dwRet = NO_ERROR;                       
                     break;                                  
-                case PBT_APMRESUMEAUTOMATIC:                                                      
+                case PBT_APMRESUMEAUTOMATIC:          
+                   /* This is the message delivered once all devices are up */
                     afsi_log("SERVICE_CONTROL_APMRESUMEAUTOMATIC"); 
+                   powerStateSuspended = 0;
+                   if (osVersion.dwMajorVersion >= 6) {
+                       smb_SetLanAdapterChangeDetected();
+                    }
                     dwRet = NO_ERROR;                       
                     break;                                  
                 default:                                                                          
@@ -369,7 +409,7 @@ afsd_ServiceControlHandlerEx(
         {
             afsi_log("SERVICE_CONTROL_CUSTOM_DUMP"); 
             GenerateMiniDump(NULL);
-                       dwRet = NO_ERROR;
+           dwRet = NO_ERROR;
         }
         break;
     }          /* end switch(ctrlCode) */                                                        
@@ -381,10 +421,13 @@ afsd_ServiceControlHandlerEx(
  * Mount a drive into AFS if there global mapping
  */
 /* DEE Could check first if we are run as SYSTEM */
-#define MAX_RETRIES 30
-static void MountGlobalDrives(void)
+#define MAX_RETRIES 10
+#define MAX_DRIVES  23
+static DWORD __stdcall MountGlobalDrivesThread(void * notUsed)
 {
+#ifndef AFSIFS
     char szAfsPath[_MAX_PATH];
+#endif
     char szDriveToMapTo[5];
     DWORD dwResult;
     char szKeyName[256];
@@ -399,9 +442,9 @@ static void MountGlobalDrives(void)
 
     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
     if (dwResult != ERROR_SUCCESS)
-        return;
+        return 0;
 
-    while (dwRetry < MAX_RETRIES) {
+    while (dwIndex < MAX_DRIVES) {
         dwDriveSize = sizeof(szDriveToMapTo);
         dwSubMountSize = sizeof(szSubMount);
         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
@@ -414,7 +457,7 @@ static void MountGlobalDrives(void)
         }
 
 #ifndef AFSIFS
-        for ( ; dwRetry < MAX_RETRIES; dwRetry++)
+        for (dwRetry = 0 ; dwRetry < MAX_RETRIES; dwRetry++)
         {
             NETRESOURCE nr;
             memset (&nr, 0x00, sizeof(NETRESOURCE));
@@ -442,24 +485,61 @@ static void MountGlobalDrives(void)
         }
 #else
        /* FIXFIX: implement */
+       afsi_log("GlobalAutoMap of %s to %s not implemented", szDriveToMapTo, szSubMount);
 #endif
     }        
 
     RegCloseKey(hKey);
+    return 0;
+}
+
+static HANDLE hThreadMountGlobalDrives = NULL;
+
+static void MountGlobalDrives()
+{
+    DWORD tid;
+
+    hThreadMountGlobalDrives = CreateThread(NULL, 0, MountGlobalDrivesThread, 0, 0, &tid);
+
+    if ( hThreadMountGlobalDrives ) {
+        DWORD rc = WaitForSingleObject( hThreadMountGlobalDrives, 15000 );
+       if (rc == WAIT_TIMEOUT) {
+           afsi_log("GlobalAutoMap thread failed to complete after 15 seconds");
+       } else if (rc == WAIT_OBJECT_0) {
+           afsi_log("GlobalAutoMap thread completed");
+           CloseHandle( hThreadMountGlobalDrives );
+           hThreadMountGlobalDrives = NULL;
+       }
+    }
 }
 
 static void DismountGlobalDrives()
 {
+#ifndef AFSIFS
     char szAfsPath[_MAX_PATH];
     char szDriveToMapTo[5];
-    DWORD dwResult;
-    char szKeyName[256];
-    HKEY hKey;
-    DWORD dwIndex = 0;
     DWORD dwDriveSize;
     DWORD dwSubMountSize;
     char szSubMount[256];
     DWORD dwType;
+#endif
+    DWORD dwResult;
+    char szKeyName[256];
+    HKEY hKey;
+    DWORD dwIndex = 0;
+
+    if ( hThreadMountGlobalDrives ) {
+        DWORD rc = WaitForSingleObject(hThreadMountGlobalDrives, 0);
+
+       if (rc == WAIT_TIMEOUT) {
+           afsi_log("GlobalAutoMap thread failed to complete before service shutdown");
+       }
+       else if (rc == WAIT_OBJECT_0) {
+           afsi_log("GlobalAutoMap thread completed");
+           CloseHandle( hThreadMountGlobalDrives );
+           hThreadMountGlobalDrives = NULL;
+       }
+    }
 
     sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSREG_CLT_SVC_PARAM_SUBKEY);
 
@@ -467,8 +547,10 @@ static void DismountGlobalDrives()
     if (dwResult != ERROR_SUCCESS)
         return;
 
-#ifndef AFSIFS    
-    while (1) {
+#ifdef AFSIFS    
+    /* FIXFIX: implement */
+#else
+    while (dwIndex < MAX_DRIVES) {
         dwDriveSize = sizeof(szDriveToMapTo);
         dwSubMountSize = sizeof(szSubMount);
         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
@@ -487,8 +569,6 @@ static void DismountGlobalDrives()
         
         afsi_log("Disconnect from GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
     }        
-#else
-       /* FIXFIX: implement */
 #endif
 
     RegCloseKey(hKey);
@@ -926,7 +1006,11 @@ BOOL AFSModulesVerify(void)
         RegCloseKey (parmKey);
     }
 
-    if (verifyServiceSig && cacheSize < 716800) {
+    if (verifyServiceSig 
+#ifndef _WIN64
+         && cacheSize < 716800
+#endif
+         ) {
         trustVerified = VerifyTrust(filename);
     } else {
         afsi_log("Signature Verification disabled");
@@ -1033,12 +1117,18 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 #endif /* JUMP */
     HMODULE hHookDll;
     HMODULE hAdvApi32;
+#ifdef AFSIFS
+    int cnt;
+#endif
 
 #ifdef _DEBUG
+    afsd_DbgBreakAllocInit();
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
 #endif 
 
+    afsd_SetUnhandledExceptionFilter();
+       
     osi_InitPanic(afsd_notifier);
     osi_InitTraceOption();
 
@@ -1050,12 +1140,6 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
         afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
 
-#ifdef AFSIFS
-    DoTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_DoTerminate"));
-    if ( GetLastError() == ERROR_ALREADY_EXISTS )
-        afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_DoTerminate"));
-#endif
-
 #ifndef NOTSERVICE
     hAdvApi32 = LoadLibrary("advapi32.dll");
     if (hAdvApi32 == NULL)
@@ -1080,7 +1164,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
     ServiceStatus.dwWin32ExitCode = NO_ERROR;
     ServiceStatus.dwCheckPoint = 1;
-    ServiceStatus.dwWaitHint = 30000;
+    ServiceStatus.dwWaitHint = 120000;
     /* accept Power Events */
     ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
     SetServiceStatus(StatusHandle, &ServiceStatus);
@@ -1158,19 +1242,22 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
         else
         {
-            /* allow another 15 seconds to start */
+            /* allow another 120 seconds to start */
             ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
             ServiceStatus.dwServiceSpecificExitCode = 0;
             ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
             ServiceStatus.dwWin32ExitCode = NO_ERROR;
             ServiceStatus.dwCheckPoint = 2;
-            ServiceStatus.dwWaitHint = 20000;
+            ServiceStatus.dwWaitHint = 120000;
             /* accept Power Events */
             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_PARAMCHANGE;
             SetServiceStatus(StatusHandle, &ServiceStatus);
         }
     }
 
+    /* Perform Volume Status Notification Initialization */
+    cm_VolStatus_Initialization();
+
 #ifdef JUMP
     MainThreadId = GetCurrentThreadId();
     jmpret = setjmp(notifier_jmp);
@@ -1185,8 +1272,8 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
 
 #ifndef NOTSERVICE
-        ServiceStatus.dwCheckPoint++;
-        ServiceStatus.dwWaitHint -= 5000;
+        ServiceStatus.dwCheckPoint = 3;
+        ServiceStatus.dwWaitHint = 30000;
         SetServiceStatus(StatusHandle, &ServiceStatus);
 #endif
         code = afsd_InitDaemons(&reason);
@@ -1223,11 +1310,14 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
 
 #ifndef NOTSERVICE
-        ServiceStatus.dwCheckPoint++;
-        ServiceStatus.dwWaitHint -= 5000;
+        ServiceStatus.dwCheckPoint = 4;
+        ServiceStatus.dwWaitHint = 15000;
         SetServiceStatus(StatusHandle, &ServiceStatus);
 #endif
 
+        /* Notify any volume status handlers that the cache manager has started */
+        cm_VolStatus_Service_Started();
+
 /* the following ifdef chooses the mode of operation for the service.  to enable
  * a runtime flag (instead of compile-time), pioctl() would need to dynamically
  * determine the mode, in order to use the correct ioctl special-file path. */
@@ -1279,7 +1369,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 #ifndef NOTSERVICE
         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
         ServiceStatus.dwWin32ExitCode = NO_ERROR;
-        ServiceStatus.dwCheckPoint = 0;
+        ServiceStatus.dwCheckPoint = 5;
         ServiceStatus.dwWaitHint = 0;
 
         /* accept Power events */
@@ -1325,6 +1415,13 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         CloseHandle(hAFSDWorkerThread[cnt]);
 #endif
 
+    ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+    ServiceStatus.dwCheckPoint = 6;
+    ServiceStatus.dwWaitHint = 120000;
+    ServiceStatus.dwControlsAccepted = 0;
+    SetServiceStatus(StatusHandle, &ServiceStatus);
+
     afsi_log("Received Termination Signal, Stopping Service");
 
     if ( GlobalStatus )
@@ -1344,19 +1441,6 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         }
         FreeLibrary(hHookDll);
         hHookDll = NULL;
-
-        if (hookRc == FALSE)
-        {
-            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-            ServiceStatus.dwWin32ExitCode = NO_ERROR;
-            ServiceStatus.dwCheckPoint = 0;
-            ServiceStatus.dwWaitHint = 0;
-            ServiceStatus.dwControlsAccepted = 0;
-            SetServiceStatus(StatusHandle, &ServiceStatus);
-                       
-            /* exit if initialization failed */
-            return;
-        }
     }
 
 
@@ -1370,7 +1454,9 @@ afsd_Main(DWORD argc, LPTSTR *argv)
                                          
     cm_DaemonShutdown();                 
     afsi_log("Daemon shutdown complete");
-                                         
+    
+    afsd_ShutdownCM();
+
     buf_Shutdown();                      
     afsi_log("Buffer shutdown complete");
                                          
@@ -1378,7 +1464,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     afsi_log("rx finalization complete");
                                          
 #ifndef AFSIFS
-       smb_Shutdown();                      
+    smb_Shutdown();                      
     afsi_log("smb shutdown complete");   
 #endif
                                          
@@ -1397,6 +1483,17 @@ afsd_Main(DWORD argc, LPTSTR *argv)
         PowerNotificationThreadExit();
 #endif
 
+    cm_DirDumpStats();
+#ifdef USE_BPLUS
+    cm_BPlusDumpStats();
+#endif
+
+    /* Notify any Volume Status Handlers that we are stopped */
+    cm_VolStatus_Service_Stopped();
+
+    /* Cleanup any Volume Status Notification Handler */
+    cm_VolStatus_Finalize();
+
     /* allow an exit to be called after stopping the service */
     hHookDll = LoadLibrary(AFSD_HOOK_DLL);
     if (hHookDll)
@@ -1416,7 +1513,7 @@ afsd_Main(DWORD argc, LPTSTR *argv)
 
     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
     ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
-    ServiceStatus.dwCheckPoint = 0;
+    ServiceStatus.dwCheckPoint = 7;
     ServiceStatus.dwWaitHint = 0;
     ServiceStatus.dwControlsAccepted = 0;
     SetServiceStatus(StatusHandle, &ServiceStatus);
@@ -1467,11 +1564,9 @@ main(int argc, char * argv[])
                
             printf("Hit <Enter> to terminate OpenAFS Client Service\n");
             getchar();  
-#ifndef AFSIFS
             SetEvent(WaitToTerminate);
-#else
-            SetEvent(DoTerminate);
-                       dc_release_hooks();
+#ifdef AFSIFS
+           dc_release_hooks();
 #endif
         }
     }